00001
00010 #include "system.h"
00011 #include "cpio.h"
00012 #include "rpmerr.h"
00013 #include "debug.h"
00014
00015
00016
00017 #define CPIO_NEWC_MAGIC "070701"
00018 #define CPIO_CRC_MAGIC "070702"
00019 #define TRAILER "TRAILER!!!"
00020
00024 struct hardLink {
00025 struct hardLink * next;
00026 const char ** files;
00027 int * fileMaps;
00028 dev_t dev;
00029 ino_t inode;
00030 int nlink;
00031 int linksLeft;
00032 int createdPath;
00033 const struct stat sb;
00034 };
00035
00038 enum hardLinkType {
00039 HARDLINK_INSTALL=1,
00040 HARDLINK_BUILD
00041 };
00042
00047 struct cpioCrcPhysicalHeader {
00048 char magic[6];
00049 char inode[8];
00050 char mode[8];
00051 char uid[8];
00052 char gid[8];
00053 char nlink[8];
00054 char mtime[8];
00055 char filesize[8];
00056 char devMajor[8];
00057 char devMinor[8];
00058 char rdevMajor[8];
00059 char rdevMinor[8];
00060 char namesize[8];
00061 char checksum[8];
00062 };
00063
00064 #define PHYS_HDR_SIZE 110
00069 struct cpioHeader {
00070 const char * path;
00071 struct stat sb;
00072 };
00073
00074 #if 0
00075 static void prtli(const char *msg, struct hardLink * li)
00076 {
00077 if (msg) fprintf(stderr, "%s", msg);
00078 fprintf(stderr, " next %p files %p fileMaps %p dev %x ino %x nlink %d left %d createdPath %d size %d\n", li->next, li->files, li->fileMaps, (unsigned)li->dev, (unsigned)li->inode, li->nlink, li->linksLeft, li->createdPath, li->sb.st_size);
00079 }
00080 #endif
00081
00089 static inline off_t saferead(FD_t cfd, void * vbuf, size_t amount)
00090
00091 {
00092 off_t rc = 0;
00093 char * buf = vbuf;
00094
00095 while (amount > 0) {
00096 size_t nb;
00097
00098 nb = Fread(buf, sizeof(buf[0]), amount, cfd);
00099 if (nb <= 0)
00100 return nb;
00101 rc += nb;
00102 if (rc >= amount)
00103 break;
00104 buf += nb;
00105 amount -= nb;
00106 }
00107 return rc;
00108 }
00109
00117 static inline off_t ourread(FD_t cfd, void * buf, size_t size)
00118
00119 {
00120 off_t i = saferead(cfd, buf, size);
00121 if (i > 0)
00122 fdSetCpioPos(cfd, fdGetCpioPos(cfd) + i);
00123 return i;
00124 }
00125
00131 static inline void padinfd(FD_t cfd, int modulo)
00132
00133 {
00134 int buf[10];
00135 int amount;
00136
00137 amount = (modulo - fdGetCpioPos(cfd) % modulo) % modulo;
00138 (void)ourread(cfd, buf, amount);
00139 }
00140
00148 static inline off_t safewrite(FD_t cfd, const void * vbuf, size_t amount)
00149
00150 {
00151 off_t rc = 0;
00152 const char * buf = vbuf;
00153
00154 while (amount > 0) {
00155 size_t nb;
00156
00157 nb = Fwrite(buf, sizeof(buf[0]), amount, cfd);
00158 if (nb <= 0)
00159 return nb;
00160 rc += nb;
00161 if (rc >= amount)
00162 break;
00163 buf += nb;
00164 amount -= nb;
00165 }
00166
00167 return rc;
00168 }
00169
00176 static inline int padoutfd(FD_t cfd, size_t * where, int modulo)
00177
00178 {
00179 static int buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
00180 int amount;
00181
00182 amount = (modulo - *where % modulo) % modulo;
00183 *where += amount;
00184
00185 if (safewrite(cfd, buf, amount) != amount)
00186 return CPIOERR_WRITE_FAILED;
00187 return 0;
00188 }
00189
00198 static int strntoul(const char *str, char **endptr, int base, int num)
00199
00200 {
00201 char * buf, * end;
00202 unsigned long ret;
00203
00204 buf = alloca(num + 1);
00205 strncpy(buf, str, num);
00206 buf[num] = '\0';
00207
00208 ret = strtoul(buf, &end, base);
00209 if (*end)
00210 *endptr = ((char *)str) + (end - buf);
00211 else
00212 *endptr = ((char *)str) + strlen(str);
00213
00214 return ret;
00215 }
00216
00217 #define GET_NUM_FIELD(phys, log) \
00218 log = strntoul(phys, &end, 16, sizeof(phys)); \
00219 if (*end) return CPIOERR_BAD_HEADER;
00220 #define SET_NUM_FIELD(phys, val, space) \
00221 sprintf(space, "%8.8lx", (unsigned long) (val)); \
00222 memcpy(phys, space, 8);
00223
00230 static int getNextHeader(FD_t cfd, struct cpioHeader * hdr)
00231
00232 {
00233 struct cpioCrcPhysicalHeader physHeader;
00234 struct stat * st = &hdr->sb;
00235 int nameSize;
00236 char * end;
00237 int major, minor;
00238
00239 if (ourread(cfd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE)
00240 return CPIOERR_READ_FAILED;
00241
00242 if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
00243 strncmp(CPIO_NEWC_MAGIC, physHeader.magic, sizeof(CPIO_NEWC_MAGIC)-1))
00244 return CPIOERR_BAD_MAGIC;
00245
00246 GET_NUM_FIELD(physHeader.inode, st->st_ino);
00247 GET_NUM_FIELD(physHeader.mode, st->st_mode);
00248 GET_NUM_FIELD(physHeader.uid, st->st_uid);
00249 GET_NUM_FIELD(physHeader.gid, st->st_gid);
00250 GET_NUM_FIELD(physHeader.nlink, st->st_nlink);
00251 GET_NUM_FIELD(physHeader.mtime, st->st_mtime);
00252 GET_NUM_FIELD(physHeader.filesize, st->st_size);
00253
00254 GET_NUM_FIELD(physHeader.devMajor, major);
00255 GET_NUM_FIELD(physHeader.devMinor, minor);
00256 st->st_dev = makedev(major, minor) ;
00257
00258 GET_NUM_FIELD(physHeader.rdevMajor, major);
00259 GET_NUM_FIELD(physHeader.rdevMinor, minor);
00260 st->st_rdev = makedev(major, minor) ;
00261
00262 GET_NUM_FIELD(physHeader.namesize, nameSize);
00263
00264 { char * t = xmalloc(nameSize + 1);
00265 if (ourread(cfd, t, nameSize) != nameSize) {
00266 free(t);
00267 hdr->path = NULL;
00268 return CPIOERR_BAD_HEADER;
00269 }
00270 hdr->path = t;
00271 }
00272
00273
00274
00275 padinfd(cfd, 4);
00276
00277 return 0;
00278 }
00279
00280 int cpioFileMapCmp(const void * a, const void * b)
00281 {
00282 const char * afn = ((const struct cpioFileMapping *)a)->archivePath;
00283 const char * bfn = ((const struct cpioFileMapping *)b)->archivePath;
00284
00285
00286 if (afn[0] == '.' && afn[1] == '/') afn += 2;
00287 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
00288
00289 return strcmp(afn, bfn);
00290 }
00291
00292
00298 static int createDirectory(const char * path, mode_t perms)
00299
00300 {
00301 struct stat sb;
00302
00303 if (!lstat(path, &sb)) {
00304 int dounlink = 0;
00305 if (S_ISDIR(sb.st_mode)) {
00306 return 0;
00307 } else if (S_ISLNK(sb.st_mode)) {
00308 if (stat(path, &sb)) {
00309 if (errno != ENOENT)
00310 return CPIOERR_STAT_FAILED;
00311 dounlink = 1;
00312 } else {
00313 if (S_ISDIR(sb.st_mode))
00314 return 0;
00315 dounlink = 1;
00316 }
00317 } else {
00318 dounlink = 1;
00319 }
00320
00321 if (dounlink && unlink(path)) {
00322 return CPIOERR_UNLINK_FAILED;
00323 }
00324 }
00325
00326 if (mkdir(path, 000))
00327 return CPIOERR_MKDIR_FAILED;
00328
00329 if (chmod(path, perms))
00330 return CPIOERR_CHMOD_FAILED;
00331
00332 return 0;
00333 }
00334
00340 static int setInfo(struct cpioHeader * hdr)
00341
00342 {
00343 int rc = 0;
00344 struct utimbuf stamp;
00345 struct stat * st = &hdr->sb;
00346
00347 stamp.actime = st->st_mtime;
00348 stamp.modtime = st->st_mtime;
00349
00350 if (!S_ISLNK(st->st_mode)) {
00351 if (!getuid() && chown(hdr->path, st->st_uid, st->st_gid))
00352 rc = CPIOERR_CHOWN_FAILED;
00353 if (!rc && chmod(hdr->path, st->st_mode & 07777))
00354 rc = CPIOERR_CHMOD_FAILED;
00355 if (!rc && utime(hdr->path, &stamp))
00356 rc = CPIOERR_UTIME_FAILED;
00357 } else {
00358 #if ! CHOWN_FOLLOWS_SYMLINK
00359 if (!getuid() && !rc && lchown(hdr->path, st->st_uid, st->st_gid))
00360
00361 #if defined(__linux__)
00362 rc = 0;
00363 #else
00364 rc = CPIOERR_CHOWN_FAILED;
00365 #endif
00366 #endif
00367 }
00368
00369 return rc;
00370 }
00371
00377 static int inline checkDirectory(const char * filename)
00378 {
00379 static char * lastDir = NULL;
00380 static int lastDirLength = 0;
00381 static int lastDirAlloced = 0;
00382 int length = strlen(filename);
00383 char * buf;
00384 char * chptr;
00385 int rc = 0;
00386
00387 buf = alloca(length + 1);
00388 strcpy(buf, filename);
00389
00390 for (chptr = buf + length - 1; chptr > buf; chptr--) {
00391 if (*chptr == '/') break;
00392 }
00393
00394 if (chptr == buf) return 0;
00395
00396 *chptr = '\0';
00397
00398 length = strlen(buf);
00399 if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
00400
00401 if (lastDirAlloced < (length + 1)) {
00402 lastDirAlloced = length + 100;
00403 lastDir = xrealloc(lastDir, lastDirAlloced);
00404 }
00405
00406 strcpy(lastDir, buf);
00407 lastDirLength = length;
00408
00409 for (chptr = buf + 1; *chptr; chptr++) {
00410 if (*chptr == '/') {
00411 *chptr = '\0';
00412 rc = createDirectory(buf, 0755);
00413 *chptr = '/';
00414 if (rc) return rc;
00415 }
00416 }
00417 rc = createDirectory(buf, 0755);
00418
00419 return rc;
00420 }
00421
00432 static int expandRegular(FD_t cfd, const struct cpioHeader * hdr,
00433 const char * filemd5, cpioCallback cb, void * cbData)
00434
00435 {
00436 FD_t ofd;
00437 char buf[BUFSIZ];
00438 int bytesRead;
00439 const struct stat * st = &hdr->sb;
00440 int left = st->st_size;
00441 int rc = 0;
00442 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
00443 struct stat sb;
00444
00445
00446 if (!lstat(hdr->path, &sb)) {
00447 strcpy(buf, hdr->path);
00448 strcat(buf, "-RPMDELETE");
00449 if (rename(hdr->path, buf)) {
00450 rpmError(RPMERR_RENAME, _("can't rename %s to %s: %s\n"),
00451 hdr->path, buf, strerror(errno));
00452 return CPIOERR_UNLINK_FAILED;
00453 }
00454
00455 if (unlink(buf)) {
00456 rpmError(RPMERR_UNLINK, _("can't unlink %s: %s\n"),
00457 buf, strerror(errno));
00458 #if 0
00459 return CPIOERR_UNLINK_FAILED;
00460 #endif
00461 }
00462 }
00463
00464 ofd = Fopen(hdr->path, "w.ufdio");
00465 if (ofd == NULL || Ferror(ofd))
00466 return CPIOERR_OPEN_FAILED;
00467
00468
00469 #if !defined(__sparc__)
00470 if (filemd5)
00471 fdInitMD5(ofd, 0);
00472 #endif
00473
00474 cbInfo.file = hdr->path;
00475 cbInfo.fileSize = st->st_size;
00476
00477 while (left) {
00478 bytesRead = ourread(cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
00479 if (bytesRead <= 0) {
00480 rc = CPIOERR_READ_FAILED;
00481 break;
00482 }
00483
00484 if (Fwrite(buf, sizeof(buf[0]), bytesRead, ofd) != bytesRead) {
00485 rc = CPIOERR_COPY_FAILED;
00486 break;
00487 }
00488
00489 left -= bytesRead;
00490
00491
00492 if (!rc && cb && left) {
00493 cbInfo.fileComplete = st->st_size - left;
00494 cbInfo.bytesProcessed = fdGetCpioPos(cfd);
00495 cb(&cbInfo, cbData);
00496 }
00497 }
00498
00499 #if !defined(__sparc__)
00500 if (filemd5) {
00501 const char * md5sum = NULL;
00502
00503 Fflush(ofd);
00504 fdFiniMD5(ofd, (void **)&md5sum, NULL, 1);
00505
00506 if (md5sum == NULL) {
00507 rc = CPIOERR_MD5SUM_MISMATCH;
00508 } else {
00509 if (strcmp(md5sum, filemd5))
00510 rc = CPIOERR_MD5SUM_MISMATCH;
00511 free((void *)md5sum);
00512 }
00513 }
00514 #endif
00515
00516 Fclose(ofd);
00517
00518 return rc;
00519 }
00520
00527 static int expandSymlink(FD_t cfd, const struct cpioHeader * hdr)
00528
00529 {
00530 char buf[2048], buf2[2048];
00531 struct stat sb;
00532 const struct stat * st = &hdr->sb;
00533 int len;
00534
00535 if ((st->st_size + 1)> sizeof(buf))
00536 return CPIOERR_HDR_SIZE;
00537
00538 if (ourread(cfd, buf, st->st_size) != st->st_size)
00539 return CPIOERR_READ_FAILED;
00540
00541 buf[st->st_size] = '\0';
00542
00543 if (!lstat(hdr->path, &sb)) {
00544 if (S_ISLNK(sb.st_mode)) {
00545 len = readlink(hdr->path, buf2, sizeof(buf2) - 1);
00546 if (len > 0) {
00547 buf2[len] = '\0';
00548 if (!strcmp(buf, buf2)) return 0;
00549 }
00550 }
00551
00552 if (unlink(hdr->path))
00553 return CPIOERR_UNLINK_FAILED;
00554 }
00555
00556 if (symlink(buf, hdr->path) < 0)
00557 return CPIOERR_SYMLINK_FAILED;
00558
00559 return 0;
00560 }
00561
00568 static int expandFifo( FD_t cfd, const struct cpioHeader * hdr)
00569
00570 {
00571 struct stat sb;
00572
00573 if (!lstat(hdr->path, &sb)) {
00574 if (S_ISFIFO(sb.st_mode)) return 0;
00575
00576 if (unlink(hdr->path))
00577 return CPIOERR_UNLINK_FAILED;
00578 }
00579
00580 if (mkfifo(hdr->path, 0))
00581 return CPIOERR_MKFIFO_FAILED;
00582
00583 return 0;
00584 }
00585
00592 static int expandDevice( FD_t cfd, const struct cpioHeader * hdr)
00593
00594 {
00595 const struct stat * st = &hdr->sb;
00596 struct stat sb;
00597
00598 if (!lstat(hdr->path, &sb)) {
00599 if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) &&
00600 (sb.st_rdev == st->st_rdev))
00601 return 0;
00602 if (unlink(hdr->path))
00603 return CPIOERR_UNLINK_FAILED;
00604 }
00605
00606 if ( mknod(hdr->path, st->st_mode & (~0777), st->st_rdev) )
00607 return CPIOERR_MKNOD_FAILED;
00608
00609 return 0;
00610 }
00611
00618 static struct hardLink * newHardLink(const struct stat * st,
00619 enum hardLinkType hltype)
00620 {
00621 struct hardLink * li = xmalloc(sizeof(*li));
00622
00623 li->next = NULL;
00624 li->nlink = st->st_nlink;
00625 li->dev = st->st_dev;
00626 li->inode = st->st_ino;
00627 li->createdPath = -1;
00628
00629 switch (hltype) {
00630 case HARDLINK_INSTALL:
00631 li->linksLeft = st->st_nlink;
00632 li->fileMaps = xmalloc(sizeof(li->fileMaps[0]) * st->st_nlink);
00633 li->files = NULL;
00634 break;
00635 case HARDLINK_BUILD:
00636 li->linksLeft = 0;
00637 li->fileMaps = NULL;
00638 li->files = xcalloc(st->st_nlink, sizeof(*li->files));
00639 break;
00640 }
00641
00642 { struct stat * myst = (struct stat *) &li->sb;
00643 *myst = *st;
00644 }
00645
00646 return li;
00647 }
00648
00653 static void freeHardLink( struct hardLink * li)
00654 {
00655
00656 if (li->files) {
00657 int i;
00658 for (i = 0; i < li->nlink; i++) {
00659 if (li->files[i] == NULL) continue;
00660 free((void *)li->files[i]) ;
00661 li->files[i] = NULL;
00662 }
00663 free(li->files);
00664 li->files = NULL;
00665 }
00666 if (li->fileMaps) {
00667 free(li->fileMaps);
00668 li->fileMaps = NULL;
00669 }
00670 free(li);
00671 }
00672
00679 static int createLinks(struct hardLink * li, const char ** failedFile)
00680
00681 {
00682 int i;
00683 struct stat sb;
00684
00685 for (i = 0; i < li->nlink; i++) {
00686 if (i == li->createdPath) continue;
00687 if (li->files[i] == NULL) continue;
00688
00689 if (!lstat(li->files[i], &sb)) {
00690 if (unlink(li->files[i])) {
00691 if (failedFile)
00692 *failedFile = xstrdup(li->files[i]);
00693 return CPIOERR_UNLINK_FAILED;
00694 }
00695 }
00696
00697 if (link(li->files[li->createdPath], li->files[i])) {
00698 if (failedFile)
00699 *failedFile = xstrdup(li->files[i]);
00700 return CPIOERR_LINK_FAILED;
00701 }
00702
00703 free((void *)li->files[i]) ;
00704 li->files[i] = NULL;
00705 li->linksLeft--;
00706 }
00707
00708 return 0;
00709 }
00710
00717 static int eatBytes(FD_t cfd, int amount)
00718
00719 {
00720 char buf[4096];
00721 int bite;
00722
00723 while (amount) {
00724 bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
00725 if (ourread(cfd, buf, bite) != bite)
00726 return CPIOERR_READ_FAILED;
00727 amount -= bite;
00728 }
00729
00730 return 0;
00731 }
00732
00734 int cpioInstallArchive(FD_t cfd, const struct cpioFileMapping * mappings,
00735 int numMappings, cpioCallback cb, void * cbData,
00736 const char ** failedFile)
00737 {
00738 struct cpioHeader ch, *hdr = &ch;
00739 struct cpioFileMapping * map = NULL;
00740 struct cpioFileMapping needle;
00741 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
00742 struct hardLink * links = NULL;
00743 struct hardLink * li = NULL;
00744 int rc = 0;
00745
00746 #ifdef NOTYET
00747 char * md5sum = NULL;
00748
00749 fdInitMD5(cfd, 0);
00750 #endif
00751
00752 fdSetCpioPos(cfd, 0);
00753 if (failedFile)
00754 *failedFile = NULL;
00755
00756 memset(hdr, 0, sizeof(*hdr));
00757 hdr->path = NULL;
00758 do {
00759 struct stat * st;
00760
00761 if (hdr->path) {
00762 free((void *)hdr->path);
00763 hdr->path = NULL;
00764 }
00765 if ((rc = getNextHeader(cfd, hdr))) {
00766 #if 0
00767 rpmError(RPMERR_BADPACKAGE, _("getNextHeader: %s\n"),
00768 cpioStrerror(rc));
00769 #endif
00770 return rc;
00771 }
00772 st = &hdr->sb;
00773
00774 if (!strcmp(hdr->path, TRAILER))
00775 break;
00776
00777 if (mappings) {
00778 needle.archivePath = hdr->path;
00779 map = bsearch(&needle, mappings, numMappings, sizeof(needle),
00780 cpioFileMapCmp);
00781 }
00782
00783 if (mappings && !map) {
00784 eatBytes(cfd, st->st_size);
00785 } else {
00786 if (map) {
00787 if (map->mapFlags & CPIO_MAP_PATH) {
00788 if (hdr->path) free((void *)hdr->path);
00789 hdr->path = xstrdup(map->fsPath);
00790 }
00791
00792 if (map->mapFlags & CPIO_MAP_MODE)
00793 st->st_mode = map->finalMode;
00794 if (map->mapFlags & CPIO_MAP_UID)
00795 st->st_uid = map->finalUid;
00796 if (map->mapFlags & CPIO_MAP_GID)
00797 st->st_gid = map->finalGid;
00798 }
00799
00800
00801
00802
00803 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
00804 for (li = links; li; li = li->next) {
00805 if (li->inode == st->st_ino && li->dev == st->st_dev) break;
00806 }
00807
00808 if (li == NULL) {
00809 li = newHardLink(st, HARDLINK_BUILD);
00810 li->next = links;
00811 links = li;
00812 }
00813
00814 li->files[li->linksLeft++] = xstrdup(hdr->path);
00815 }
00816
00817 if ((st->st_nlink > 1) && S_ISREG(st->st_mode) && !st->st_size &&
00818 li->createdPath == -1) {
00819
00820 } else if ((st->st_nlink > 1) && S_ISREG(st->st_mode) &&
00821 (li->createdPath != -1)) {
00822 createLinks(li, failedFile);
00823
00824
00825
00826
00827
00828
00829 if (st->st_size) eatBytes(cfd, st->st_size);
00830 } else {
00831 rc = checkDirectory(hdr->path);
00832
00833 if (!rc) {
00834 if (S_ISREG(st->st_mode))
00835 rc = expandRegular(cfd, hdr, map->md5sum, cb, cbData);
00836 else if (S_ISDIR(st->st_mode))
00837 rc = createDirectory(hdr->path, 000);
00838 else if (S_ISLNK(st->st_mode))
00839 rc = expandSymlink(cfd, hdr);
00840 else if (S_ISFIFO(st->st_mode))
00841 rc = expandFifo(cfd, hdr);
00842 else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00843 rc = expandDevice(cfd, hdr);
00844 else if (S_ISSOCK(st->st_mode)) {
00845
00846 rc = expandFifo(cfd, hdr);
00847 } else {
00848 rc = CPIOERR_UNKNOWN_FILETYPE;
00849 }
00850 }
00851
00852 if (!rc)
00853 rc = setInfo(hdr);
00854
00855 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
00856 li->createdPath = --li->linksLeft;
00857 rc = createLinks(li, failedFile);
00858 }
00859 }
00860
00861 if (rc && failedFile && *failedFile == NULL) {
00862 int olderrno;
00863
00864 *failedFile = xstrdup(hdr->path);
00865 olderrno = errno;
00866 unlink(hdr->path);
00867 errno = olderrno;
00868 }
00869 }
00870
00871 padinfd(cfd, 4);
00872
00873 if (!rc && cb) {
00874 cbInfo.file = hdr->path;
00875 cbInfo.fileSize = st->st_size;
00876 cbInfo.fileComplete = st->st_size;
00877 cbInfo.bytesProcessed = fdGetCpioPos(cfd);
00878 cb(&cbInfo, cbData);
00879 }
00880
00881 } while (rc == 0);
00882
00883 if (hdr->path) {
00884 free((void *)hdr->path);
00885 hdr->path = NULL;
00886 }
00887
00888
00889 while ((li = links) != NULL) {
00890 links = li->next;
00891 li->next = NULL;
00892
00893 if (rc == 0 && li->linksLeft) {
00894 if (li->createdPath == -1)
00895 rc = CPIOERR_MISSING_HARDLINK;
00896 else
00897 rc = createLinks(li, failedFile);
00898 }
00899
00900 freeHardLink(li);
00901 }
00902
00903 #ifdef NOTYET
00904 fdFiniMD5(cfd, (void **)&md5sum, NULL, 1);
00905
00906 if (md5sum)
00907 free(md5sum);
00908 #endif
00909
00910 return rc;
00911 }
00912
00922 static int writeFile(FD_t cfd, const struct stat * st,
00923 const struct cpioFileMapping * map, size_t * sizep,
00924 int writeData)
00925
00926 {
00927 struct cpioCrcPhysicalHeader hdr;
00928 char buf[8192], symbuf[2048];
00929 dev_t num;
00930 FD_t datafd;
00931 size_t st_size = st->st_size;
00932 const char * archivePath;
00933 mode_t st_mode = st->st_mode;
00934 uid_t st_uid = st->st_uid;
00935 gid_t st_gid = st->st_gid;
00936 size_t size, amount = 0;
00937 int rc;
00938
00939 archivePath = (!(map->mapFlags & CPIO_MAP_PATH))
00940 ? map->fsPath : map->archivePath;
00941
00942 if (map->mapFlags & CPIO_MAP_MODE)
00943 st_mode = (st_mode & S_IFMT) | map->finalMode;
00944 if (map->mapFlags & CPIO_MAP_UID)
00945 st_uid = map->finalUid;
00946 if (map->mapFlags & CPIO_MAP_GID)
00947 st_gid = map->finalGid;
00948
00949 if (!writeData || S_ISDIR(st_mode)) {
00950 st_size = 0;
00951 } else if (S_ISLNK(st_mode)) {
00952
00953
00954
00955 amount = Readlink(map->fsPath, symbuf, sizeof(symbuf));
00956 if (amount <= 0) {
00957 return CPIOERR_READLINK_FAILED;
00958 }
00959
00960 st_size = amount;
00961 }
00962
00963 memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
00964 SET_NUM_FIELD(hdr.inode, st->st_ino, buf);
00965 SET_NUM_FIELD(hdr.mode, st_mode, buf);
00966 SET_NUM_FIELD(hdr.uid, st_uid, buf);
00967 SET_NUM_FIELD(hdr.gid, st_gid, buf);
00968 SET_NUM_FIELD(hdr.nlink, st->st_nlink, buf);
00969 SET_NUM_FIELD(hdr.mtime, st->st_mtime, buf);
00970 SET_NUM_FIELD(hdr.filesize, st_size, buf);
00971
00972 num = major((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
00973 num = minor((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
00974 num = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
00975 num = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
00976
00977 num = strlen(archivePath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
00978 memcpy(hdr.checksum, "00000000", 8);
00979
00980 if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
00981 return rc;
00982 if ((rc = safewrite(cfd, archivePath, num)) != num)
00983 return rc;
00984 size = PHYS_HDR_SIZE + num;
00985 if ((rc = padoutfd(cfd, &size, 4)))
00986 return rc;
00987
00988 if (writeData && S_ISREG(st_mode)) {
00989 char *b;
00990 #if HAVE_MMAP
00991 void *mapped;
00992 size_t nmapped;
00993 #endif
00994
00995
00996 datafd = Fopen(map->fsPath, "r.ufdio");
00997 if (datafd == NULL || Ferror(datafd))
00998 return CPIOERR_OPEN_FAILED;
00999
01000 #if HAVE_MMAP
01001 nmapped = 0;
01002 mapped = mmap(NULL, st_size, PROT_READ, MAP_SHARED, Fileno(datafd), 0);
01003 if (mapped != (void *)-1) {
01004 b = (char *)mapped;
01005 nmapped = st_size;
01006 } else
01007 #endif
01008 {
01009 b = buf;
01010 }
01011
01012 size += st_size;
01013
01014 while (st_size) {
01015 #if HAVE_MMAP
01016 if (mapped != (void *)-1) {
01017 amount = nmapped;
01018 } else
01019 #endif
01020 {
01021 amount = Fread(b, sizeof(buf[0]),
01022 (st_size > sizeof(buf) ? sizeof(buf) : st_size),
01023 datafd);
01024 if (amount <= 0) {
01025 int olderrno = errno;
01026 Fclose(datafd);
01027 errno = olderrno;
01028 return CPIOERR_READ_FAILED;
01029 }
01030 }
01031
01032 if ((rc = safewrite(cfd, b, amount)) != amount) {
01033 int olderrno = errno;
01034 Fclose(datafd);
01035 errno = olderrno;
01036 return rc;
01037 }
01038
01039 st_size -= amount;
01040 }
01041
01042 #if HAVE_MMAP
01043 if (mapped != (void *)-1) {
01044 munmap(mapped, nmapped) ;
01045 }
01046 #endif
01047
01048 Fclose(datafd);
01049 } else if (writeData && S_ISLNK(st_mode)) {
01050 if ((rc = safewrite(cfd, symbuf, amount)) != amount)
01051 return rc;
01052 size += amount;
01053 }
01054
01055
01056 if ((rc = padoutfd(cfd, &size, 4)))
01057 return rc;
01058
01059 if (sizep)
01060 *sizep = size;
01061
01062 return 0;
01063 }
01064
01076 static int writeLinkedFile(FD_t cfd, const struct hardLink * hlink,
01077 const struct cpioFileMapping * mappings,
01078 cpioCallback cb, void * cbData,
01079 size_t * sizep,
01080 const char ** failedFile)
01081
01082 {
01083 int i, rc;
01084 size_t size, total;
01085 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
01086
01087 total = 0;
01088
01089 for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
01090 if ((rc = writeFile(cfd, &hlink->sb, mappings + hlink->fileMaps[i],
01091 &size, 0))) {
01092 if (failedFile)
01093 *failedFile = xstrdup(mappings[hlink->fileMaps[i]].fsPath);
01094 return rc;
01095 }
01096
01097 total += size;
01098
01099 if (cb) {
01100 cbInfo.file = mappings[i].archivePath;
01101 cb(&cbInfo, cbData);
01102 }
01103 }
01104
01105 if ((rc = writeFile(cfd, &hlink->sb,
01106 mappings + hlink->fileMaps[hlink->linksLeft],
01107 &size, 1))) {
01108 if (sizep)
01109 *sizep = total;
01110 if (failedFile)
01111 *failedFile = xstrdup(mappings[hlink->fileMaps[hlink->linksLeft]].fsPath);
01112 return rc;
01113 }
01114 total += size;
01115
01116 if (sizep)
01117 *sizep = total;
01118
01119 if (cb) {
01120 cbInfo.file = mappings[i].archivePath;
01121 cb(&cbInfo, cbData);
01122 }
01123
01124 return 0;
01125 }
01126
01127 int cpioBuildArchive(FD_t cfd, const struct cpioFileMapping * mappings,
01128 int numMappings, cpioCallback cb, void * cbData,
01129 unsigned int * archiveSize, const char ** failedFile)
01130 {
01131 size_t size, totalsize = 0;
01132 int rc;
01133 int i;
01134 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
01135 struct cpioCrcPhysicalHeader hdr;
01136
01137 struct hardLink hlinkList = { NULL };
01138
01139 struct stat * st = (struct stat *) &hlinkList.sb;
01140 struct hardLink * hlink;
01141
01142 hlinkList.next = NULL;
01143
01144 for (i = 0; i < numMappings; i++) {
01145 const struct cpioFileMapping * map;
01146
01147 map = mappings + i;
01148
01149 if (map->mapFlags & CPIO_FOLLOW_SYMLINKS)
01150 rc = Stat(map->fsPath, st);
01151 else
01152 rc = Lstat(map->fsPath, st);
01153
01154 if (rc) {
01155 if (failedFile)
01156 *failedFile = xstrdup(map->fsPath);
01157 return CPIOERR_STAT_FAILED;
01158 }
01159
01160 if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
01161 hlink = hlinkList.next;
01162 while (hlink &&
01163 (hlink->dev != st->st_dev || hlink->inode != st->st_ino))
01164 hlink = hlink->next;
01165 if (hlink == NULL) {
01166 hlink = newHardLink(st, HARDLINK_INSTALL);
01167 hlink->next = hlinkList.next;
01168 hlinkList.next = hlink;
01169 }
01170
01171 hlink->fileMaps[--hlink->linksLeft] = i;
01172
01173 if (hlink->linksLeft == 0) {
01174 struct hardLink * prev;
01175 if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
01176 &size, failedFile)))
01177 return rc;
01178
01179 totalsize += size;
01180
01181 prev = &hlinkList;
01182 do {
01183 if (prev->next != hlink)
01184 continue;
01185 prev->next = hlink->next;
01186 hlink->next = NULL;
01187 freeHardLink(hlink);
01188 hlink = NULL;
01189 break;
01190 } while ((prev = prev->next) != NULL);
01191 }
01192 } else {
01193 if ((rc = writeFile(cfd, st, map, &size, 1))) {
01194 if (failedFile)
01195 *failedFile = xstrdup(mappings[i].fsPath);
01196 return rc;
01197 }
01198
01199 if (cb) {
01200 cbInfo.file = map->archivePath;
01201 cb(&cbInfo, cbData);
01202 }
01203
01204 totalsize += size;
01205 }
01206 }
01207
01208 rc = 0;
01209 while ((hlink = hlinkList.next) != NULL) {
01210 hlinkList.next = hlink->next;
01211 hlink->next = NULL;
01212
01213 if (rc == 0) {
01214 rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
01215 &size, failedFile);
01216 totalsize += size;
01217 }
01218 freeHardLink(hlink);
01219 }
01220 if (rc)
01221 return rc;
01222
01223 memset(&hdr, '0', PHYS_HDR_SIZE);
01224 memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
01225 memcpy(hdr.nlink, "00000001", 8);
01226 memcpy(hdr.namesize, "0000000b", 8);
01227 if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
01228 return rc;
01229 if ((rc = safewrite(cfd, "TRAILER!!!", 11)) != 11)
01230 return rc;
01231 totalsize += PHYS_HDR_SIZE + 11;
01232
01233
01234
01235
01236 if ((rc = padoutfd(cfd, &totalsize, 4)))
01237 return rc;
01238
01239 if (archiveSize) *archiveSize = totalsize;
01240
01241 return 0;
01242 }
01243
01244 const char * cpioStrerror(int rc)
01245 {
01246 static char msg[256];
01247 char *s;
01248 int l, myerrno = errno;
01249
01250 strcpy(msg, "cpio: ");
01251 switch (rc) {
01252 default:
01253 s = msg + strlen(msg);
01254 sprintf(s, _("(error 0x%x)"), (unsigned)rc);
01255 s = NULL;
01256 break;
01257 case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
01258 case CPIOERR_BAD_HEADER: s = _("Bad/unreadable header");break;
01259
01260 case CPIOERR_OPEN_FAILED: s = "open"; break;
01261 case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
01262 case CPIOERR_CHOWN_FAILED: s = "chown"; break;
01263 case CPIOERR_WRITE_FAILED: s = "write"; break;
01264 case CPIOERR_UTIME_FAILED: s = "utime"; break;
01265 case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
01266 case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
01267 case CPIOERR_STAT_FAILED: s = "stat"; break;
01268 case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
01269 case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
01270 case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
01271 case CPIOERR_LINK_FAILED: s = "link"; break;
01272 case CPIOERR_READLINK_FAILED: s = "readlink"; break;
01273 case CPIOERR_READ_FAILED: s = "read"; break;
01274 case CPIOERR_COPY_FAILED: s = "copy"; break;
01275
01276 case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
01277 case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
01278 case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link"); break;
01279 case CPIOERR_MD5SUM_MISMATCH: s = _("MD5 sum mismatch"); break;
01280 case CPIOERR_INTERNAL: s = _("Internal error"); break;
01281 }
01282
01283 l = sizeof(msg) - strlen(msg) - 1;
01284 if (s != NULL) {
01285 if (l > 0) strncat(msg, s, l);
01286 l -= strlen(s);
01287 }
01288 if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
01289 s = _(" failed - ");
01290 if (l > 0) strncat(msg, s, l);
01291 l -= strlen(s);
01292 if (l > 0) strncat(msg, strerror(myerrno), l);
01293 }
01294 return msg;
01295 }