home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / rpm / lib / cpio.c next >
C/C++ Source or Header  |  1997-09-17  |  21KB  |  887 lines

  1. #include "config.h"
  2. #include "miscfn.h"
  3.  
  4. #if HAVE_ALLOCA_H
  5. # include <alloca.h>
  6. #endif
  7.  
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/stat.h>
  14. #include <sys/types.h>
  15. #include <unistd.h>
  16. #include <utime.h>
  17.  
  18. #include "cpio.h"
  19.  
  20. #if MAJOR_IN_SYSMACROS 
  21. #include <sys/sysmacros.h>
  22. #elif MAJOR_IN_MKDEV 
  23. #include <sys/mkdev.h>
  24. #endif
  25.  
  26. #define CPIO_NEWC_MAGIC    "070701"
  27. #define CPIO_CRC_MAGIC    "070702"
  28. #define TRAILER        "TRAILER!!!"
  29.  
  30. /* FIXME: We don't translate between cpio and system mode bits! These
  31.    should both be the same, but really odd things are going to happen if
  32.    that's not true! */
  33.  
  34. /* We need to maintain our oun file pointer to allow padding */
  35. struct ourfd {
  36.     gzFile fd;
  37.     int pos;
  38. };
  39.  
  40. struct hardLink {
  41.     struct hardLink * next;
  42.     char ** files;        /* there are nlink of these, used by install */
  43.     int * fileMaps;        /* used by build */
  44.     dev_t dev;
  45.     ino_t inode;
  46.     int nlink;            
  47.     int linksLeft;
  48.     int createdPath;
  49.     struct stat sb;
  50. };
  51.  
  52. struct cpioCrcPhysicalHeader {
  53.     char magic[6];
  54.     char inode[8];
  55.     char mode[8];
  56.     char uid[8];
  57.     char gid[8];
  58.     char nlink[8];
  59.     char mtime[8];
  60.     char filesize[8];
  61.     char devMajor[8];
  62.     char devMinor[8];
  63.     char rdevMajor[8];
  64.     char rdevMinor[8];
  65.     char namesize[8];
  66.     char checksum[8];            /* ignored !! */
  67. };
  68.  
  69. struct cpioHeader {
  70.     ino_t inode;
  71.     mode_t mode;
  72.     uid_t uid;
  73.     gid_t gid;
  74.     int nlink;
  75.     time_t mtime;
  76.     long size;
  77.     dev_t dev, rdev;
  78.     char * path;
  79. };
  80.  
  81. static inline off_t ourread(struct ourfd * thefd, void * buf, size_t size) {
  82.     off_t i;
  83.  
  84.     i = gzread(thefd->fd, buf, size);
  85.     thefd->pos += i;
  86.     
  87.     return i;
  88. }
  89.  
  90. static inline void padinfd(struct ourfd * fd, int modulo) {
  91.     int buf[10];
  92.     int amount;
  93.     
  94.     amount = (modulo - fd->pos % modulo) % modulo;
  95.     ourread(fd, buf, amount);
  96. }
  97.  
  98. static inline off_t safewrite(int fd, void * vbuf, size_t amount) {
  99.     int rc = 0;
  100.     char * buf = vbuf;
  101.  
  102.     while (amount && (rc = write(fd, buf, amount)) < amount && rc > 0) {
  103.     buf += rc;
  104.     amount -= rc;
  105.     }
  106.  
  107.     if (rc < 0) return rc;
  108.  
  109.     return 0; 
  110. }
  111.  
  112. static inline int padoutfd(int fd, int * where, int modulo) {
  113.     static int buf[10] = { '\0', '\0', '\0', '\0', '\0', 
  114.                '\0', '\0', '\0', '\0', '\0' };
  115.     int amount;
  116.     
  117.     amount = (modulo - *where % modulo) % modulo;
  118.     *where += amount;
  119.  
  120.     if (safewrite(fd, buf, amount)) 
  121.     return CPIO_WRITE_FAILED;
  122.     return 0;
  123. }
  124.  
  125. static int strntoul(const char * str, char ** endptr, int base, int num) {
  126.     char * buf;
  127.  
  128.     buf = alloca(num + 1);
  129.     strncpy(buf, str, num);
  130.     buf[num] = '\0';
  131.  
  132.     return strtoul(buf, endptr, base);
  133. }
  134.  
  135. #define GET_NUM_FIELD(phys, log) \
  136.     log = strntoul(phys, &end, 16, sizeof(phys)); \
  137.     if (*end) return CPIO_BAD_HEADER;
  138. #define SET_NUM_FIELD(phys, val, space) \
  139.     sprintf(space, "%8.8lx", (unsigned long) (val)); \
  140.     memcpy(phys, space, 8);
  141.  
  142. static int getNextHeader(struct ourfd * fd, struct cpioHeader * chPtr) {
  143.     struct cpioCrcPhysicalHeader physHeader;
  144.     int nameSize;
  145.     char * end;
  146.     int major, minor;
  147.  
  148.     if (ourread(fd, &physHeader, sizeof(physHeader)) != sizeof(physHeader)) 
  149.     return CPIO_READ_FAILED;
  150.  
  151.     if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC)) &&
  152.     strncmp(CPIO_NEWC_MAGIC, physHeader.magic, strlen(CPIO_NEWC_MAGIC)))
  153.     return CPIO_BAD_MAGIC;
  154.  
  155.     GET_NUM_FIELD(physHeader.inode, chPtr->inode);
  156.     GET_NUM_FIELD(physHeader.mode, chPtr->mode);
  157.     GET_NUM_FIELD(physHeader.uid, chPtr->uid);
  158.     GET_NUM_FIELD(physHeader.gid, chPtr->gid);
  159.     GET_NUM_FIELD(physHeader.nlink, chPtr->nlink);
  160.     GET_NUM_FIELD(physHeader.mtime, chPtr->mtime);
  161.     GET_NUM_FIELD(physHeader.filesize, chPtr->size);
  162.  
  163.     GET_NUM_FIELD(physHeader.devMajor, major);
  164.     GET_NUM_FIELD(physHeader.devMinor, minor);
  165.     chPtr->dev = makedev(major, minor);
  166.  
  167.     GET_NUM_FIELD(physHeader.rdevMajor, major);
  168.     GET_NUM_FIELD(physHeader.rdevMinor, minor);
  169.     chPtr->rdev = makedev(major, minor);
  170.  
  171.     GET_NUM_FIELD(physHeader.namesize, nameSize);
  172.  
  173.     chPtr->path = malloc(nameSize + 1);
  174.     if (ourread(fd, chPtr->path, nameSize) != nameSize) {
  175.     free(chPtr->path);
  176.     return CPIO_BAD_HEADER;
  177.     }
  178.  
  179.     /* this is unecessary chPtr->path[nameSize] = '\0'; */
  180.  
  181.     padinfd(fd, 4);
  182.  
  183.     return 0;
  184. }
  185.  
  186. int cpioFileMapCmp(const void * a, const void * b) {
  187.     const struct cpioFileMapping * first = a;
  188.     const struct cpioFileMapping * second = b;
  189.  
  190.     return (strcmp(first->archivePath, second->archivePath));
  191. }
  192.  
  193. /* This could trash files in the path! I'm not sure that's a good thing */
  194. static int createDirectory(char * path, mode_t perms) {
  195.     struct stat sb;
  196.     int dounlink;
  197.  
  198.     if (!lstat(path, &sb)) {
  199.     if (S_ISDIR(sb.st_mode)) {
  200.         return 0;
  201.     } else if (S_ISLNK(sb.st_mode)) {
  202.         if (stat(path, &sb)) {
  203.         if (errno != ENOENT) 
  204.             return CPIO_STAT_FAILED;
  205.         dounlink = 1;
  206.         } else {
  207.         if (S_ISDIR(sb.st_mode))
  208.             return 0;
  209.         dounlink = 1;
  210.         }
  211.     } else {
  212.         dounlink = 1;
  213.     }
  214.  
  215.     if (dounlink && unlink(path)) {
  216.         return CPIO_UNLINK_FAILED;
  217.     }
  218.     }
  219.  
  220.     if (mkdir(path, 000))
  221.     return CPIO_MKDIR_FAILED;
  222.  
  223.     if (chmod(path, perms))
  224.     return CPIO_CHMOD_FAILED;
  225.  
  226.     return 0;
  227. }
  228.  
  229. static int setInfo(struct cpioHeader * hdr) {
  230.     int rc = 0;
  231.     struct utimbuf stamp = { hdr->mtime, hdr->mtime };
  232.  
  233.  
  234.     if (!S_ISLNK(hdr->mode)) {
  235.     if (!getuid() && chown(hdr->path, hdr->uid, hdr->gid))
  236.         rc = CPIO_CHOWN_FAILED;
  237.     if (!rc && chmod(hdr->path, hdr->mode & 07777))
  238.         rc = CPIO_CHMOD_FAILED;
  239.     if (!rc && utime(hdr->path, &stamp))
  240.         rc = CPIO_UTIME_FAILED;
  241.     } else {
  242.     #if ! CHOWN_FOLLOWS_SYMLINK
  243.         if (!getuid() && !rc && lchown(hdr->path, hdr->uid, hdr->gid))
  244.         rc = CPIO_CHOWN_FAILED;
  245.     #endif
  246.     }
  247.  
  248.     return rc;
  249. }
  250.  
  251. static int checkDirectory(char * filename) {
  252.     static char * lastDir = NULL;
  253.     static int lastDirLength = 0;
  254.     static int lastDirAlloced = 0;
  255.     int length = strlen(filename);
  256.     char * buf;
  257.     char * chptr;
  258.     int rc = 0;
  259.  
  260.     buf = alloca(length + 1);
  261.     strcpy(buf, filename);
  262.  
  263.     for (chptr = buf + length - 1; chptr > buf; chptr--) {
  264.     if (*chptr == '/') break;
  265.     }
  266.  
  267.     if (chptr == buf) return 0;     /* /filename - no directories */
  268.  
  269.     *chptr = '\0';                  /* buffer is now just directories */
  270.  
  271.     length = strlen(buf);
  272.     if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
  273.  
  274.     if (lastDirAlloced < (length + 1)) {
  275.     lastDirAlloced = length + 100;
  276.     lastDir = realloc(lastDir, lastDirAlloced);
  277.     }
  278.  
  279.     strcpy(lastDir, buf);
  280.     lastDirLength = length;
  281.  
  282.     for (chptr = buf + 1; *chptr; chptr++) {
  283.     if (*chptr == '/') {
  284.         *chptr = '\0';
  285.         rc = createDirectory(buf, 0755);
  286.         *chptr = '/';
  287.         if (rc) return rc;
  288.     }
  289.     }
  290.     rc = createDirectory(buf, 0755);
  291.  
  292.     return rc;
  293. }
  294.  
  295. static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr,
  296.              cpioCallback cb, void * cbData) {
  297.     int out;
  298.     char buf[8192];
  299.     int bytesRead;
  300.     int left = hdr->size;
  301.     int rc = 0;
  302.     struct cpioCallbackInfo cbInfo;
  303.     struct stat sb;
  304.  
  305.     if (!lstat(hdr->path, &sb))
  306.     if (unlink(hdr->path))
  307.         return CPIO_UNLINK_FAILED;
  308.  
  309.     out = open(hdr->path, O_CREAT | O_WRONLY, 0);
  310.     if (out < 0) 
  311.     return CPIO_OPEN_FAILED;
  312.  
  313.     cbInfo.file = hdr->path;
  314.     cbInfo.fileSize = hdr->size;
  315.  
  316.     while (left) {
  317.     bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
  318.     if (bytesRead <= 0) {
  319.         rc = CPIO_READ_FAILED;
  320.         break;
  321.     }
  322.  
  323.     if (write(out, buf, bytesRead) != bytesRead) {
  324.         rc = CPIO_READ_FAILED;
  325.         break;
  326.     }
  327.  
  328.     left -= bytesRead;
  329.  
  330.     /* don't call this with fileSize == fileComplete */
  331.     if (!rc && cb && left) {
  332.         cbInfo.fileComplete = hdr->size - left;
  333.         cbInfo.bytesProcessed = fd->pos;
  334.         cb(&cbInfo, cbData);
  335.     }
  336.     }
  337.  
  338.     close(out);
  339.     
  340.     return rc;
  341. }
  342.  
  343. static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
  344.     char buf[2048], buf2[2048];
  345.     struct stat sb;
  346.     int len;
  347.  
  348.     if ((hdr->size + 1)> sizeof(buf))
  349.     return CPIO_INTERNAL;
  350.  
  351.     if (ourread(fd, buf, hdr->size) != hdr->size)
  352.     return CPIO_READ_FAILED;
  353.  
  354.     buf[hdr->size] = '\0';
  355.  
  356.     if (!lstat(hdr->path, &sb)) {
  357.     if (S_ISLNK(sb.st_mode)) {
  358.         len = readlink(hdr->path, buf2, sizeof(buf2) - 1);
  359.         if (len > 0) {
  360.         buf2[len] = '\0';
  361.         if (!strcmp(buf, buf2)) return 0;
  362.         }
  363.     }
  364.  
  365.     if (unlink(hdr->path))
  366.         return CPIO_UNLINK_FAILED;
  367.     }
  368.  
  369.     if (symlink(buf, hdr->path) < 0)
  370.     return CPIO_SYMLINK_FAILED;
  371.  
  372.     return 0;
  373. }
  374.  
  375. static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
  376.     struct stat sb;
  377.  
  378.     if (!lstat(hdr->path, &sb)) {
  379.     if (S_ISFIFO(sb.st_mode)) return 0;
  380.  
  381.     if (unlink(hdr->path))
  382.         return CPIO_UNLINK_FAILED;
  383.     }
  384.  
  385.     if (mkfifo(hdr->path, 0))
  386.     return CPIO_MKFIFO_FAILED;
  387.  
  388.     return 0; 
  389. }
  390.  
  391. static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
  392.     struct stat sb;
  393.  
  394.     if (!lstat(hdr->path, &sb)) {
  395.     if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) && 
  396.         (sb.st_rdev == hdr->rdev))
  397.         return 0;
  398.     if (unlink(hdr->path))
  399.         return CPIO_UNLINK_FAILED;
  400.     }
  401.  
  402.     if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
  403.     return CPIO_MKNOD_FAILED;
  404.     
  405.     return 0;
  406. }
  407.  
  408. static void freeLink(struct hardLink * li) {
  409.     int i;
  410.  
  411.     for (i = 0; i < li->nlink; i++) {
  412.     if (li->files[i]) free(li->files[i]);
  413.     }
  414.     free(li->files);
  415. }
  416.  
  417. static int createLinks(struct hardLink * li, char ** failedFile) {
  418.     int i;
  419.     struct stat sb;
  420.  
  421.     for (i = 0; i < li->nlink; i++) {
  422.     if (i == li->createdPath) continue;
  423.     if (!li->files[i]) continue;
  424.  
  425.     if (!lstat(li->files[i], &sb)) {
  426.         if (unlink(li->files[i])) {
  427.         *failedFile = strdup(li->files[i]);
  428.         return CPIO_UNLINK_FAILED;
  429.         }
  430.     }
  431.  
  432.     if (link(li->files[li->createdPath], li->files[i])) {
  433.         *failedFile = strdup(li->files[i]);
  434.         return CPIO_LINK_FAILED;
  435.     }
  436.  
  437.     free(li->files[i]);
  438.     li->files[i] = NULL;
  439.     li->linksLeft--;
  440.     }
  441.  
  442.     return 0;
  443. }
  444.  
  445. static int eatBytes(struct ourfd * fd, int amount) {
  446.     char buf[4096];
  447.     int bite;
  448.    
  449.     while (amount) {
  450.     bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
  451.     if (ourread(fd, buf, bite) != bite)
  452.         return CPIO_READ_FAILED;
  453.     amount -= bite;
  454.     }
  455.  
  456.     return 0;
  457. }
  458.  
  459. int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings, 
  460.                int numMappings, cpioCallback cb, void * cbData,
  461.                char ** failedFile) {
  462.     struct cpioHeader ch;
  463.     struct ourfd fd;
  464.     int rc = 0;
  465.     int linkNum = 0;
  466.     struct cpioFileMapping * map = NULL;
  467.     struct cpioFileMapping needle;
  468.     mode_t cpioMode;
  469.     int olderr;
  470.     struct cpioCallbackInfo cbInfo;
  471.     struct hardLink * links = NULL;
  472.     struct hardLink * li = NULL;
  473.  
  474.     fd.fd = stream;
  475.     fd.pos = 0;
  476.  
  477.     *failedFile = NULL;
  478.  
  479.     do {
  480.     if ((rc = getNextHeader(&fd, &ch))) {
  481.         printf("error %d reading header: %s\n", rc, strerror(errno));
  482.         exit(1);
  483.     }
  484.  
  485.     if (!strcmp(ch.path, TRAILER)) {
  486.         free(ch.path);
  487.         break;
  488.     }
  489.  
  490.     if (mappings) {
  491.         needle.archivePath = ch.path;
  492.         map = bsearch(&needle, mappings, numMappings, sizeof(needle),
  493.               cpioFileMapCmp);
  494.     }
  495.  
  496.     if (mappings && !map) {
  497.         eatBytes(&fd, ch.size);
  498.     } else {
  499.         cpioMode = ch.mode;
  500.  
  501.         if (map) {
  502.         if (map->mapFlags & CPIO_MAP_PATH) {
  503.             free(ch.path);
  504.             ch.path = strdup(map->fsPath);
  505.         } 
  506.  
  507.         if (map->mapFlags & CPIO_MAP_MODE)
  508.             ch.mode = map->finalMode;
  509.         if (map->mapFlags & CPIO_MAP_UID)
  510.             ch.uid = map->finalUid;
  511.         if (map->mapFlags & CPIO_MAP_GID)
  512.             ch.gid = map->finalGid;
  513.         }
  514.  
  515.         /* This won't get hard linked symlinks right, but I can't seem 
  516.            to create those anyway */
  517.  
  518.         if (S_ISREG(ch.mode) && ch.nlink > 1) {
  519.         li = links;
  520.         for (li = links; li; li = li->next) {
  521.             if (li->inode == ch.inode && li->dev == ch.dev) break;
  522.         }
  523.  
  524.         if (!li) {
  525.             li = malloc(sizeof(*li));
  526.             li->inode = ch.inode;
  527.             li->dev = ch.dev;
  528.             li->nlink = ch.nlink;
  529.             li->linksLeft = ch.nlink;
  530.             li->createdPath = -1;
  531.             li->files = calloc(sizeof(char *), li->nlink);
  532.             li->next = links;
  533.             links = li;
  534.         }
  535.  
  536.         for (linkNum = 0; linkNum < li->nlink; linkNum++)
  537.             if (!li->files[linkNum]) break;
  538.         li->files[linkNum] = strdup(ch.path);
  539.         }
  540.         
  541.         if ((ch.nlink > 1) && S_ISREG(ch.mode) && !ch.size &&
  542.         li->createdPath == -1) {
  543.         /* defer file creation */
  544.         } else if ((ch.nlink > 1) && S_ISREG(ch.mode) && 
  545.                (li->createdPath != -1)) {
  546.         createLinks(li, failedFile);
  547.  
  548.         /* this only happens for cpio archives which contain
  549.            hardlinks w/ the contents of each hardlink being
  550.            listed (intead of the data being given just once. This
  551.            shouldn't happen, but I've made it happen w/ buggy
  552.            code, so what the heck? GNU cpio handles this well fwiw */
  553.         if (ch.size) eatBytes(&fd, ch.size);
  554.         } else {
  555.         rc = checkDirectory(ch.path);
  556.  
  557.         if (!rc) {
  558.             if (S_ISREG(ch.mode))
  559.             rc = expandRegular(&fd, &ch, cb, cbData);
  560.             else if (S_ISDIR(ch.mode))
  561.             rc = createDirectory(ch.path, 000);
  562.             else if (S_ISLNK(ch.mode))
  563.             rc = expandSymlink(&fd, &ch);
  564.             else if (S_ISFIFO(ch.mode))
  565.             rc = expandFifo(&fd, &ch);
  566.             else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
  567.             rc = expandDevice(&fd, &ch);
  568.             else if (S_ISSOCK(ch.mode)) {
  569.             /* this mimicks cpio but probably isnt' right */
  570.             rc = expandFifo(&fd, &ch);
  571.             } else {
  572.             rc = CPIO_INTERNAL;
  573.             }
  574.         }
  575.  
  576.         if (!rc)
  577.             rc = setInfo(&ch);
  578.  
  579.         if (S_ISREG(ch.mode) && ch.nlink > 1) {
  580.             li->createdPath = linkNum;
  581.             li->linksLeft--;
  582.             rc = createLinks(li, failedFile);
  583.         }
  584.         }
  585.  
  586.         if (rc && !*failedFile) {
  587.         *failedFile = strdup(ch.path);
  588.  
  589.         olderr = errno;
  590.         unlink(ch.path);
  591.         errno = olderr;
  592.         }
  593.     }
  594.  
  595.     padinfd(&fd, 4);
  596.  
  597.     if (!rc && cb) {
  598.         cbInfo.file = ch.path;
  599.         cbInfo.fileSize = ch.size;
  600.         cbInfo.fileComplete = ch.size;
  601.         cbInfo.bytesProcessed = fd.pos;
  602.         cb(&cbInfo, cbData);
  603.     }
  604.  
  605.     free(ch.path);
  606.     } while (1 && !rc);
  607.  
  608.     li = links;
  609.     while (li && !rc) {
  610.     if (li->linksLeft) {
  611.         if (li->createdPath == -1)
  612.         rc = CPIO_INTERNAL;
  613.         else 
  614.         rc = createLinks(li, failedFile);
  615.     }
  616.  
  617.     freeLink(li);
  618.  
  619.     links = li;
  620.     li = li->next;
  621.     free(links);
  622.     links = li;
  623.     }
  624.  
  625.     li = links;
  626.     /* if an error got us here links will still be eating some memory */
  627.     while (li) {
  628.     freeLink(li);
  629.     links = li;
  630.     li = li->next;
  631.     free(links);
  632.     }
  633.  
  634.     return rc;
  635. }
  636.  
  637. static int writeFile(int fd, struct stat sb, struct cpioFileMapping * map, 
  638.              size_t * sizeptr, int writeData) {
  639.     struct cpioCrcPhysicalHeader hdr;
  640.     char buf[8192], symbuf[2048];
  641.     dev_t num;
  642.     int datafd;
  643.     size_t size, amount = 0;
  644.     int rc, olderrno;
  645.  
  646.     if (!(map->mapFlags & CPIO_MAP_PATH))
  647.     map->archivePath = map->fsPath;
  648.     if (map->mapFlags & CPIO_MAP_MODE)
  649.     sb.st_mode = (sb.st_mode & S_IFMT) | map->finalMode;
  650.     if (map->mapFlags & CPIO_MAP_UID)
  651.     sb.st_uid = map->finalUid;
  652.     if (map->mapFlags & CPIO_MAP_GID)
  653.     sb.st_gid = map->finalGid;
  654.  
  655.     if (!writeData || S_ISDIR(sb.st_mode)) {
  656.     sb.st_size = 0;
  657.     } else if (S_ISLNK(sb.st_mode)) {
  658.     /* While linux puts the size of a symlink in the st_size field,
  659.        I don't think that's a specified standard */
  660.  
  661.     amount = readlink(map->fsPath, symbuf, sizeof(symbuf));
  662.     if (amount <= 0) {
  663.         return CPIO_READLINK_FAILED;
  664.     }
  665.  
  666.     sb.st_size = amount;
  667.     }
  668.  
  669.     memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
  670.     SET_NUM_FIELD(hdr.inode, sb.st_ino, buf);
  671.     SET_NUM_FIELD(hdr.mode, sb.st_mode, buf);
  672.     SET_NUM_FIELD(hdr.uid, sb.st_uid, buf);
  673.     SET_NUM_FIELD(hdr.gid, sb.st_gid, buf);
  674.     SET_NUM_FIELD(hdr.nlink, sb.st_nlink, buf);
  675.     SET_NUM_FIELD(hdr.mtime, sb.st_mtime, buf);
  676.     SET_NUM_FIELD(hdr.filesize, sb.st_size, buf);
  677.  
  678.     num = major(sb.st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
  679.     num = minor(sb.st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
  680.     num = major(sb.st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
  681.     num = minor(sb.st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
  682.  
  683.     num = strlen(map->archivePath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
  684.     memcpy(hdr.checksum, "00000000", 8);
  685.  
  686.     if ((rc = safewrite(fd, &hdr, sizeof(hdr))))
  687.     return rc;
  688.     if ((rc = safewrite(fd, map->archivePath, num)))
  689.     return rc;
  690.     size = sizeof(hdr) + num;
  691.     if ((rc = padoutfd(fd, &size, 4)))
  692.     return rc;
  693.     
  694.     if (writeData && S_ISREG(sb.st_mode)) {
  695.     /* FIXME: we should use mmap here if it's available */
  696.     if ((datafd = open(map->archivePath, O_RDONLY)) < 0)
  697.         return CPIO_OPEN_FAILED;
  698.  
  699.     size += sb.st_size;
  700.  
  701.     while (sb.st_size) {
  702.         amount = read(datafd, buf, 
  703.              sb.st_size > sizeof(buf) ? sizeof(buf) : sb.st_size);
  704.         if (amount <= 0) {
  705.         olderrno = errno;
  706.         close(datafd);
  707.         errno = olderrno;
  708.         return CPIO_READ_FAILED;
  709.         }
  710.  
  711.         if ((rc = safewrite(fd, buf, amount))) {
  712.         olderrno = errno;
  713.         close(datafd);
  714.         errno = olderrno;
  715.         return rc;
  716.         }
  717.  
  718.         sb.st_size -= amount;
  719.     }
  720.  
  721.     close(datafd);
  722.     } else if (writeData && S_ISLNK(sb.st_mode)) {
  723.     if ((rc = safewrite(fd, symbuf, amount)))
  724.         return rc;
  725.     size += amount;
  726.     }
  727.  
  728.     /* this is a noop for most file types */
  729.     if ((rc = padoutfd(fd, &size, 4)))
  730.     return rc;
  731.  
  732.     *sizeptr = size;
  733.  
  734.     return 0;
  735. }
  736.  
  737. static int writeLinkedFile(int fd, struct hardLink * hlink, 
  738.                struct cpioFileMapping * mappings,
  739.                cpioCallback cb, void * cbData,
  740.                size_t * sizeptr,
  741.                char ** failedFile) {
  742.     int i, rc;
  743.     size_t size;
  744.     struct cpioCallbackInfo cbinfo;
  745.  
  746.     *sizeptr = 0;
  747.  
  748.     for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
  749.     if ((rc = writeFile(fd, hlink->sb, mappings + hlink->fileMaps[i], 
  750.                 &size, 0))) {
  751.         if (failedFile) *failedFile = 
  752.             mappings[hlink->fileMaps[i]].fsPath;
  753.         return rc;
  754.     }
  755.  
  756.     *sizeptr += size;
  757.  
  758.     if (cb) {
  759.         cbinfo.file = mappings[i].archivePath;
  760.         cb(&cbinfo, cbData);
  761.     }
  762.     }
  763.  
  764.     if ((rc = writeFile(fd, hlink->sb, 
  765.             mappings + hlink->fileMaps[hlink->linksLeft], 
  766.             &size, 1))) {
  767.     if (failedFile) 
  768.         *failedFile = mappings[hlink->fileMaps[hlink->linksLeft]].fsPath;
  769.     return rc;
  770.     }
  771.  
  772.     *sizeptr += size;
  773.  
  774.     if (cb) {
  775.     cbinfo.file = mappings[i].archivePath;
  776.     cb(&cbinfo, cbData);
  777.     }
  778.  
  779.     return 0;
  780. }
  781.  
  782. int cpioBuildArchive(int fd, struct cpioFileMapping * mappings, 
  783.              int numMappings, cpioCallback cb, void * cbData,
  784.              unsigned int * archiveSize, char ** failedFile) {
  785.     size_t size, totalsize = 0;
  786.     int rc;
  787.     int i;
  788.     struct cpioCallbackInfo cbinfo;
  789.     struct cpioCrcPhysicalHeader hdr;
  790.     struct stat sb;
  791.     struct hardLink hlinkList = { NULL };
  792.     struct hardLink * hlink, * parent;
  793.  
  794.     hlinkList.next = NULL;
  795.  
  796.     for (i = 0; i < numMappings; i++) {
  797.     if (mappings[i].mapFlags & CPIO_FOLLOW_SYMLINKS)
  798.         rc = stat(mappings[i].fsPath, &sb);
  799.     else
  800.         rc = lstat(mappings[i].fsPath, &sb);
  801.  
  802.     if (rc) {
  803.         if (failedFile) *failedFile = mappings[i].fsPath;
  804.         return CPIO_STAT_FAILED;
  805.     }
  806.  
  807.     if (!S_ISDIR(sb.st_mode) && sb.st_nlink > 1) {
  808.         hlink = hlinkList.next;
  809.         while (hlink && 
  810.            (hlink->dev != sb.st_dev || hlink->inode != sb.st_ino))
  811.         hlink = hlink->next;
  812.         if (!hlink) {
  813.         hlink = malloc(sizeof(*hlink));
  814.         hlink->next = hlinkList.next;
  815.         hlinkList.next = hlink;
  816.         hlink->sb = sb;
  817.         hlink->dev = sb.st_dev;
  818.         hlink->inode = sb.st_ino;
  819.         hlink->nlink = sb.st_nlink;
  820.         hlink->linksLeft = sb.st_nlink;
  821.         hlink->fileMaps = malloc(sizeof(*hlink->fileMaps) * 
  822.                         sb.st_nlink);
  823.         }
  824.  
  825.         hlink->fileMaps[--hlink->linksLeft] = i;
  826.  
  827.         if (!hlink->linksLeft) {
  828.         if ((rc = writeLinkedFile(fd, hlink, mappings, cb, cbData,
  829.                        &size, failedFile)))
  830.             return rc;
  831.  
  832.         totalsize += size;
  833.  
  834.         free(hlink->fileMaps);
  835.  
  836.         parent = &hlinkList;
  837.         while (parent->next != hlink) parent = parent->next;
  838.         parent->next = parent->next->next;
  839.         free(hlink);
  840.         }
  841.     } else {
  842.         if ((rc = writeFile(fd, sb, mappings + i, &size, 1))) {
  843.         if (failedFile) *failedFile = mappings[i].fsPath;
  844.         return rc;
  845.         }
  846.  
  847.         if (cb) {
  848.         cbinfo.file = mappings[i].archivePath;
  849.         cb(&cbinfo, cbData);
  850.         }
  851.  
  852.         totalsize += size;
  853.     }
  854.     }    
  855.  
  856.     hlink = hlinkList.next;
  857.     while (hlink) {
  858.     if ((rc = writeLinkedFile(fd, hlink, mappings, cb, cbData,
  859.                   &size, failedFile)))
  860.         return rc;
  861.     free(hlink->fileMaps);
  862.     parent = hlink;
  863.     hlink = hlink->next;
  864.     free(parent);
  865.     }
  866.  
  867.     memset(&hdr, '0', sizeof(hdr));
  868.     memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
  869.     memcpy(hdr.nlink, "00000001", 8);
  870.     memcpy(hdr.namesize, "0000000b", 8);
  871.     if ((rc = safewrite(fd, &hdr, sizeof(hdr))))
  872.     return rc;
  873.     if ((rc = safewrite(fd, "TRAILER!!!", 11)))
  874.     return rc;
  875.     totalsize += sizeof(hdr) + 11;
  876.  
  877.     /* GNU cpio pads to 512 bytes here, but we don't. I'm not sure if
  878.        it matters or not */
  879.     
  880.     if ((rc = padoutfd(fd, &totalsize, 4)))
  881.     return rc;
  882.  
  883.     if (archiveSize) *archiveSize = totalsize;
  884.  
  885.     return 0;
  886. }
  887.