"Fossies" - the Fresh Open Source Software Archive

Member "unipkg-0.6.5/archive.c" (16 Dec 2005, 14887 Bytes) of package /linux/privat/old/unipkg-0.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /******************************************************************************\
    2 *                                                                              *
    3 * UniPKG (c) iSteve <isteve@bofh.cz>, 2005                                     *
    4 *                                                                              *
    5 * Universal PacKaGer.                                                          *
    6 * Licensed under GNU/GPL - if you don't like the software, fix it!             *
    7 *                                                                              *
    8 \******************************************************************************/
    9 
   10 #define _GNU_SOURCE
   11 #include <stdlib.h>
   12 #include <stdio.h>
   13 #include <string.h>
   14 #include <unistd.h>
   15 #include <fcntl.h>
   16 
   17 #include <ctype.h>
   18 #include <libgen.h>
   19 
   20 #include <sys/types.h>
   21 #include <sys/mman.h>
   22 #include <sys/stat.h>
   23 
   24 #include "common.h"
   25 #include "archive.h"
   26 
   27 #ifdef HAVE_SYSMACROS_H
   28 #include <sys/sysmacros.h>
   29 #endif
   30 
   31 typedef struct {
   32     char    *name;
   33     time_t  time;
   34     uid_t   uid;
   35     gid_t   gid;
   36     mode_t  mode;
   37     off_t       filesize;
   38 } arheader;
   39 
   40 typedef struct {
   41     char    *name;
   42     mode_t  mode;
   43     time_t  time;
   44     uid_t   uid;
   45     gid_t   gid;
   46     off_t       filesize;
   47     char            linkflag;
   48     char            *linktarget;
   49     unsigned long   devmajor;
   50     unsigned long   devminor;
   51     
   52     int             tarstage;   // for GNU tar extensions
   53 } tarheader;
   54 
   55 typedef struct {
   56     char *name;
   57     mode_t mode;
   58     uid_t uid;
   59     gid_t gid;
   60     time_t time;
   61     off_t filesize;
   62     unsigned long devmajor;
   63     unsigned long devminor;
   64     off_t namesize;
   65     
   66     off_t   archivesize;
   67     int pad;
   68 } cpioheader;
   69 
   70 ///////////////////////////////////////////////////////////////////////////////
   71 // T A R   F U N C T I O N S                                                 //
   72 ///////////////////////////////////////////////////////////////////////////////
   73 static tarheader *init_tar_archive(void) {
   74     tarheader *rv;
   75     
   76     rv = malloc(sizeof(tarheader));
   77     rv->name = NULL;
   78     rv->linktarget = NULL;
   79     rv->tarstage = 0;
   80     rv->linkflag = '\0';
   81     
   82     return rv;
   83 }
   84 
   85 static void clear_tar_archive(tarheader *tarhdr) {
   86     free(tarhdr->name);
   87     free(tarhdr->linktarget);
   88     tarhdr->name = NULL;
   89     tarhdr->tarstage = 0;
   90     tarhdr->linktarget = NULL;
   91 }
   92 
   93 ///////////////////////////////////////////////////////////////////////////////
   94 // A R   F U N C T I O N S                                                   //
   95 ///////////////////////////////////////////////////////////////////////////////
   96 static arheader *init_ar_archive(void) {
   97     arheader *rv;
   98     
   99     rv = malloc(sizeof(arheader));
  100     rv->name = NULL;
  101     
  102     return rv;
  103 }
  104 
  105 static void clear_ar_archive(arheader *arhdr) {
  106     free(arhdr->name);
  107     arhdr->name = NULL;
  108 }
  109 
  110 ///////////////////////////////////////////////////////////////////////////////
  111 // C P I O   F U N C T I O N S                                               //
  112 ///////////////////////////////////////////////////////////////////////////////
  113 static cpioheader *init_cpio_archive(void) {
  114     cpioheader *rv;
  115     
  116     rv = malloc(sizeof(cpioheader));
  117     rv->archivesize = 0;
  118     rv->pad = 0;
  119     rv->name = NULL;
  120     
  121     return rv;
  122 }
  123 
  124 static void clear_cpio_archive(cpioheader *cpiohdr) {
  125     free(cpiohdr->name);
  126     cpiohdr->name = NULL;
  127 }
  128 
  129 ///////////////////////////////////////////////////////////////////////////////
  130 // A P I   F U N C T I O N S                                                 //
  131 ///////////////////////////////////////////////////////////////////////////////
  132 static unsigned long strtouln(char *src, unsigned long len, int base) {
  133     char            *tmp;
  134     unsigned long   rv;
  135     
  136     tmp = strndup(src, len);
  137     rv = strtoul(tmp, NULL, base);
  138     free(tmp);
  139     return rv;
  140 }
  141 
  142 static void update_stage_simple(comarchive *carchive) {
  143     if (carchive->stage == AS_DATA) {
  144         if (carchive->filesize > 0) {
  145             if (carchive->upfilesize >= carchive->filesize) {
  146                 carchive->stage = AS_HEADER;
  147             } else {
  148                 carchive->stage = AS_DATA;
  149             }
  150         } else {
  151             carchive->stage = AS_HEADER;
  152         }
  153     }
  154 }
  155 
  156 comarchive *init_archive(int atype) {
  157     comarchive *rv;
  158     
  159     rv = malloc(sizeof(comarchive));
  160     rv->atype = atype;
  161     rv->internal = NULL;
  162     
  163     switch (rv->atype) {
  164         case AT_TAR:
  165             rv->internal = init_tar_archive();
  166             break;
  167         case AT_AR:
  168             rv->internal = init_ar_archive();
  169             break;
  170         case AT_CPIO:
  171             rv->internal = init_cpio_archive();
  172             break;
  173     }
  174     
  175     rv->name = NULL;
  176     rv->linktarget = NULL;
  177     rv->stage = AS_HEADER;
  178     rv->ftype = AF_UNDEFINED;
  179     rv->filesize = 0;
  180     rv->upfilesize = 0;
  181     rv->longheader = 0;
  182     
  183     return rv;
  184 }
  185 
  186 void clear_archive_member(comarchive *carchive) {
  187     if (carchive->longheader)
  188         return;
  189     
  190     switch (carchive->atype) {
  191         case AT_TAR:
  192             clear_tar_archive(carchive->internal);
  193             break;
  194         case AT_AR:
  195             clear_ar_archive(carchive->internal);
  196             break;
  197         case AT_CPIO:
  198             clear_cpio_archive(carchive->internal);
  199             break;
  200     }
  201     
  202     free(carchive->name);
  203     free(carchive->linktarget);
  204     
  205     carchive->name = NULL;
  206     carchive->linktarget = NULL;
  207     carchive->ftype = AF_UNDEFINED;
  208     carchive->filesize = 0;
  209     carchive->upfilesize = 0;
  210 }
  211 
  212 void deinit_archive(comarchive *carchive) {
  213     clear_archive_member(carchive);
  214     
  215     free(carchive->internal);
  216     free(carchive);
  217 }
  218 
  219 void update_stage(comarchive *carchive) {
  220     if (carchive->stage == AS_NEWFILE)
  221         carchive->stage = AS_DATA;
  222     
  223     update_stage_simple(carchive);
  224 }
  225 
  226 void update_upfilesize(comarchive *carchive) {
  227     switch (carchive->atype) {
  228         case AT_CPIO:
  229             if (((cpioheader*)(carchive->internal)) -> pad == -1)
  230                 return; // And thus prevent updating upfilesize;
  231             break;
  232     }
  233     carchive->upfilesize += carchive->nextblock;
  234 }
  235 
  236 void update_nextblock(comarchive *carchive) {
  237     update_stage(carchive);
  238     
  239     switch (carchive->atype) {
  240         case AT_TAR:
  241                 carchive->nextblock = 512;  // Fix size.
  242                 if (carchive->stage == AS_MOREHEAD) {
  243                     // We have the long name here. Let's unpack it in one burst.
  244                     carchive->nextblock = carchive->filesize + TARPAD(carchive->filesize);
  245                 }
  246             break;
  247         case AT_AR:
  248                 switch (carchive->stage) {
  249                     case AS_HEADER:
  250                         carchive->nextblock = 60;
  251                         break;
  252                     case AS_DATA:
  253                         // 512 is such a neat blocksize...
  254                         carchive->nextblock = (carchive->filesize - carchive->upfilesize > 512) ? 512 : carchive->filesize - carchive->upfilesize;
  255                         break;
  256                 }
  257             break;
  258         case AT_CPIO:
  259                 if ((((cpioheader*)(carchive->internal)) -> pad == 1) && (CPIOPAD(((cpioheader*)(carchive->internal)) -> archivesize))) {
  260                     carchive->nextblock = CPIOPAD(((cpioheader*)(carchive->internal)) -> archivesize);
  261                     ((cpioheader*)(carchive->internal)) -> pad = -1;
  262                 } else {
  263                     ((cpioheader*)(carchive->internal)) -> pad = 0;
  264                     switch (carchive->stage) {
  265                         case AS_HEADER:
  266                             carchive->nextblock = 110;
  267                             break;
  268                         case AS_MOREHEAD:
  269                             if (carchive->name == NULL) {
  270                                 carchive->nextblock = ((cpioheader*)(carchive->internal)) -> namesize;
  271                             } else if (carchive->ftype == AF_SYMLINK) {
  272                                 carchive->nextblock = ((cpioheader*)(carchive->internal)) -> filesize;
  273                             }
  274                             break;
  275                         case AS_DATA:
  276                             if (carchive->filesize - carchive->upfilesize > 512) {
  277                                 carchive->nextblock = 512;
  278                             } else {
  279                                 carchive->nextblock = carchive->filesize - carchive->upfilesize;
  280                                 carchive->nextblock += CPIOPAD(((cpioheader*)(carchive->internal)) -> archivesize + carchive->nextblock);
  281                             }
  282                             break;
  283                     }
  284                 }
  285                 ((cpioheader*)(carchive->internal)) -> archivesize += carchive->nextblock;
  286             break;
  287     }
  288 }
  289 
  290 // Returns 0 on data reading, 1 on file header parsing finished, 2 on end of archive
  291 // Sets stage, too; 0 = finished file, need initial header; 1 = need more header, ask nextblock; 2 = reading data.
  292 int parse_block(comarchive *carchive, char *block) {
  293     int rv;
  294         
  295     if (carchive->stage == AS_DATA)
  296         return 0;
  297     
  298     rv = 0;
  299     
  300     // Block is exactly nextblock large.
  301     switch (carchive->atype) {
  302         case AT_TAR:
  303                 switch (carchive->stage) {
  304                         case AS_HEADER:
  305                         if (block[0] == 0x0) {
  306                             rv = 2;
  307                             break;
  308                         }
  309                         
  310                         carchive->upfilesize = 0;
  311                     
  312                         carchive->mode = ((tarheader*)(carchive->internal))->mode = strtouln((block+100), 8, 8);
  313                         carchive->uid = ((tarheader*)(carchive->internal))->uid = strtouln((block+108), 8, 8);
  314                         carchive->gid = ((tarheader*)(carchive->internal))->gid = strtouln((block+116), 8, 8);
  315                         carchive->filesize = ((tarheader*)(carchive->internal))->filesize = strtouln((block+124), 12, 8);
  316                         carchive->time = ((tarheader*)(carchive->internal))->time = strtouln((block+136), 12, 8);
  317                         ((tarheader*)(carchive->internal))->linkflag = block[156];
  318                         
  319                         carchive->dmajor = ((tarheader*)(carchive->internal))->devmajor = strtouln((block+329), 8, 10);
  320                         carchive->dminor = ((tarheader*)(carchive->internal))->devminor = strtouln((block+337), 8, 10);
  321                         
  322                         carchive->stage = AS_NEWFILE;
  323 
  324                         if (((tarheader*)(carchive->internal))->tarstage == 0) {
  325                             ((tarheader*)(carchive->internal))->name = strndup(block, 100);
  326                             carchive->name = strdup(((tarheader*)(carchive->internal))->name);
  327                             
  328                             ((tarheader*)(carchive->internal))->linktarget = strndup(block+157, 100);
  329                             carchive->linktarget = strdup(((tarheader*)(carchive->internal))->linktarget);
  330                         } else {
  331                             ((tarheader*)(carchive->internal))->tarstage = 0;
  332                         }
  333                         
  334                         switch (((tarheader*)(carchive->internal))->linkflag) {
  335                             // Them bloody GNU tar extensions...
  336                             case 'L':
  337                                 ((tarheader*)(carchive->internal))->name = realloc(((tarheader*)(carchive->internal))->name, ((tarheader*)(carchive->internal))->filesize+1);
  338                                 carchive->stage = AS_MOREHEAD;
  339                                 ((tarheader*)(carchive->internal))->tarstage = 1;
  340                                 carchive->longheader = 1;
  341                                 break;
  342                             case 'K':
  343                                 ((tarheader*)(carchive->internal))->linktarget = realloc(((tarheader*)(carchive->internal))->linktarget, ((tarheader*)(carchive->internal))->filesize+1);
  344                                 carchive->stage = AS_MOREHEAD;
  345                                 ((tarheader*)(carchive->internal))->tarstage = 1;
  346                                 carchive->longheader = 1;
  347                                 break;
  348                             
  349                             case '\0':
  350                             case '0':
  351                                 carchive->ftype = AF_REGULAR;
  352                                 break;
  353                             /*case '1':
  354                                 // Hard link
  355                                 break;*/
  356                             case '2':
  357                                 carchive->ftype = AF_SYMLINK;
  358                                 break;
  359                             case '3':
  360                             case '4':
  361                                 carchive->ftype = AF_DEVNODE;
  362                                 break;
  363                             case '5':
  364                                 carchive->ftype = AF_DIRECTORY;
  365                                 break;
  366                             case '6':
  367                                 carchive->ftype = AF_FIFOBUF;
  368                                 break;
  369                         }
  370                         
  371                         if (carchive->stage == AS_NEWFILE)
  372                             carchive->longheader = 0;
  373 
  374                         break;
  375                         
  376                     case AS_MOREHEAD:
  377                         switch (((tarheader*)(carchive->internal))->linkflag) {
  378                             // Them bloody GNU tar extensions...
  379                             case 'L':
  380                                 memcpy(((tarheader*)(carchive->internal))->name, block, carchive->filesize);
  381                                 free(carchive->name);
  382                                 carchive->name = strdup(((tarheader*)(carchive->internal))->name);
  383                                 break;
  384                             case 'K':
  385                                 memcpy(((tarheader*)(carchive->internal))->linktarget, block, carchive->filesize);
  386                                 free(carchive->linktarget);
  387                                 carchive->linktarget = strdup(((tarheader*)(carchive->internal))->linktarget);
  388                                 break;
  389                         }
  390                         carchive->stage = AS_HEADER;
  391                         break;
  392                 }
  393             break;
  394                 
  395         case AT_AR:
  396                 if (carchive->stage == AS_HEADER) {
  397                     ((arheader*)(carchive->internal))->name = strndup(block, 16);
  398                     carchive->name = strdup(((arheader*)(carchive->internal))->name);
  399                     
  400                     carchive->time = ((arheader*)(carchive->internal))->time = strtouln(block + 16, 12, 10);
  401                     
  402                     carchive->uid = ((arheader*)(carchive->internal))->uid = strtouln(block + 28, 6, 10);
  403                     carchive->gid = ((arheader*)(carchive->internal))->gid = strtouln(block + 34, 6, 10);
  404                     
  405                     carchive->mode = ((arheader*)(carchive->internal))->mode = strtouln(block + 40, 8, 8);
  406                     
  407                     if (S_ISREG(carchive->mode)) carchive->ftype = AF_REGULAR;
  408                     else if (S_ISDIR(carchive->mode)) carchive->ftype = AF_DIRECTORY;
  409                     else if (S_ISLNK(carchive->mode)) carchive->ftype = AF_SYMLINK;
  410                     else if (S_ISFIFO(carchive->mode)) carchive->ftype = AF_FIFOBUF;
  411                     else if (S_ISSOCK(carchive->mode)) carchive->ftype = AF_SOCKET;
  412                     else if ((S_ISBLK(carchive->mode)) || (S_ISCHR(carchive->mode))) carchive->ftype = AF_DEVNODE;
  413                     
  414                     carchive->filesize = ((arheader*)(carchive->internal))->filesize = strtouln(block + 48, 10, 10);
  415                     
  416                     carchive->stage = AS_NEWFILE;
  417                 }
  418             break;
  419         case AT_CPIO:
  420                 if (((cpioheader*)(carchive->internal)) -> pad == -1) {
  421                     ((cpioheader*)(carchive->internal)) -> pad = 0;
  422                     break;
  423                 }
  424                 
  425                 switch (carchive->stage) {
  426                     case AS_HEADER:
  427                             if ((memcmp(block, "07070", 5)) || ((block[5] != '1') && (block[5] != '2'))) {
  428                                 fprintf(stderr, "block[0] = '%c' = %d\n", block[0], block[0]);
  429                                 return 2;
  430                             }
  431                             
  432                             carchive->stage = AS_MOREHEAD;
  433                             carchive->name = NULL;
  434                             
  435                             carchive->mode = ((cpioheader*)(carchive->internal))->mode = strtouln(block + 14, 8, 16);
  436                             carchive->uid = ((cpioheader*)(carchive->internal))->uid = strtouln(block + 22, 8, 16);
  437                             carchive->gid = ((cpioheader*)(carchive->internal))->gid = strtouln(block + 30, 8, 16);
  438                             
  439                             carchive->time = ((cpioheader*)(carchive->internal))->time = strtouln(block + 46, 8, 16);
  440                             carchive->filesize = ((cpioheader*)(carchive->internal))->filesize = strtouln(block + 54, 8, 16);
  441                             
  442                             carchive->dmajor = ((cpioheader*)(carchive->internal))->devmajor = strtouln(block + 78, 8, 16);
  443                             carchive->dminor = ((cpioheader*)(carchive->internal))->devminor = strtouln(block + 86, 8, 16);
  444                             
  445                             ((cpioheader*)(carchive->internal))->namesize = strtouln(block + 94, 8, 16);
  446                             
  447                             if (S_ISREG(carchive->mode)) carchive->ftype = AF_REGULAR;
  448                             else if (S_ISDIR(carchive->mode)) carchive->ftype = AF_DIRECTORY;
  449                             else if (S_ISLNK(carchive->mode)) carchive->ftype = AF_SYMLINK;
  450                             else if (S_ISFIFO(carchive->mode)) carchive->ftype = AF_FIFOBUF;
  451                             else if (S_ISSOCK(carchive->mode)) carchive->ftype = AF_SOCKET;
  452                             else if ((S_ISBLK(carchive->mode)) || (S_ISCHR(carchive->mode))) carchive->ftype = AF_DEVNODE;
  453                         break;
  454                     case AS_MOREHEAD:
  455                             if (carchive->name == NULL) {
  456                                 ((cpioheader*)(carchive->internal))->name = strndup(block, ((cpioheader*)(carchive->internal))->namesize);
  457                                 carchive->name = strdup(((cpioheader*)(carchive->internal))->name);
  458                                 
  459                                 if ((carchive->filesize == 0) && (!strcmp(carchive->name, "TRAILER!!!"))) {
  460                                     return 2;
  461                                 }
  462                                 
  463                                 if (carchive->ftype != AF_SYMLINK) {
  464                                     carchive->stage = AS_NEWFILE;
  465                                 }
  466                             } else if (carchive->ftype == AF_SYMLINK) {
  467                                 carchive->linktarget = strndup(block, carchive->filesize);
  468                                 carchive->upfilesize = carchive->filesize;
  469                                 carchive->stage = AS_DATA;
  470                             }
  471                             ((cpioheader*)(carchive->internal)) -> pad = 1;
  472                         break;
  473                 }
  474             break;
  475     }
  476     
  477     return rv;
  478 }