Back to index

lightning-sunbird  0.9+nobinonly
mar_create.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Archive code.
00017  *
00018  * The Initial Developer of the Original Code is Google Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Darin Fisher <darin@meer.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <fcntl.h>
00042 #include <stdlib.h>
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include "mar.h"
00046 #include "mar_private.h"
00047 
00048 #ifdef XP_WIN
00049 #include <winsock2.h>
00050 #else
00051 #include <netinet/in.h>
00052 #include <unistd.h>
00053 #endif
00054 
00055 struct MarItemStack {
00056   void *head;
00057   PRUint32 size_used;
00058   PRUint32 size_allocated;
00059   PRUint32 last_offset;
00060 };
00061 
00066 static int mar_push(struct MarItemStack *stack, PRUint32 length, PRUint32 flags,
00067                     const char *name) {
00068   int namelen;
00069   PRUint32 n_offset, n_length, n_flags;
00070   PRUint32 size;
00071   char *data;
00072   
00073   namelen = strlen(name);
00074   size = MAR_ITEM_SIZE(namelen);
00075 
00076   if (stack->size_allocated - stack->size_used < size) {
00077     /* increase size of stack */
00078     size_t size_needed = ROUND_UP(stack->size_used + size, BLOCKSIZE);
00079     stack->head = realloc(stack->head, size_needed);
00080     if (!stack->head)
00081       return -1;
00082     stack->size_allocated = size_needed;
00083   }
00084 
00085   data = (((char *) stack->head) + stack->size_used);
00086 
00087   n_offset = htonl(stack->last_offset);
00088   n_length = htonl(length);
00089   n_flags = htonl(flags);
00090 
00091   memcpy(data, &n_offset, sizeof(n_offset));
00092   data += sizeof(n_offset);
00093 
00094   memcpy(data, &n_length, sizeof(n_length));
00095   data += sizeof(n_length);
00096 
00097   memcpy(data, &n_flags, sizeof(n_flags));
00098   data += sizeof(n_flags);
00099 
00100   memcpy(data, name, namelen + 1);
00101   
00102   stack->size_used += size;
00103   stack->last_offset += length;
00104   return 0;
00105 }
00106 
00107 static int mar_concat_file(FILE *fp, const char *path) {
00108   FILE *in;
00109   char buf[BLOCKSIZE];
00110   size_t len;
00111   int rv = 0;
00112 
00113   in = fopen(path, "rb");
00114   if (!in)
00115     return -1;
00116 
00117   while ((len = fread(buf, 1, BLOCKSIZE, in)) > 0) {
00118     if (fwrite(buf, len, 1, fp) != 1) {
00119       rv = -1;
00120       break;
00121     }
00122   }
00123 
00124   fclose(in);
00125   return rv;
00126 }
00127 
00128 int mar_create(const char *dest, int num_files, char **files) {
00129   struct MarItemStack stack;
00130   PRUint32 offset_to_index = 0, size_of_index;
00131   struct stat st;
00132   FILE *fp;
00133   int i, rv = -1;
00134 
00135   memset(&stack, 0, sizeof(stack));
00136 
00137   fp = fopen(dest, "wb");
00138   if (!fp) {
00139     fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
00140     return -1;
00141   }
00142 
00143   if (fwrite(MAR_ID, MAR_ID_SIZE, 1, fp) != 1)
00144     goto failure;
00145   if (fwrite(&offset_to_index, sizeof(PRUint32), 1, fp) != 1)
00146     goto failure;
00147 
00148   stack.last_offset = MAR_ID_SIZE + sizeof(PRUint32);
00149 
00150   for (i = 0; i < num_files; ++i) {
00151     if (stat(files[i], &st)) {
00152       fprintf(stderr, "ERROR: file not found: %s\n", files[i]);
00153       goto failure;
00154     }
00155 
00156     if (mar_push(&stack, st.st_size, st.st_mode & 0777, files[i]))
00157       goto failure;
00158 
00159     /* concatenate input file to archive */
00160     if (mar_concat_file(fp, files[i]))
00161       goto failure;
00162   }
00163 
00164   /* write out the index (prefixed with length of index) */
00165   size_of_index = htonl(stack.size_used);
00166   if (fwrite(&size_of_index, sizeof(size_of_index), 1, fp) != 1)
00167     goto failure;
00168   if (fwrite(stack.head, stack.size_used, 1, fp) != 1)
00169     goto failure;
00170 
00171   /* write out offset to index file in network byte order */
00172   offset_to_index = htonl(stack.last_offset);
00173   if (fseek(fp, MAR_ID_SIZE, SEEK_SET))
00174     goto failure;
00175   if (fwrite(&offset_to_index, sizeof(offset_to_index), 1, fp) != 1)
00176     goto failure;
00177 
00178   rv = 0;
00179 failure: 
00180   if (stack.head)
00181     free(stack.head);
00182   fclose(fp);
00183   if (rv)
00184     remove(dest);
00185   return rv;
00186 }