"Fossies" - the Fresh Open Source Software Archive

Member "unipkg-0.6.5/unipkglib/unipkg-rpm.c" (16 Dec 2005, 16641 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 ///////////////////////////////////////////////////////////////////////////////
   11 //                                                                           //
   12 // B A S E   I N C L U S I O N S   A N D   D E F I N I T I O N S             //
   13 //                                                                           //
   14 ///////////////////////////////////////////////////////////////////////////////
   15 #define _GNU_SOURCE
   16 
   17 #include <stdlib.h>
   18 #include <stdio.h>
   19 #include <string.h>
   20 #include <unistd.h>
   21 #include <fcntl.h>
   22 #include <libgen.h>
   23 
   24 #include <sys/types.h>
   25 #include <sys/mman.h>
   26 #include <sys/stat.h>
   27 
   28 #ifdef HAVE_SYSMACROS_H
   29 #include <sys/sysmacros.h>
   30 #endif
   31 
   32 #include <errno.h>
   33 
   34 #include <zlib.h>
   35 
   36 #include "../archive.h"
   37 #include "../common.h"
   38 #include "../compression.h"
   39 
   40 #define RPMLEAD_MAGIC           "\xed\xab\xee\xdb"
   41 #define RPMLEAD_MAGICSIZE       4
   42 #define RPMLEAD_SIZE            96
   43 #define RPMCOMMON_SIZEBLOCK     4
   44 #define RPMCOMMON_INDEXSIZE     16
   45 
   46 #define RPMHEADER_MAGIC         "\x8e\xad\xe8"
   47 #define RPMHEADER_MAGICSIZE     3
   48 
   49 #define RPMTAG_I18NTABLE       100
   50 #define RPMTAG_NAME                     1000
   51 #define RPMTAG_VERSION                  1001
   52 
   53 #define RPMHT_NULL          0
   54 #define RPMHT_CHAR          1
   55 #define RPMHT_INT8          2
   56 #define RPMHT_INT16         3
   57 #define RPMHT_INT32         4
   58 #define RPMHT_INT64         5
   59 #define RPMHT_STRING            6
   60 #define RPMHT_BIN           7
   61 #define RPMHT_STRING_ARRAY          8
   62 #define RPMHT_I18NSTRING            9
   63 
   64 #define RAW2DEC(buffer) (256*(256*(256*((unsigned char)((buffer)[0])) + ((unsigned char)((buffer)[1]))) + ((unsigned char)((buffer)[2]))) + ((unsigned char)((buffer)[3])))
   65 
   66 typedef struct {
   67     unsigned long tagdef;
   68     unsigned long tagdatatype;
   69     unsigned long tagdatacount;
   70     unsigned long tagdataoffset;
   71 } rpmheader;
   72 
   73 ///////////////////////////////////////////////////////////////////////////////
   74 //                                                                           //
   75 // B A S E   F U N C T I O N S                                               //
   76 //                                                                           //
   77 ///////////////////////////////////////////////////////////////////////////////
   78 
   79 // PARSE_RPM_HEADER
   80 //
   81 // Parses the RPM header
   82 //
   83 // Parameters:
   84 //   the header bloxk
   85 //   pointer to rpm data structure, to which data is written
   86 //
   87 // Return value:
   88 //   none
   89 static void parse_rpm_header(char *block, rpmheader *chead) {
   90     chead->tagdef = RAW2DEC(block);
   91     chead->tagdatatype = RAW2DEC(block+4);
   92     chead->tagdataoffset = RAW2DEC(block+8);
   93     chead->tagdatacount = RAW2DEC(block+12);
   94 }
   95 
   96 // COMPRESSIONSWITCH()
   97 //
   98 // Used to switch for proper compression
   99 //
  100 // Parameters:
  101 //   the value of header ID 1125
  102 //   original compression
  103 //
  104 // Return value:
  105 //   new compression
  106 static int compressionswitch(const char *header, int compression) {
  107     if (!strcmp(header, "gzip")) { return C_GZIP; }
  108     if (!strcmp(header, "bzip2")) { return C_BZIP2; }
  109     return compression;
  110 }
  111 
  112 // ADDFILEWITHDIR()
  113 //
  114 // Ensures that the directories are properly listed in pkginfo.
  115 //
  116 // Parameters:
  117 //   package descriptor
  118 //   filename
  119 //
  120 // Return value:
  121 //   none
  122 static void addfilewithdir(pkginfo *pinfo, char *filename, int flag) {
  123     char        *buf, *ptr, tmpc;
  124     unsigned long   i, buflen, ofilecount;
  125     int     found;
  126     
  127     buf = strdup(filename);
  128     buflen = strlen(filename);
  129     
  130     ofilecount = pinfo->filecount;
  131     
  132     ptr = buf;
  133     tmpc = '\0';
  134     while ((ptr = strchr(ptr, '/')) != NULL) {
  135         if ((unsigned long)(ptr - buf) < buflen) {
  136             tmpc = ptr[1];
  137             ptr[1] = '\0';
  138         }
  139         
  140         // Ensure adding.
  141         found = 0;
  142         
  143         if (ofilecount > 0) {
  144             i = ofilecount; // Otherwise a loop occures.
  145         
  146             while (i-- > 0) {
  147                 if (!strcmp(pinfo->files[i].name, buf)) {
  148                     found = 1;
  149                     break;
  150                 }
  151             }
  152         }
  153         
  154         if (!found) {
  155             addfile(pinfo, strdup(buf), F_DIRECTORY);
  156         }
  157 
  158         if ((unsigned long)(ptr - buf) < buflen) {
  159             ptr[1] = tmpc;
  160         }
  161         ptr++;
  162     }
  163     free(buf);
  164     
  165     addfile(pinfo, filename, flag);
  166 }
  167 
  168 ///////////////////////////////////////////////////////////////////////////////
  169 //                                                                           //
  170 // A P I   F U N C T I O N S                                                 //
  171 //                                                                           //
  172 ///////////////////////////////////////////////////////////////////////////////
  173 int identify(packdef pdef) {
  174     char    buf[RPMLEAD_MAGICSIZE];
  175     unsigned long   curpos;
  176     if ((curpos = ftell(pdef.filepointer)) == -1) {
  177         return 2;
  178     }
  179     if (fseek(pdef.filepointer, 0, SEEK_SET)) {
  180         return 2;
  181     }
  182     
  183     if (!fread(buf, RPMLEAD_MAGICSIZE, 1, pdef.filepointer)) {
  184         return 2;
  185     }
  186     
  187     if (fseek(pdef.filepointer, curpos, SEEK_SET)) {
  188         return 2;
  189     }
  190     
  191     if (memcmp(buf, RPMLEAD_MAGIC, RPMLEAD_MAGICSIZE) == 0) {
  192         return 0;
  193     }
  194     else {
  195         return 1;
  196     }
  197 }
  198 
  199 int pkgdetails(packdef pdef, pkginfo *pinfo) {
  200     void            *filemap;
  201     struct stat     statbuf;
  202     off_t               offset, store_offset, current_offset;
  203     off_t               i, indexes, storesize;
  204     rpmheader       rheader;
  205     int             cloc_id = 0;
  206     unsigned long   cloop;
  207     
  208     int             err, compression = C_GZIP;
  209     c_compdata      cstream;
  210     comarchive      *cpio_archive;
  211     char            *obuf;
  212     unsigned long   obuflen;
  213     
  214     fstat(fileno(pdef.filepointer), &statbuf);
  215     filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
  216     if (filemap == MAP_FAILED) { return 1; }
  217     
  218     offset = RPMLEAD_SIZE;
  219     
  220     // We now jump the signatures
  221     if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
  222         munmap(filemap, statbuf.st_size);
  223         return 1;
  224     }
  225     indexes = RAW2DEC((char*)(filemap + offset + 8));
  226     storesize = RAW2DEC((char*)(filemap + offset + 12));
  227     
  228     offset += RPMCOMMON_INDEXSIZE; // Skip the initial header of section
  229     offset += RPMCOMMON_INDEXSIZE * indexes + storesize +  ((8 - (storesize % 8)) % 8);
  230     
  231     // And arrive at headers
  232     if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
  233         munmap(filemap, statbuf.st_size);
  234         return 1;
  235     }
  236     indexes = RAW2DEC((char*)(filemap + offset + 8));
  237     storesize = RAW2DEC((char*)(filemap + offset + 12));
  238     
  239     offset += RPMCOMMON_INDEXSIZE;
  240     store_offset = offset + RPMCOMMON_INDEXSIZE * indexes;
  241     for (i = 0; i < indexes; i++) {
  242         parse_rpm_header(filemap + offset, &rheader);
  243 
  244         switch (rheader.tagdef) {
  245             case 100:
  246                 // Locale list table.
  247                 if (rheader.tagdatatype != RPMHT_STRING_ARRAY) continue;
  248                     
  249                 current_offset = store_offset + rheader.tagdataoffset;
  250                 for (cloop = 0; cloop < rheader.tagdatacount; cloop++) {
  251                     if (!strcmp(filemap + current_offset, "C")) {
  252                         cloc_id = cloop;
  253                         break;
  254                     }
  255                     
  256                     current_offset += strlen(filemap + current_offset) + 1;
  257                 }
  258                 break;
  259             
  260             case 1000:
  261                 if (rheader.tagdatatype != RPMHT_STRING) continue;
  262                 
  263                 current_offset = store_offset + rheader.tagdataoffset;
  264                 pinfo->name = strdup(filemap + current_offset);
  265                 break;
  266                 
  267             case 1001:
  268                 if (rheader.tagdatatype != RPMHT_STRING) continue;
  269                 
  270                 current_offset = store_offset + rheader.tagdataoffset;
  271                 pinfo->version = strdup(filemap + current_offset);
  272                 break;
  273                 
  274             case 1004:
  275                 current_offset = store_offset + rheader.tagdataoffset;
  276                 switch (rheader.tagdatatype) {
  277                     case RPMHT_I18NSTRING:
  278                         for (cloop = 0; cloop < cloc_id; cloop++) {
  279                             current_offset += strlen(filemap + current_offset) + 1;
  280                         }
  281                         pinfo->description = strdup(filemap + current_offset);
  282                         break;
  283                     case RPMHT_STRING:
  284                         pinfo->description = strdup(filemap + current_offset);
  285                         break;
  286                 }
  287                 break;
  288 
  289                 
  290             case 1023:
  291                 current_offset = store_offset + rheader.tagdataoffset;
  292                 switch (rheader.tagdatatype) {
  293                     case RPMHT_STRING:
  294                         pinfo->preinst.data = strdup(filemap + current_offset);
  295                         pinfo->preinst.len = strlen(pinfo->preinst.data);
  296                         break;
  297                     case RPMHT_BIN:
  298                         pinfo->preinst.len = rheader.tagdatacount;
  299                         pinfo->preinst.data = malloc(pinfo->preinst.len);
  300                         memcpy(pinfo->preinst.data, filemap + current_offset, pinfo->preinst.len);
  301                         break;
  302                 }
  303                 break;
  304             case 1024:
  305                 current_offset = store_offset + rheader.tagdataoffset;
  306                 switch (rheader.tagdatatype) {
  307                     case RPMHT_STRING:
  308                         pinfo->postinst.data = strdup(filemap + current_offset);
  309                         pinfo->postinst.len = strlen(pinfo->postinst.data);
  310                         break;
  311                     case RPMHT_BIN:
  312                         pinfo->postinst.len = rheader.tagdatacount;
  313                         pinfo->postinst.data = malloc(pinfo->postinst.len);
  314                         memcpy(pinfo->postinst.data, filemap + current_offset, pinfo->postinst.len);
  315                         break;
  316                 }
  317                 break;
  318             case 1025:
  319                 current_offset = store_offset + rheader.tagdataoffset;
  320                 switch (rheader.tagdatatype) {
  321                     case RPMHT_STRING:
  322                         pinfo->prerm.data = strdup(filemap + current_offset);
  323                         pinfo->prerm.len = strlen(pinfo->prerm.data);
  324                         break;
  325                     case RPMHT_BIN:
  326                         pinfo->prerm.len = rheader.tagdatacount;
  327                         pinfo->prerm.data = malloc(pinfo->prerm.len);
  328                         memcpy(pinfo->prerm.data, filemap + current_offset, pinfo->prerm.len);
  329                         break;
  330                 }
  331                 break;
  332             case 1026:
  333                 current_offset = store_offset + rheader.tagdataoffset;
  334                 switch (rheader.tagdatatype) {
  335                     case RPMHT_STRING:
  336                         pinfo->postrm.data = strdup(filemap + current_offset);
  337                         pinfo->postrm.len = strlen(pinfo->postrm.data);
  338                         break;
  339                     case RPMHT_BIN:
  340                         pinfo->postrm.len = rheader.tagdatacount;
  341                         pinfo->postrm.data = malloc(pinfo->postrm.len);
  342                         memcpy(pinfo->postrm.data, filemap + current_offset, pinfo->postrm.len);
  343                         break;
  344                 }
  345                 break;
  346                 
  347             case 1125:
  348                 if (rheader.tagdatatype != RPMHT_STRING) continue;
  349                 
  350                 current_offset = store_offset + rheader.tagdataoffset;
  351                 compression = compressionswitch(filemap + current_offset, compression);
  352                 break;
  353         }
  354         
  355         offset += RPMCOMMON_INDEXSIZE;
  356     }
  357     offset += storesize;
  358     
  359     obuflen = 100;
  360     obuf = malloc(obuflen);
  361     
  362     err = decompression_setup(&cstream, filemap, offset, statbuf.st_size, obuf, obuflen, C_GZIP);
  363     if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) {
  364         decompression_cleanup(&cstream);
  365         munmap(filemap, statbuf.st_size);
  366         free(obuf);
  367         return 1;
  368     }
  369     
  370     cpio_archive = init_archive(AT_CPIO);
  371     do {
  372         if (cpio_archive->stage == AS_NEWFILE) {
  373             addfilewithdir(pinfo, absolutizestr(cpio_archive->name, "/"), (cpio_archive->ftype == AF_DIRECTORY) ? F_DIRECTORY : F_REGULAR);
  374             pinfo->pkgsize += cpio_archive->filesize;
  375         }
  376         
  377         update_nextblock(cpio_archive);
  378         
  379         if (cpio_archive->nextblock > obuflen) {
  380             obuflen = cpio_archive->nextblock;
  381             obuf = realloc(obuf, obuflen);
  382         }
  383         memset(obuf, 0, obuflen);
  384         
  385         if (decompression_decompress(&cstream, cpio_archive->nextblock, obuf) != CE_OK)
  386             break;
  387         
  388         if (decompression_ammount_not_processed(&cstream) > 0)
  389             break;
  390         
  391         update_stage(cpio_archive);
  392         
  393         switch (cpio_archive->stage) {
  394             case AS_DATA:
  395                 update_upfilesize(cpio_archive);
  396                 break;
  397             case AS_HEADER:
  398                 clear_archive_member(cpio_archive);
  399                 break;
  400         }
  401         
  402         err = parse_block(cpio_archive, obuf);
  403         
  404         if (err)
  405             break;
  406     } while (decompression_ammount_left(&cstream, 0) > 0);
  407     deinit_archive(cpio_archive);
  408     decompression_cleanup(&cstream);
  409     munmap(filemap, statbuf.st_size);
  410     free(obuf);
  411     return 0;
  412 }
  413 
  414 int pkginstall(packdef pdef) {
  415     void            *filemap;
  416     struct stat     statbuf;
  417     off_t               offset, store_offset, current_offset;
  418     off_t               i, indexes, storesize;
  419     rpmheader       rheader;
  420     int             cloc_id = 0;
  421     unsigned long   cloop;
  422     
  423     int             err, compression = C_GZIP;
  424     c_compdata      cstream;
  425     comarchive      *cpio_archive;
  426     char            *obuf;
  427     unsigned long   obuflen;
  428     char        *curpath;
  429     FILE        *fpout;
  430     
  431     fstat(fileno(pdef.filepointer), &statbuf);
  432     filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
  433     if (filemap == MAP_FAILED) 
  434         return 1;
  435     
  436     offset = RPMLEAD_SIZE;
  437     
  438     // We now jump the signatures
  439     if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
  440         munmap(filemap, statbuf.st_size);
  441         return 1;
  442     }
  443     indexes = RAW2DEC((char*)(filemap + offset + 8));
  444     storesize = RAW2DEC((char*)(filemap + offset + 12));
  445     
  446     offset += RPMCOMMON_INDEXSIZE; // Skip the initial header of section
  447     offset += RPMCOMMON_INDEXSIZE * indexes + storesize +  ((8 - (storesize % 8)) % 8);
  448     
  449     // And arrive at headers
  450     if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
  451         munmap(filemap, statbuf.st_size);
  452         return 1;
  453     }
  454     indexes = RAW2DEC((char*)(filemap + offset + 8));
  455     storesize = RAW2DEC((char*)(filemap + offset + 12));
  456     
  457     offset += RPMCOMMON_INDEXSIZE;
  458     offset += RPMCOMMON_INDEXSIZE * indexes + storesize;
  459     
  460     obuflen = 100;
  461     obuf = malloc(obuflen);
  462     
  463     err = decompression_setup(&cstream, filemap, offset, statbuf.st_size, obuf, obuflen, C_GZIP);
  464     if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) {
  465         decompression_cleanup(&cstream);
  466         munmap(filemap, statbuf.st_size);
  467         free(obuf);
  468         return 1;
  469     }
  470     
  471     fpout = NULL;
  472     curpath = NULL;
  473     
  474     cpio_archive = init_archive(AT_CPIO);
  475     do {
  476         if (cpio_archive->stage == AS_NEWFILE) {
  477             free(curpath);
  478             curpath = absolutizestr(cpio_archive->name, pdef.destdir);
  479             // Create relevant files
  480             switch (cpio_archive->ftype) {
  481                 case AF_REGULAR:
  482                         if (fpout != NULL) { 
  483                             fclose(fpout);
  484                         }
  485                         if ((fpout = fopen(curpath, "w")) == NULL) {
  486                             free(curpath);
  487                             free(obuf);
  488                             decompression_cleanup(&cstream);
  489                             munmap(filemap, statbuf.st_size);
  490                             deinit_archive(cpio_archive);
  491                             return 2;
  492                         }
  493                         
  494                         FCHOWNMOD(fileno(fpout), cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  495                         
  496                         if (cpio_archive->filesize == 0) {
  497                             // Nothing to write. We just created it.
  498                             fclose(fpout);
  499                             fpout = NULL;
  500                             
  501                             // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored
  502                             CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  503                         }
  504                     break;
  505                 case AF_SYMLINK:
  506                         symlink(cpio_archive->linktarget, curpath);
  507                         CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  508                     break;
  509                 case AF_DEVNODE:
  510                         mknod(curpath, cpio_archive->mode, makedev(cpio_archive->dmajor, cpio_archive->dminor));
  511                         CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  512                     break;
  513                 case AF_FIFOBUF:
  514                         mkfifo(curpath, cpio_archive->mode);
  515                         CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  516                     break;
  517                 case AF_DIRECTORY:
  518                         if (stat(curpath, &statbuf)) {
  519                             mkdir(curpath, cpio_archive->mode);
  520                             CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  521                         }
  522                     break;
  523             }
  524         }
  525         
  526         update_nextblock(cpio_archive);
  527         
  528         if (cpio_archive->nextblock > obuflen) {
  529             obuflen = cpio_archive->nextblock;
  530             obuf = realloc(obuf, obuflen);
  531         }
  532         memset(obuf, 0, obuflen);
  533         
  534         if (decompression_decompress(&cstream, cpio_archive->nextblock, obuf) != CE_OK)
  535             break;
  536         
  537         if (decompression_ammount_not_processed(&cstream) > 0)
  538             break;
  539         
  540         update_stage(cpio_archive);
  541         
  542         switch (cpio_archive->stage) {
  543             case AS_DATA:
  544                 // Feed data...
  545                 if (cpio_archive->ftype == AF_REGULAR) {
  546                     if (fpout != NULL) {
  547                         fwrite(obuf, ((cpio_archive->filesize - cpio_archive->upfilesize) > cpio_archive->nextblock) ? cpio_archive->nextblock : cpio_archive->filesize - cpio_archive->upfilesize, 1, fpout);
  548                     }
  549                 }
  550                 
  551                 update_upfilesize(cpio_archive);
  552                 break;
  553             case AS_HEADER:
  554                 // Clear up...
  555                 if (cpio_archive->ftype == AF_REGULAR) {
  556                     if (fpout != NULL) {
  557                         fsync(fileno(fpout));
  558                         fclose(fpout);
  559                         fpout = NULL;
  560                         
  561                         // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored
  562                         CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
  563                     }
  564                 }
  565                 clear_archive_member(cpio_archive);
  566                 break;
  567         }
  568         
  569         err = parse_block(cpio_archive, obuf);
  570         
  571         if (err)
  572             break;
  573     } while (decompression_ammount_left(&cstream, 0) > 0);
  574     deinit_archive(cpio_archive);
  575     decompression_cleanup(&cstream);
  576     munmap(filemap, statbuf.st_size);
  577     free(curpath);
  578     free(obuf);
  579     return 0;
  580 }