1 /** \ingroup payload rpmio
3 * Handle cpio payloads within rpm packages.
5 * \warning FIXME: We don't translate between cpio and system mode bits! These
6 * should both be the same, but really odd things are going to happen if
17 #define CPIO_NEWC_MAGIC "070701"
18 #define CPIO_CRC_MAGIC "070702"
19 #define TRAILER "TRAILER!!!"
22 * Keeps track of set of all hard linked files in archive.
25 struct hardLink * next;
26 const char ** files; /* nlink of these, used by install */
27 int * fileMaps; /* used by build */
44 * Cpio archive header information.
45 * @todo Add support for tar (soon) and ar (eventually) archive formats.
47 struct cpioCrcPhysicalHeader {
61 char checksum[8]; /* ignored !! */
64 #define PHYS_HDR_SIZE 110 /*!< Don't depend on sizeof(struct) */
67 * File name and stat information.
70 /*@owned@*/ const char * path;
75 static void prtli(const char *msg, struct hardLink * li)
77 if (msg) fprintf(stderr, "%s", msg);
78 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);
83 * Read data from payload.
84 * @param cfd payload file handle
85 * @retval vbuf data from read
86 * @param amount no. bytes to read
87 * @return no. bytes read
89 static inline off_t saferead(FD_t cfd, /*@out@*/void * vbuf, size_t amount)
90 /*@modifies cfd, *vbuf @*/
98 nb = Fread(buf, sizeof(buf[0]), amount, cfd);
111 * Read data from payload and update number of bytes read.
112 * @param cfd payload file handle
113 * @retval buf data from read
114 * @param size no. bytes to read
115 * @return no. bytes read
117 static inline off_t ourread(FD_t cfd, /*@out@*/void * buf, size_t size)
118 /*@modifies cfd, *buf @*/
120 off_t i = saferead(cfd, buf, size);
122 fdSetCpioPos(cfd, fdGetCpioPos(cfd) + i);
127 * Align input payload handle, skipping input bytes.
128 * @param cfd payload file handle
129 * @param modulo data alignment
131 static inline void padinfd(FD_t cfd, int modulo)
137 amount = (modulo - fdGetCpioPos(cfd) % modulo) % modulo;
138 (void)ourread(cfd, buf, amount);
142 * Write data to payload.
143 * @param cfd payload file handle
144 * @param vbuf data to write
145 * @param amount no. bytes to write
146 * @return no. bytes written
148 static inline off_t safewrite(FD_t cfd, const void * vbuf, size_t amount)
152 const char * buf = vbuf;
157 nb = Fwrite(buf, sizeof(buf[0]), amount, cfd);
171 * Align output payload handle, padding with zeroes.
172 * @param cfd payload file handle
173 * @param modulo data alignment
174 * @return 0 on success, CPIOERR_WRITE_FAILED
176 static inline int padoutfd(FD_t cfd, size_t * where, int modulo)
177 /*@modifies cfd, *where @*/
179 static int buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
182 amount = (modulo - *where % modulo) % modulo;
185 if (safewrite(cfd, buf, amount) != amount)
186 return CPIOERR_WRITE_FAILED;
191 * Convert string to unsigned integer (with buffer size check).
192 * @param input string
193 * @retval address of 1st character not processed
194 * @param base numerical conversion base
195 * @param num max no. of bytes to read
196 * @return converted integer
198 static int strntoul(const char *str, /*@out@*/char **endptr, int base, int num)
199 /*@modifies *endptr @*/
204 buf = alloca(num + 1);
205 strncpy(buf, str, num);
208 ret = strtoul(buf, &end, base);
210 *endptr = ((char *)str) + (end - buf); /* XXX discards const */
212 *endptr = ((char *)str) + strlen(str);
217 #define GET_NUM_FIELD(phys, log) \
218 log = strntoul(phys, &end, 16, sizeof(phys)); \
219 if (*end) return CPIOERR_BAD_HEADER;
220 #define SET_NUM_FIELD(phys, val, space) \
221 sprintf(space, "%8.8lx", (unsigned long) (val)); \
222 memcpy(phys, space, 8);
225 * Process next cpio heasder.
226 * @param cfd payload file handle
227 * @retval hdr file name and stat info
228 * @return 0 on success
230 static int getNextHeader(FD_t cfd, struct cpioHeader * hdr)
231 /*@modifies cfd, hdr->path, hdr->sb @*/
233 struct cpioCrcPhysicalHeader physHeader;
234 struct stat * st = &hdr->sb;
239 if (ourread(cfd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE)
240 return CPIOERR_READ_FAILED;
242 if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
243 strncmp(CPIO_NEWC_MAGIC, physHeader.magic, sizeof(CPIO_NEWC_MAGIC)-1))
244 return CPIOERR_BAD_MAGIC;
246 GET_NUM_FIELD(physHeader.inode, st->st_ino);
247 GET_NUM_FIELD(physHeader.mode, st->st_mode);
248 GET_NUM_FIELD(physHeader.uid, st->st_uid);
249 GET_NUM_FIELD(physHeader.gid, st->st_gid);
250 GET_NUM_FIELD(physHeader.nlink, st->st_nlink);
251 GET_NUM_FIELD(physHeader.mtime, st->st_mtime);
252 GET_NUM_FIELD(physHeader.filesize, st->st_size);
254 GET_NUM_FIELD(physHeader.devMajor, major);
255 GET_NUM_FIELD(physHeader.devMinor, minor);
256 st->st_dev = /*@-shiftsigned@*/ makedev(major, minor) /*@=shiftsigned@*/ ;
258 GET_NUM_FIELD(physHeader.rdevMajor, major);
259 GET_NUM_FIELD(physHeader.rdevMinor, minor);
260 st->st_rdev = /*@-shiftsigned@*/ makedev(major, minor) /*@=shiftsigned@*/ ;
262 GET_NUM_FIELD(physHeader.namesize, nameSize);
264 { char * t = xmalloc(nameSize + 1);
265 if (ourread(cfd, t, nameSize) != nameSize) {
268 return CPIOERR_BAD_HEADER;
273 /* this is unecessary hdr->path[nameSize] = '\0'; */
280 int cpioFileMapCmp(const void * a, const void * b)
282 const char * afn = ((const struct cpioFileMapping *)a)->archivePath;
283 const char * bfn = ((const struct cpioFileMapping *)b)->archivePath;
285 /* Match payloads with ./ prefixes as well. */
286 if (afn[0] == '.' && afn[1] == '/') afn += 2;
287 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
289 return strcmp(afn, bfn);
292 /* This could trash files in the path! I'm not sure that's a good thing */
294 * @param path directory path
295 * @param perms directory permissions
296 * @return 0 on success
298 static int createDirectory(const char * path, mode_t perms)
299 /*@modifies fileSystem @*/
303 if (!lstat(path, &sb)) {
304 int dounlink = 0; /* XXX eliminate, dounlink==1 on all paths */
305 if (S_ISDIR(sb.st_mode)) {
307 } else if (S_ISLNK(sb.st_mode)) {
308 if (stat(path, &sb)) {
310 return CPIOERR_STAT_FAILED;
313 if (S_ISDIR(sb.st_mode))
321 if (dounlink && unlink(path)) {
322 return CPIOERR_UNLINK_FAILED;
326 if (mkdir(path, 000))
327 return CPIOERR_MKDIR_FAILED;
329 if (chmod(path, perms))
330 return CPIOERR_CHMOD_FAILED;
336 * Set owner, group, and modify/access times.
337 * @param hdr file name and stat info
338 * @return 0 on success
340 static int setInfo(struct cpioHeader * hdr)
341 /*@modifies fileSystem @*/
344 struct utimbuf stamp;
345 struct stat * st = &hdr->sb;
347 stamp.actime = st->st_mtime;
348 stamp.modtime = st->st_mtime;
350 if (!S_ISLNK(st->st_mode)) {
351 if (!getuid() && chown(hdr->path, st->st_uid, st->st_gid))
352 rc = CPIOERR_CHOWN_FAILED;
353 if (!rc && chmod(hdr->path, st->st_mode & 07777))
354 rc = CPIOERR_CHMOD_FAILED;
355 if (!rc && utime(hdr->path, &stamp))
356 rc = CPIOERR_UTIME_FAILED;
358 # if ! CHOWN_FOLLOWS_SYMLINK
359 if (!getuid() && !rc && lchown(hdr->path, st->st_uid, st->st_gid))
360 rc = CPIOERR_CHOWN_FAILED;
368 * Create directories in file path (like "mkdir -p").
369 * @param filename file path
370 * @return 0 on success
372 static int inline checkDirectory(const char * filename) /*@*/
374 /*@only@*/ static char * lastDir = NULL; /* XXX memory leak */
375 static int lastDirLength = 0;
376 static int lastDirAlloced = 0;
377 int length = strlen(filename);
382 buf = alloca(length + 1);
383 strcpy(buf, filename);
385 for (chptr = buf + length - 1; chptr > buf; chptr--) {
386 if (*chptr == '/') break;
389 if (chptr == buf) return 0; /* /filename - no directories */
391 *chptr = '\0'; /* buffer is now just directories */
393 length = strlen(buf);
394 if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
396 if (lastDirAlloced < (length + 1)) {
397 lastDirAlloced = length + 100;
398 lastDir = xrealloc(lastDir, lastDirAlloced); /* XXX memory leak */
401 strcpy(lastDir, buf);
402 lastDirLength = length;
404 for (chptr = buf + 1; *chptr; chptr++) {
407 rc = createDirectory(buf, 0755);
412 rc = createDirectory(buf, 0755);
418 * Create file from payload stream.
419 * @todo Legacy: support brokenEndian MD5 checks?
420 * @param cfd payload file handle
421 * @param hdr file name and stat info
422 * @param filemd5 file md5 sum
423 * @param cb callback function
424 * @param cbData callback private data
425 * @return 0 on success
427 static int expandRegular(FD_t cfd, const struct cpioHeader * hdr,
428 const char * filemd5, cpioCallback cb, void * cbData)
429 /*@modifies fileSystem, cfd @*/
434 const struct stat * st = &hdr->sb;
435 int left = st->st_size;
437 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
440 /* Rename the old file before attempting unlink to avoid EBUSY errors */
441 if (!lstat(hdr->path, &sb)) {
442 strcpy(buf, hdr->path);
443 strcat(buf, "-RPMDELETE");
444 if (rename(hdr->path, buf)) {
445 rpmError(RPMERR_RENAME, _("can't rename %s to %s: %s\n"),
446 hdr->path, buf, strerror(errno));
447 return CPIOERR_UNLINK_FAILED;
451 rpmError(RPMERR_UNLINK, _("can't unlink %s: %s\n"),
452 buf, strerror(errno));
454 return CPIOERR_UNLINK_FAILED;
459 ofd = Fopen(hdr->path, "w.ufdio");
460 if (ofd == NULL || Ferror(ofd))
461 return CPIOERR_OPEN_FAILED;
463 /* XXX This doesn't support brokenEndian checks. */
467 cbInfo.file = hdr->path;
468 cbInfo.fileSize = st->st_size;
471 bytesRead = ourread(cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
472 if (bytesRead <= 0) {
473 rc = CPIOERR_READ_FAILED;
477 if (Fwrite(buf, sizeof(buf[0]), bytesRead, ofd) != bytesRead) {
478 rc = CPIOERR_COPY_FAILED;
484 /* don't call this with fileSize == fileComplete */
485 if (!rc && cb && left) {
486 cbInfo.fileComplete = st->st_size - left;
487 cbInfo.bytesProcessed = fdGetCpioPos(cfd);
493 const char * md5sum = NULL;
496 fdFiniMD5(ofd, (void **)&md5sum, NULL, 1);
498 if (md5sum == NULL) {
499 rc = CPIOERR_MD5SUM_MISMATCH;
501 if (strcmp(md5sum, filemd5))
502 rc = CPIOERR_MD5SUM_MISMATCH;
503 free((void *)md5sum);
513 * Create symlink from payload stream.
514 * @param cfd payload file handle
515 * @param hdr file name and stat info
516 * @return 0 on success
518 static int expandSymlink(FD_t cfd, const struct cpioHeader * hdr)
519 /*@modifies fileSystem, cfd @*/
521 char buf[2048], buf2[2048];
523 const struct stat * st = &hdr->sb;
526 if ((st->st_size + 1)> sizeof(buf))
527 return CPIOERR_HDR_SIZE;
529 if (ourread(cfd, buf, st->st_size) != st->st_size)
530 return CPIOERR_READ_FAILED;
532 buf[st->st_size] = '\0';
534 if (!lstat(hdr->path, &sb)) {
535 if (S_ISLNK(sb.st_mode)) {
536 len = readlink(hdr->path, buf2, sizeof(buf2) - 1);
539 if (!strcmp(buf, buf2)) return 0;
543 if (unlink(hdr->path))
544 return CPIOERR_UNLINK_FAILED;
547 if (symlink(buf, hdr->path) < 0)
548 return CPIOERR_SYMLINK_FAILED;
554 * Create fifo from payload stream.
555 * @param cfd payload file handle
556 * @param hdr file name and stat info
557 * @return 0 on success
559 static int expandFifo( /*@unused@*/ FD_t cfd, const struct cpioHeader * hdr)
560 /*@modifies fileSystem @*/
564 if (!lstat(hdr->path, &sb)) {
565 if (S_ISFIFO(sb.st_mode)) return 0;
567 if (unlink(hdr->path))
568 return CPIOERR_UNLINK_FAILED;
571 if (mkfifo(hdr->path, 0))
572 return CPIOERR_MKFIFO_FAILED;
578 * Create fifo from payload stream.
579 * @param cfd payload file handle
580 * @param hdr file name and stat info
581 * @return 0 on success
583 static int expandDevice( /*@unused@*/ FD_t cfd, const struct cpioHeader * hdr)
584 /*@modifies fileSystem @*/
586 const struct stat * st = &hdr->sb;
589 if (!lstat(hdr->path, &sb)) {
590 if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) &&
591 (sb.st_rdev == st->st_rdev))
593 if (unlink(hdr->path))
594 return CPIOERR_UNLINK_FAILED;
597 if ( /*@-unrecog@*/ mknod(hdr->path, st->st_mode & (~0777), st->st_rdev) /*@=unrecog@*/ )
598 return CPIOERR_MKNOD_FAILED;
604 * Create and initialize set of hard links.
605 * @param st link stat info
606 * @param hltype type of hard link set to create
607 * @return pointer to set of hard links
609 static /*@only@*/ struct hardLink * newHardLink(const struct stat * st,
610 enum hardLinkType hltype) /*@*/
612 struct hardLink * li = xmalloc(sizeof(*li));
615 li->nlink = st->st_nlink;
616 li->dev = st->st_dev;
617 li->inode = st->st_ino;
618 li->createdPath = -1;
621 case HARDLINK_INSTALL:
622 li->linksLeft = st->st_nlink;
623 li->fileMaps = xmalloc(sizeof(li->fileMaps[0]) * st->st_nlink);
629 li->files = xcalloc(st->st_nlink, sizeof(*li->files));
633 { struct stat * myst = (struct stat *) &li->sb;
634 *myst = *st; /* structure assignment */
641 * Destroy set of hard links.
642 * @param li set of hard links
644 static void freeHardLink( /*@only@*/ struct hardLink * li)
649 for (i = 0; i < li->nlink; i++) {
650 if (li->files[i] == NULL) continue;
651 /*@-unqualifiedtrans@*/ free((void *)li->files[i]) /*@=unqualifiedtrans@*/ ;
665 * Create hard links to existing file.
666 * @param li set of hard links
667 * @retval failedFile on error, file name that failed
668 * @return 0 on success
670 static int createLinks(struct hardLink * li, /*@out@*/ const char ** failedFile)
671 /*@modifies fileSystem, *failedFile, li->files, li->linksLeft @*/
676 for (i = 0; i < li->nlink; i++) {
677 if (i == li->createdPath) continue;
678 if (li->files[i] == NULL) continue;
680 if (!lstat(li->files[i], &sb)) {
681 if (unlink(li->files[i])) {
683 *failedFile = xstrdup(li->files[i]);
684 return CPIOERR_UNLINK_FAILED;
688 if (link(li->files[li->createdPath], li->files[i])) {
690 *failedFile = xstrdup(li->files[i]);
691 return CPIOERR_LINK_FAILED;
694 /*@-unqualifiedtrans@*/ free((void *)li->files[i]) /*@=unqualifiedtrans@*/ ;
703 * Skip amount bytes on input payload stream.
704 * @param cfd payload file handle
705 * @param amount no. bytes to skip
706 * @return 0 on success
708 static int eatBytes(FD_t cfd, int amount)
715 bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
716 if (ourread(cfd, buf, bite) != bite)
717 return CPIOERR_READ_FAILED;
724 /** @todo Verify payload MD5 sum. */
725 int cpioInstallArchive(FD_t cfd, const struct cpioFileMapping * mappings,
726 int numMappings, cpioCallback cb, void * cbData,
727 const char ** failedFile)
729 struct cpioHeader ch, *hdr = &ch;
730 struct cpioFileMapping * map = NULL;
731 struct cpioFileMapping needle;
732 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
733 struct hardLink * links = NULL;
734 struct hardLink * li = NULL;
738 char * md5sum = NULL;
743 fdSetCpioPos(cfd, 0);
747 memset(hdr, 0, sizeof(*hdr));
753 free((void *)hdr->path);
756 if ((rc = getNextHeader(cfd, hdr))) {
757 #if 0 /* XXX this is the failure point for an unreadable rpm */
758 rpmError(RPMERR_BADPACKAGE, _("getNextHeader: %s\n"),
765 if (!strcmp(hdr->path, TRAILER))
769 needle.archivePath = hdr->path;
770 map = bsearch(&needle, mappings, numMappings, sizeof(needle),
774 if (mappings && !map) {
775 eatBytes(cfd, st->st_size);
778 if (map->mapFlags & CPIO_MAP_PATH) {
779 if (hdr->path) free((void *)hdr->path);
780 hdr->path = xstrdup(map->fsPath);
783 if (map->mapFlags & CPIO_MAP_MODE)
784 st->st_mode = map->finalMode;
785 if (map->mapFlags & CPIO_MAP_UID)
786 st->st_uid = map->finalUid;
787 if (map->mapFlags & CPIO_MAP_GID)
788 st->st_gid = map->finalGid;
791 /* This won't get hard linked symlinks right, but I can't seem
792 to create those anyway */
794 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
795 for (li = links; li; li = li->next) {
796 if (li->inode == st->st_ino && li->dev == st->st_dev) break;
800 li = newHardLink(st, HARDLINK_BUILD);
805 li->files[li->linksLeft++] = xstrdup(hdr->path);
808 if ((st->st_nlink > 1) && S_ISREG(st->st_mode) && !st->st_size &&
809 li->createdPath == -1) {
810 /* defer file creation */
811 } else if ((st->st_nlink > 1) && S_ISREG(st->st_mode) &&
812 (li->createdPath != -1)) {
813 createLinks(li, failedFile);
815 /* this only happens for cpio archives which contain
816 hardlinks w/ the contents of each hardlink being
817 listed (intead of the data being given just once. This
818 shouldn't happen, but I've made it happen w/ buggy
819 code, so what the heck? GNU cpio handles this well fwiw */
820 if (st->st_size) eatBytes(cfd, st->st_size);
822 rc = checkDirectory(hdr->path);
825 if (S_ISREG(st->st_mode))
826 rc = expandRegular(cfd, hdr, map->md5sum, cb, cbData);
827 else if (S_ISDIR(st->st_mode))
828 rc = createDirectory(hdr->path, 000);
829 else if (S_ISLNK(st->st_mode))
830 rc = expandSymlink(cfd, hdr);
831 else if (S_ISFIFO(st->st_mode))
832 rc = expandFifo(cfd, hdr);
833 else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
834 rc = expandDevice(cfd, hdr);
835 else if (S_ISSOCK(st->st_mode)) {
836 /* this mimicks cpio but probably isnt' right */
837 rc = expandFifo(cfd, hdr);
839 rc = CPIOERR_UNKNOWN_FILETYPE;
846 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
847 li->createdPath = --li->linksLeft;
848 rc = createLinks(li, failedFile);
852 if (rc && failedFile && *failedFile == NULL) {
855 *failedFile = xstrdup(hdr->path);
865 cbInfo.file = hdr->path;
866 cbInfo.fileSize = st->st_size;
867 cbInfo.fileComplete = st->st_size;
868 cbInfo.bytesProcessed = fdGetCpioPos(cfd);
875 free((void *)hdr->path);
879 /* Create any remaining links (if no error), and clean up. */
880 while ((li = links) != NULL) {
884 if (rc == 0 && li->linksLeft) {
885 if (li->createdPath == -1)
886 rc = CPIOERR_MISSING_HARDLINK;
888 rc = createLinks(li, failedFile);
895 fdFiniMD5(cfd, (void **)&md5sum, NULL, 1);
905 * Write next item to payload stream.
906 * @param cfd payload file handle
907 * @param st stat info for item
908 * @param map mapping name and flags for item
909 * @retval sizep address of no. bytes written
910 * @param writeData should data be written?
911 * @return 0 on success
913 static int writeFile(FD_t cfd, const struct stat * st,
914 const struct cpioFileMapping * map, /*@out@*/ size_t * sizep,
916 /*@modifies cfd, *sizep @*/
918 struct cpioCrcPhysicalHeader hdr;
919 char buf[8192], symbuf[2048];
922 size_t st_size = st->st_size; /* XXX hard links need size preserved */
923 const char * archivePath;
924 mode_t st_mode = st->st_mode;
925 uid_t st_uid = st->st_uid;
926 gid_t st_gid = st->st_gid;
927 size_t size, amount = 0;
930 archivePath = (!(map->mapFlags & CPIO_MAP_PATH))
931 ? map->fsPath : map->archivePath;
933 if (map->mapFlags & CPIO_MAP_MODE)
934 st_mode = (st_mode & S_IFMT) | map->finalMode;
935 if (map->mapFlags & CPIO_MAP_UID)
936 st_uid = map->finalUid;
937 if (map->mapFlags & CPIO_MAP_GID)
938 st_gid = map->finalGid;
940 if (!writeData || S_ISDIR(st_mode)) {
942 } else if (S_ISLNK(st_mode)) {
943 /* While linux puts the size of a symlink in the st_size field,
944 I don't think that's a specified standard */
946 amount = Readlink(map->fsPath, symbuf, sizeof(symbuf));
948 return CPIOERR_READLINK_FAILED;
954 memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
955 SET_NUM_FIELD(hdr.inode, st->st_ino, buf);
956 SET_NUM_FIELD(hdr.mode, st_mode, buf);
957 SET_NUM_FIELD(hdr.uid, st_uid, buf);
958 SET_NUM_FIELD(hdr.gid, st_gid, buf);
959 SET_NUM_FIELD(hdr.nlink, st->st_nlink, buf);
960 SET_NUM_FIELD(hdr.mtime, st->st_mtime, buf);
961 SET_NUM_FIELD(hdr.filesize, st_size, buf);
963 num = major((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
964 num = minor((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
965 num = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
966 num = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
968 num = strlen(archivePath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
969 memcpy(hdr.checksum, "00000000", 8);
971 if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
973 if ((rc = safewrite(cfd, archivePath, num)) != num)
975 size = PHYS_HDR_SIZE + num;
976 if ((rc = padoutfd(cfd, &size, 4)))
979 if (writeData && S_ISREG(st_mode)) {
986 /* XXX unbuffered mmap generates *lots* of fdio debugging */
987 datafd = Fopen(map->fsPath, "r.ufdio");
988 if (datafd == NULL || Ferror(datafd))
989 return CPIOERR_OPEN_FAILED;
993 mapped = mmap(NULL, st_size, PROT_READ, MAP_SHARED, Fileno(datafd), 0);
994 if (mapped != (void *)-1) {
1007 if (mapped != (void *)-1) {
1012 amount = Fread(b, sizeof(buf[0]),
1013 (st_size > sizeof(buf) ? sizeof(buf) : st_size),
1016 int olderrno = errno;
1019 return CPIOERR_READ_FAILED;
1023 if ((rc = safewrite(cfd, b, amount)) != amount) {
1024 int olderrno = errno;
1034 if (mapped != (void *)-1) {
1035 /*@-noeffect@*/ munmap(mapped, nmapped) /*@=noeffect@*/;
1040 } else if (writeData && S_ISLNK(st_mode)) {
1041 if ((rc = safewrite(cfd, symbuf, amount)) != amount)
1046 /* this is a noop for most file types */
1047 if ((rc = padoutfd(cfd, &size, 4)))
1057 * Write set of linked files to payload stream.
1058 * @param cfd payload file handle
1059 * @param hlink set of linked files
1060 * @param mappings mapping name and flags for linked files
1061 * @param cb callback function
1062 * @param cbData callback private data
1063 * @retval sizep address of no. bytes written
1064 * @retval failedFile on error, file name that failed
1065 * @return 0 on success
1067 static int writeLinkedFile(FD_t cfd, const struct hardLink * hlink,
1068 const struct cpioFileMapping * mappings,
1069 cpioCallback cb, void * cbData,
1070 /*@out@*/size_t * sizep,
1071 /*@out@*/const char ** failedFile)
1072 /*@modifies cfd, *sizep, *failedFile @*/
1076 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
1080 for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
1081 if ((rc = writeFile(cfd, &hlink->sb, mappings + hlink->fileMaps[i],
1084 *failedFile = xstrdup(mappings[hlink->fileMaps[i]].fsPath);
1091 cbInfo.file = mappings[i].archivePath;
1092 cb(&cbInfo, cbData);
1096 if ((rc = writeFile(cfd, &hlink->sb,
1097 mappings + hlink->fileMaps[hlink->linksLeft],
1102 *failedFile = xstrdup(mappings[hlink->fileMaps[hlink->linksLeft]].fsPath);
1111 cbInfo.file = mappings[i].archivePath;
1112 cb(&cbInfo, cbData);
1118 int cpioBuildArchive(FD_t cfd, const struct cpioFileMapping * mappings,
1119 int numMappings, cpioCallback cb, void * cbData,
1120 unsigned int * archiveSize, const char ** failedFile)
1122 size_t size, totalsize = 0;
1125 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
1126 struct cpioCrcPhysicalHeader hdr;
1127 /*@-fullinitblock@*/
1128 struct hardLink hlinkList = { NULL };
1129 /*@=fullinitblock@*/
1130 struct stat * st = (struct stat *) &hlinkList.sb;
1131 struct hardLink * hlink;
1133 hlinkList.next = NULL;
1135 for (i = 0; i < numMappings; i++) {
1136 const struct cpioFileMapping * map;
1140 if (map->mapFlags & CPIO_FOLLOW_SYMLINKS)
1141 rc = Stat(map->fsPath, st);
1143 rc = Lstat(map->fsPath, st);
1147 *failedFile = xstrdup(map->fsPath);
1148 return CPIOERR_STAT_FAILED;
1151 if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
1152 hlink = hlinkList.next;
1154 (hlink->dev != st->st_dev || hlink->inode != st->st_ino))
1155 hlink = hlink->next;
1156 if (hlink == NULL) {
1157 hlink = newHardLink(st, HARDLINK_INSTALL);
1158 hlink->next = hlinkList.next;
1159 hlinkList.next = hlink;
1162 hlink->fileMaps[--hlink->linksLeft] = i;
1164 if (hlink->linksLeft == 0) {
1165 struct hardLink * prev;
1166 if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
1167 &size, failedFile)))
1174 if (prev->next != hlink)
1176 prev->next = hlink->next;
1178 freeHardLink(hlink);
1181 } while ((prev = prev->next) != NULL);
1184 if ((rc = writeFile(cfd, st, map, &size, 1))) {
1186 *failedFile = xstrdup(mappings[i].fsPath);
1191 cbInfo.file = map->archivePath;
1192 cb(&cbInfo, cbData);
1200 while ((hlink = hlinkList.next) != NULL) {
1201 hlinkList.next = hlink->next;
1205 rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
1209 freeHardLink(hlink);
1214 memset(&hdr, '0', PHYS_HDR_SIZE);
1215 memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
1216 memcpy(hdr.nlink, "00000001", 8);
1217 memcpy(hdr.namesize, "0000000b", 8);
1218 if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
1220 if ((rc = safewrite(cfd, "TRAILER!!!", 11)) != 11)
1222 totalsize += PHYS_HDR_SIZE + 11;
1224 /* GNU cpio pads to 512 bytes here, but we don't. I'm not sure if
1225 it matters or not */
1227 if ((rc = padoutfd(cfd, &totalsize, 4)))
1230 if (archiveSize) *archiveSize = totalsize;
1235 const char * cpioStrerror(int rc)
1237 static char msg[256];
1239 int l, myerrno = errno;
1241 strcpy(msg, "cpio: ");
1244 s = msg + strlen(msg);
1245 sprintf(s, _("(error 0x%x)"), (unsigned)rc);
1248 case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
1249 case CPIOERR_BAD_HEADER: s = _("Bad/unreadable header");break;
1251 case CPIOERR_OPEN_FAILED: s = "open"; break;
1252 case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
1253 case CPIOERR_CHOWN_FAILED: s = "chown"; break;
1254 case CPIOERR_WRITE_FAILED: s = "write"; break;
1255 case CPIOERR_UTIME_FAILED: s = "utime"; break;
1256 case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
1257 case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
1258 case CPIOERR_STAT_FAILED: s = "stat"; break;
1259 case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
1260 case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
1261 case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
1262 case CPIOERR_LINK_FAILED: s = "link"; break;
1263 case CPIOERR_READLINK_FAILED: s = "readlink"; break;
1264 case CPIOERR_READ_FAILED: s = "read"; break;
1265 case CPIOERR_COPY_FAILED: s = "copy"; break;
1267 case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
1268 case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
1269 case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link"); break;
1270 case CPIOERR_MD5SUM_MISMATCH: s = _("MD5 sum mismatch"); break;
1271 case CPIOERR_INTERNAL: s = _("Internal error"); break;
1274 l = sizeof(msg) - strlen(msg) - 1;
1276 if (l > 0) strncat(msg, s, l);
1279 if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
1280 s = _(" failed - ");
1281 if (l > 0) strncat(msg, s, l);
1283 if (l > 0) strncat(msg, strerror(myerrno), l);