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),
775 if (mappings && !map)
777 if (mappings && !map && (st->st_nlink == 1 || !S_ISREG(st->st_mode)
779 } else if ((st->st_nlink > 1) && S_ISREG(st->st_mode) &&
780 (li->createdPath != -1))
783 eatBytes(cfd, st->st_size);
786 if (map->mapFlags & CPIO_MAP_PATH) {
787 if (hdr->path) free((void *)hdr->path);
788 hdr->path = xstrdup(map->fsPath);
791 if (map->mapFlags & CPIO_MAP_MODE)
792 st->st_mode = map->finalMode;
793 if (map->mapFlags & CPIO_MAP_UID)
794 st->st_uid = map->finalUid;
795 if (map->mapFlags & CPIO_MAP_GID)
796 st->st_gid = map->finalGid;
799 /* This won't get hard linked symlinks right, but I can't seem
800 to create those anyway */
802 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
803 for (li = links; li; li = li->next) {
804 if (li->inode == st->st_ino && li->dev == st->st_dev) break;
808 li = newHardLink(st, HARDLINK_BUILD);
813 li->files[li->linksLeft++] = xstrdup(hdr->path);
816 if ((st->st_nlink > 1) && S_ISREG(st->st_mode) && !st->st_size &&
817 li->createdPath == -1) {
818 /* defer file creation */
819 } else if ((st->st_nlink > 1) && S_ISREG(st->st_mode) &&
820 (li->createdPath != -1)) {
821 createLinks(li, failedFile);
823 /* this only happens for cpio archives which contain
824 hardlinks w/ the contents of each hardlink being
825 listed (intead of the data being given just once. This
826 shouldn't happen, but I've made it happen w/ buggy
827 code, so what the heck? GNU cpio handles this well fwiw */
828 if (st->st_size) eatBytes(cfd, st->st_size);
830 rc = checkDirectory(hdr->path);
833 if (S_ISREG(st->st_mode))
834 rc = expandRegular(cfd, hdr, map->md5sum, cb, cbData);
835 else if (S_ISDIR(st->st_mode))
836 rc = createDirectory(hdr->path, 000);
837 else if (S_ISLNK(st->st_mode))
838 rc = expandSymlink(cfd, hdr);
839 else if (S_ISFIFO(st->st_mode))
840 rc = expandFifo(cfd, hdr);
841 else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
842 rc = expandDevice(cfd, hdr);
843 else if (S_ISSOCK(st->st_mode)) {
844 /* this mimicks cpio but probably isnt' right */
845 rc = expandFifo(cfd, hdr);
847 rc = CPIOERR_UNKNOWN_FILETYPE;
854 if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
855 li->createdPath = --li->linksLeft;
856 rc = createLinks(li, failedFile);
860 if (rc && failedFile && *failedFile == NULL) {
863 *failedFile = xstrdup(hdr->path);
873 cbInfo.file = hdr->path;
874 cbInfo.fileSize = st->st_size;
875 cbInfo.fileComplete = st->st_size;
876 cbInfo.bytesProcessed = fdGetCpioPos(cfd);
883 free((void *)hdr->path);
887 /* Create any remaining links (if no error), and clean up. */
888 while ((li = links) != NULL) {
892 if (rc == 0 && li->linksLeft) {
893 if (li->createdPath == -1)
894 rc = CPIOERR_MISSING_HARDLINK;
896 rc = createLinks(li, failedFile);
903 fdFiniMD5(cfd, (void **)&md5sum, NULL, 1);
913 * Write next item to payload stream.
914 * @param cfd payload file handle
915 * @param st stat info for item
916 * @param map mapping name and flags for item
917 * @retval sizep address of no. bytes written
918 * @param writeData should data be written?
919 * @return 0 on success
921 static int writeFile(FD_t cfd, const struct stat * st,
922 const struct cpioFileMapping * map, /*@out@*/ size_t * sizep,
924 /*@modifies cfd, *sizep @*/
926 struct cpioCrcPhysicalHeader hdr;
927 char buf[8192], symbuf[2048];
930 size_t st_size = st->st_size; /* XXX hard links need size preserved */
931 const char * archivePath;
932 mode_t st_mode = st->st_mode;
933 uid_t st_uid = st->st_uid;
934 gid_t st_gid = st->st_gid;
935 size_t size, amount = 0;
938 archivePath = (!(map->mapFlags & CPIO_MAP_PATH))
939 ? map->fsPath : map->archivePath;
941 if (map->mapFlags & CPIO_MAP_MODE)
942 st_mode = (st_mode & S_IFMT) | map->finalMode;
943 if (map->mapFlags & CPIO_MAP_UID)
944 st_uid = map->finalUid;
945 if (map->mapFlags & CPIO_MAP_GID)
946 st_gid = map->finalGid;
948 if (!writeData || S_ISDIR(st_mode)) {
950 } else if (S_ISLNK(st_mode)) {
951 /* While linux puts the size of a symlink in the st_size field,
952 I don't think that's a specified standard */
954 amount = Readlink(map->fsPath, symbuf, sizeof(symbuf));
956 return CPIOERR_READLINK_FAILED;
962 memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
963 SET_NUM_FIELD(hdr.inode, st->st_ino, buf);
964 SET_NUM_FIELD(hdr.mode, st_mode, buf);
965 SET_NUM_FIELD(hdr.uid, st_uid, buf);
966 SET_NUM_FIELD(hdr.gid, st_gid, buf);
967 SET_NUM_FIELD(hdr.nlink, st->st_nlink, buf);
968 SET_NUM_FIELD(hdr.mtime, st->st_mtime, buf);
969 SET_NUM_FIELD(hdr.filesize, st_size, buf);
971 num = major((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
972 num = minor((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
973 num = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
974 num = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
976 num = strlen(archivePath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
977 memcpy(hdr.checksum, "00000000", 8);
979 if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
981 if ((rc = safewrite(cfd, archivePath, num)) != num)
983 size = PHYS_HDR_SIZE + num;
984 if ((rc = padoutfd(cfd, &size, 4)))
987 if (writeData && S_ISREG(st_mode)) {
994 /* XXX unbuffered mmap generates *lots* of fdio debugging */
995 datafd = Fopen(map->fsPath, "r.ufdio");
996 if (datafd == NULL || Ferror(datafd))
997 return CPIOERR_OPEN_FAILED;
1001 mapped = mmap(NULL, st_size, PROT_READ, MAP_SHARED, Fileno(datafd), 0);
1002 if (mapped != (void *)-1) {
1015 if (mapped != (void *)-1) {
1020 amount = Fread(b, sizeof(buf[0]),
1021 (st_size > sizeof(buf) ? sizeof(buf) : st_size),
1024 int olderrno = errno;
1027 return CPIOERR_READ_FAILED;
1031 if ((rc = safewrite(cfd, b, amount)) != amount) {
1032 int olderrno = errno;
1042 if (mapped != (void *)-1) {
1043 /*@-noeffect@*/ munmap(mapped, nmapped) /*@=noeffect@*/;
1048 } else if (writeData && S_ISLNK(st_mode)) {
1049 if ((rc = safewrite(cfd, symbuf, amount)) != amount)
1054 /* this is a noop for most file types */
1055 if ((rc = padoutfd(cfd, &size, 4)))
1065 * Write set of linked files to payload stream.
1066 * @param cfd payload file handle
1067 * @param hlink set of linked files
1068 * @param mappings mapping name and flags for linked files
1069 * @param cb callback function
1070 * @param cbData callback private data
1071 * @retval sizep address of no. bytes written
1072 * @retval failedFile on error, file name that failed
1073 * @return 0 on success
1075 static int writeLinkedFile(FD_t cfd, const struct hardLink * hlink,
1076 const struct cpioFileMapping * mappings,
1077 cpioCallback cb, void * cbData,
1078 /*@out@*/size_t * sizep,
1079 /*@out@*/const char ** failedFile)
1080 /*@modifies cfd, *sizep, *failedFile @*/
1084 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
1088 for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
1089 if ((rc = writeFile(cfd, &hlink->sb, mappings + hlink->fileMaps[i],
1092 *failedFile = xstrdup(mappings[hlink->fileMaps[i]].fsPath);
1099 cbInfo.file = mappings[i].archivePath;
1100 cb(&cbInfo, cbData);
1104 if ((rc = writeFile(cfd, &hlink->sb,
1105 mappings + hlink->fileMaps[hlink->linksLeft],
1110 *failedFile = xstrdup(mappings[hlink->fileMaps[hlink->linksLeft]].fsPath);
1119 cbInfo.file = mappings[i].archivePath;
1120 cb(&cbInfo, cbData);
1126 int cpioBuildArchive(FD_t cfd, const struct cpioFileMapping * mappings,
1127 int numMappings, cpioCallback cb, void * cbData,
1128 unsigned int * archiveSize, const char ** failedFile)
1130 size_t size, totalsize = 0;
1133 struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
1134 struct cpioCrcPhysicalHeader hdr;
1135 /*@-fullinitblock@*/
1136 struct hardLink hlinkList = { NULL };
1137 /*@=fullinitblock@*/
1138 struct stat * st = (struct stat *) &hlinkList.sb;
1139 struct hardLink * hlink;
1141 hlinkList.next = NULL;
1143 for (i = 0; i < numMappings; i++) {
1144 const struct cpioFileMapping * map;
1148 if (map->mapFlags & CPIO_FOLLOW_SYMLINKS)
1149 rc = Stat(map->fsPath, st);
1151 rc = Lstat(map->fsPath, st);
1155 *failedFile = xstrdup(map->fsPath);
1156 return CPIOERR_STAT_FAILED;
1159 if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
1160 hlink = hlinkList.next;
1162 (hlink->dev != st->st_dev || hlink->inode != st->st_ino))
1163 hlink = hlink->next;
1164 if (hlink == NULL) {
1165 hlink = newHardLink(st, HARDLINK_INSTALL);
1166 hlink->next = hlinkList.next;
1167 hlinkList.next = hlink;
1170 hlink->fileMaps[--hlink->linksLeft] = i;
1172 if (hlink->linksLeft == 0) {
1173 struct hardLink * prev;
1174 if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
1175 &size, failedFile)))
1182 if (prev->next != hlink)
1184 prev->next = hlink->next;
1186 freeHardLink(hlink);
1189 } while ((prev = prev->next) != NULL);
1192 if ((rc = writeFile(cfd, st, map, &size, 1))) {
1194 *failedFile = xstrdup(mappings[i].fsPath);
1199 cbInfo.file = map->archivePath;
1200 cb(&cbInfo, cbData);
1208 while ((hlink = hlinkList.next) != NULL) {
1209 hlinkList.next = hlink->next;
1213 rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
1217 freeHardLink(hlink);
1222 memset(&hdr, '0', PHYS_HDR_SIZE);
1223 memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
1224 memcpy(hdr.nlink, "00000001", 8);
1225 memcpy(hdr.namesize, "0000000b", 8);
1226 if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
1228 if ((rc = safewrite(cfd, "TRAILER!!!", 11)) != 11)
1230 totalsize += PHYS_HDR_SIZE + 11;
1232 /* GNU cpio pads to 512 bytes here, but we don't. I'm not sure if
1233 it matters or not */
1235 if ((rc = padoutfd(cfd, &totalsize, 4)))
1238 if (archiveSize) *archiveSize = totalsize;
1243 const char * cpioStrerror(int rc)
1245 static char msg[256];
1247 int l, myerrno = errno;
1249 strcpy(msg, "cpio: ");
1252 s = msg + strlen(msg);
1253 sprintf(s, _("(error 0x%x)"), (unsigned)rc);
1256 case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
1257 case CPIOERR_BAD_HEADER: s = _("Bad/unreadable header");break;
1259 case CPIOERR_OPEN_FAILED: s = "open"; break;
1260 case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
1261 case CPIOERR_CHOWN_FAILED: s = "chown"; break;
1262 case CPIOERR_WRITE_FAILED: s = "write"; break;
1263 case CPIOERR_UTIME_FAILED: s = "utime"; break;
1264 case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
1265 case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
1266 case CPIOERR_STAT_FAILED: s = "stat"; break;
1267 case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
1268 case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
1269 case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
1270 case CPIOERR_LINK_FAILED: s = "link"; break;
1271 case CPIOERR_READLINK_FAILED: s = "readlink"; break;
1272 case CPIOERR_READ_FAILED: s = "read"; break;
1273 case CPIOERR_COPY_FAILED: s = "copy"; break;
1275 case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
1276 case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
1277 case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link"); break;
1278 case CPIOERR_MD5SUM_MISMATCH: s = _("MD5 sum mismatch"); break;
1279 case CPIOERR_INTERNAL: s = _("Internal error"); break;
1282 l = sizeof(msg) - strlen(msg) - 1;
1284 if (l > 0) strncat(msg, s, l);
1287 if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
1288 s = _(" failed - ");
1289 if (l > 0) strncat(msg, s, l);
1291 if (l > 0) strncat(msg, strerror(myerrno), l);