home *** CD-ROM | disk | FTP | other *** search
- #include "config.h"
- #include "miscfn.h"
-
- #if HAVE_ALLOCA_H
- # include <alloca.h>
- #endif
-
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <utime.h>
-
- #include "cpio.h"
-
- #if MAJOR_IN_SYSMACROS
- #include <sys/sysmacros.h>
- #elif MAJOR_IN_MKDEV
- #include <sys/mkdev.h>
- #endif
-
- #define CPIO_NEWC_MAGIC "070701"
- #define CPIO_CRC_MAGIC "070702"
- #define TRAILER "TRAILER!!!"
-
- /* FIXME: We don't translate between cpio and system mode bits! These
- should both be the same, but really odd things are going to happen if
- that's not true! */
-
- /* We need to maintain our oun file pointer to allow padding */
- struct ourfd {
- gzFile fd;
- int pos;
- };
-
- struct hardLink {
- struct hardLink * next;
- char ** files; /* there are nlink of these, used by install */
- int * fileMaps; /* used by build */
- dev_t dev;
- ino_t inode;
- int nlink;
- int linksLeft;
- int createdPath;
- struct stat sb;
- };
-
- struct cpioCrcPhysicalHeader {
- char magic[6];
- char inode[8];
- char mode[8];
- char uid[8];
- char gid[8];
- char nlink[8];
- char mtime[8];
- char filesize[8];
- char devMajor[8];
- char devMinor[8];
- char rdevMajor[8];
- char rdevMinor[8];
- char namesize[8];
- char checksum[8]; /* ignored !! */
- };
-
- struct cpioHeader {
- ino_t inode;
- mode_t mode;
- uid_t uid;
- gid_t gid;
- int nlink;
- time_t mtime;
- long size;
- dev_t dev, rdev;
- char * path;
- };
-
- static inline off_t ourread(struct ourfd * thefd, void * buf, size_t size) {
- off_t i;
-
- i = gzread(thefd->fd, buf, size);
- thefd->pos += i;
-
- return i;
- }
-
- static inline void padinfd(struct ourfd * fd, int modulo) {
- int buf[10];
- int amount;
-
- amount = (modulo - fd->pos % modulo) % modulo;
- ourread(fd, buf, amount);
- }
-
- static inline off_t safewrite(int fd, void * vbuf, size_t amount) {
- int rc = 0;
- char * buf = vbuf;
-
- while (amount && (rc = write(fd, buf, amount)) < amount && rc > 0) {
- buf += rc;
- amount -= rc;
- }
-
- if (rc < 0) return rc;
-
- return 0;
- }
-
- static inline int padoutfd(int fd, int * where, int modulo) {
- static int buf[10] = { '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0' };
- int amount;
-
- amount = (modulo - *where % modulo) % modulo;
- *where += amount;
-
- if (safewrite(fd, buf, amount))
- return CPIO_WRITE_FAILED;
- return 0;
- }
-
- static int strntoul(const char * str, char ** endptr, int base, int num) {
- char * buf;
-
- buf = alloca(num + 1);
- strncpy(buf, str, num);
- buf[num] = '\0';
-
- return strtoul(buf, endptr, base);
- }
-
- #define GET_NUM_FIELD(phys, log) \
- log = strntoul(phys, &end, 16, sizeof(phys)); \
- if (*end) return CPIO_BAD_HEADER;
- #define SET_NUM_FIELD(phys, val, space) \
- sprintf(space, "%8.8lx", (unsigned long) (val)); \
- memcpy(phys, space, 8);
-
- static int getNextHeader(struct ourfd * fd, struct cpioHeader * chPtr) {
- struct cpioCrcPhysicalHeader physHeader;
- int nameSize;
- char * end;
- int major, minor;
-
- if (ourread(fd, &physHeader, sizeof(physHeader)) != sizeof(physHeader))
- return CPIO_READ_FAILED;
-
- if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC)) &&
- strncmp(CPIO_NEWC_MAGIC, physHeader.magic, strlen(CPIO_NEWC_MAGIC)))
- return CPIO_BAD_MAGIC;
-
- GET_NUM_FIELD(physHeader.inode, chPtr->inode);
- GET_NUM_FIELD(physHeader.mode, chPtr->mode);
- GET_NUM_FIELD(physHeader.uid, chPtr->uid);
- GET_NUM_FIELD(physHeader.gid, chPtr->gid);
- GET_NUM_FIELD(physHeader.nlink, chPtr->nlink);
- GET_NUM_FIELD(physHeader.mtime, chPtr->mtime);
- GET_NUM_FIELD(physHeader.filesize, chPtr->size);
-
- GET_NUM_FIELD(physHeader.devMajor, major);
- GET_NUM_FIELD(physHeader.devMinor, minor);
- chPtr->dev = makedev(major, minor);
-
- GET_NUM_FIELD(physHeader.rdevMajor, major);
- GET_NUM_FIELD(physHeader.rdevMinor, minor);
- chPtr->rdev = makedev(major, minor);
-
- GET_NUM_FIELD(physHeader.namesize, nameSize);
-
- chPtr->path = malloc(nameSize + 1);
- if (ourread(fd, chPtr->path, nameSize) != nameSize) {
- free(chPtr->path);
- return CPIO_BAD_HEADER;
- }
-
- /* this is unecessary chPtr->path[nameSize] = '\0'; */
-
- padinfd(fd, 4);
-
- return 0;
- }
-
- int cpioFileMapCmp(const void * a, const void * b) {
- const struct cpioFileMapping * first = a;
- const struct cpioFileMapping * second = b;
-
- return (strcmp(first->archivePath, second->archivePath));
- }
-
- /* This could trash files in the path! I'm not sure that's a good thing */
- static int createDirectory(char * path, mode_t perms) {
- struct stat sb;
- int dounlink;
-
- if (!lstat(path, &sb)) {
- if (S_ISDIR(sb.st_mode)) {
- return 0;
- } else if (S_ISLNK(sb.st_mode)) {
- if (stat(path, &sb)) {
- if (errno != ENOENT)
- return CPIO_STAT_FAILED;
- dounlink = 1;
- } else {
- if (S_ISDIR(sb.st_mode))
- return 0;
- dounlink = 1;
- }
- } else {
- dounlink = 1;
- }
-
- if (dounlink && unlink(path)) {
- return CPIO_UNLINK_FAILED;
- }
- }
-
- if (mkdir(path, 000))
- return CPIO_MKDIR_FAILED;
-
- if (chmod(path, perms))
- return CPIO_CHMOD_FAILED;
-
- return 0;
- }
-
- static int setInfo(struct cpioHeader * hdr) {
- int rc = 0;
- struct utimbuf stamp = { hdr->mtime, hdr->mtime };
-
-
- if (!S_ISLNK(hdr->mode)) {
- if (!getuid() && chown(hdr->path, hdr->uid, hdr->gid))
- rc = CPIO_CHOWN_FAILED;
- if (!rc && chmod(hdr->path, hdr->mode & 07777))
- rc = CPIO_CHMOD_FAILED;
- if (!rc && utime(hdr->path, &stamp))
- rc = CPIO_UTIME_FAILED;
- } else {
- #if ! CHOWN_FOLLOWS_SYMLINK
- if (!getuid() && !rc && lchown(hdr->path, hdr->uid, hdr->gid))
- rc = CPIO_CHOWN_FAILED;
- #endif
- }
-
- return rc;
- }
-
- static int checkDirectory(char * filename) {
- static char * lastDir = NULL;
- static int lastDirLength = 0;
- static int lastDirAlloced = 0;
- int length = strlen(filename);
- char * buf;
- char * chptr;
- int rc = 0;
-
- buf = alloca(length + 1);
- strcpy(buf, filename);
-
- for (chptr = buf + length - 1; chptr > buf; chptr--) {
- if (*chptr == '/') break;
- }
-
- if (chptr == buf) return 0; /* /filename - no directories */
-
- *chptr = '\0'; /* buffer is now just directories */
-
- length = strlen(buf);
- if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
-
- if (lastDirAlloced < (length + 1)) {
- lastDirAlloced = length + 100;
- lastDir = realloc(lastDir, lastDirAlloced);
- }
-
- strcpy(lastDir, buf);
- lastDirLength = length;
-
- for (chptr = buf + 1; *chptr; chptr++) {
- if (*chptr == '/') {
- *chptr = '\0';
- rc = createDirectory(buf, 0755);
- *chptr = '/';
- if (rc) return rc;
- }
- }
- rc = createDirectory(buf, 0755);
-
- return rc;
- }
-
- static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr,
- cpioCallback cb, void * cbData) {
- int out;
- char buf[8192];
- int bytesRead;
- int left = hdr->size;
- int rc = 0;
- struct cpioCallbackInfo cbInfo;
- struct stat sb;
-
- if (!lstat(hdr->path, &sb))
- if (unlink(hdr->path))
- return CPIO_UNLINK_FAILED;
-
- out = open(hdr->path, O_CREAT | O_WRONLY, 0);
- if (out < 0)
- return CPIO_OPEN_FAILED;
-
- cbInfo.file = hdr->path;
- cbInfo.fileSize = hdr->size;
-
- while (left) {
- bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
- if (bytesRead <= 0) {
- rc = CPIO_READ_FAILED;
- break;
- }
-
- if (write(out, buf, bytesRead) != bytesRead) {
- rc = CPIO_READ_FAILED;
- break;
- }
-
- left -= bytesRead;
-
- /* don't call this with fileSize == fileComplete */
- if (!rc && cb && left) {
- cbInfo.fileComplete = hdr->size - left;
- cbInfo.bytesProcessed = fd->pos;
- cb(&cbInfo, cbData);
- }
- }
-
- close(out);
-
- return rc;
- }
-
- static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
- char buf[2048], buf2[2048];
- struct stat sb;
- int len;
-
- if ((hdr->size + 1)> sizeof(buf))
- return CPIO_INTERNAL;
-
- if (ourread(fd, buf, hdr->size) != hdr->size)
- return CPIO_READ_FAILED;
-
- buf[hdr->size] = '\0';
-
- if (!lstat(hdr->path, &sb)) {
- if (S_ISLNK(sb.st_mode)) {
- len = readlink(hdr->path, buf2, sizeof(buf2) - 1);
- if (len > 0) {
- buf2[len] = '\0';
- if (!strcmp(buf, buf2)) return 0;
- }
- }
-
- if (unlink(hdr->path))
- return CPIO_UNLINK_FAILED;
- }
-
- if (symlink(buf, hdr->path) < 0)
- return CPIO_SYMLINK_FAILED;
-
- return 0;
- }
-
- static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
- struct stat sb;
-
- if (!lstat(hdr->path, &sb)) {
- if (S_ISFIFO(sb.st_mode)) return 0;
-
- if (unlink(hdr->path))
- return CPIO_UNLINK_FAILED;
- }
-
- if (mkfifo(hdr->path, 0))
- return CPIO_MKFIFO_FAILED;
-
- return 0;
- }
-
- static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
- struct stat sb;
-
- if (!lstat(hdr->path, &sb)) {
- if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) &&
- (sb.st_rdev == hdr->rdev))
- return 0;
- if (unlink(hdr->path))
- return CPIO_UNLINK_FAILED;
- }
-
- if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
- return CPIO_MKNOD_FAILED;
-
- return 0;
- }
-
- static void freeLink(struct hardLink * li) {
- int i;
-
- for (i = 0; i < li->nlink; i++) {
- if (li->files[i]) free(li->files[i]);
- }
- free(li->files);
- }
-
- static int createLinks(struct hardLink * li, char ** failedFile) {
- int i;
- struct stat sb;
-
- for (i = 0; i < li->nlink; i++) {
- if (i == li->createdPath) continue;
- if (!li->files[i]) continue;
-
- if (!lstat(li->files[i], &sb)) {
- if (unlink(li->files[i])) {
- *failedFile = strdup(li->files[i]);
- return CPIO_UNLINK_FAILED;
- }
- }
-
- if (link(li->files[li->createdPath], li->files[i])) {
- *failedFile = strdup(li->files[i]);
- return CPIO_LINK_FAILED;
- }
-
- free(li->files[i]);
- li->files[i] = NULL;
- li->linksLeft--;
- }
-
- return 0;
- }
-
- static int eatBytes(struct ourfd * fd, int amount) {
- char buf[4096];
- int bite;
-
- while (amount) {
- bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
- if (ourread(fd, buf, bite) != bite)
- return CPIO_READ_FAILED;
- amount -= bite;
- }
-
- return 0;
- }
-
- int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
- int numMappings, cpioCallback cb, void * cbData,
- char ** failedFile) {
- struct cpioHeader ch;
- struct ourfd fd;
- int rc = 0;
- int linkNum = 0;
- struct cpioFileMapping * map = NULL;
- struct cpioFileMapping needle;
- mode_t cpioMode;
- int olderr;
- struct cpioCallbackInfo cbInfo;
- struct hardLink * links = NULL;
- struct hardLink * li = NULL;
-
- fd.fd = stream;
- fd.pos = 0;
-
- *failedFile = NULL;
-
- do {
- if ((rc = getNextHeader(&fd, &ch))) {
- printf("error %d reading header: %s\n", rc, strerror(errno));
- exit(1);
- }
-
- if (!strcmp(ch.path, TRAILER)) {
- free(ch.path);
- break;
- }
-
- if (mappings) {
- needle.archivePath = ch.path;
- map = bsearch(&needle, mappings, numMappings, sizeof(needle),
- cpioFileMapCmp);
- }
-
- if (mappings && !map) {
- eatBytes(&fd, ch.size);
- } else {
- cpioMode = ch.mode;
-
- if (map) {
- if (map->mapFlags & CPIO_MAP_PATH) {
- free(ch.path);
- ch.path = strdup(map->fsPath);
- }
-
- if (map->mapFlags & CPIO_MAP_MODE)
- ch.mode = map->finalMode;
- if (map->mapFlags & CPIO_MAP_UID)
- ch.uid = map->finalUid;
- if (map->mapFlags & CPIO_MAP_GID)
- ch.gid = map->finalGid;
- }
-
- /* This won't get hard linked symlinks right, but I can't seem
- to create those anyway */
-
- if (S_ISREG(ch.mode) && ch.nlink > 1) {
- li = links;
- for (li = links; li; li = li->next) {
- if (li->inode == ch.inode && li->dev == ch.dev) break;
- }
-
- if (!li) {
- li = malloc(sizeof(*li));
- li->inode = ch.inode;
- li->dev = ch.dev;
- li->nlink = ch.nlink;
- li->linksLeft = ch.nlink;
- li->createdPath = -1;
- li->files = calloc(sizeof(char *), li->nlink);
- li->next = links;
- links = li;
- }
-
- for (linkNum = 0; linkNum < li->nlink; linkNum++)
- if (!li->files[linkNum]) break;
- li->files[linkNum] = strdup(ch.path);
- }
-
- if ((ch.nlink > 1) && S_ISREG(ch.mode) && !ch.size &&
- li->createdPath == -1) {
- /* defer file creation */
- } else if ((ch.nlink > 1) && S_ISREG(ch.mode) &&
- (li->createdPath != -1)) {
- createLinks(li, failedFile);
-
- /* this only happens for cpio archives which contain
- hardlinks w/ the contents of each hardlink being
- listed (intead of the data being given just once. This
- shouldn't happen, but I've made it happen w/ buggy
- code, so what the heck? GNU cpio handles this well fwiw */
- if (ch.size) eatBytes(&fd, ch.size);
- } else {
- rc = checkDirectory(ch.path);
-
- if (!rc) {
- if (S_ISREG(ch.mode))
- rc = expandRegular(&fd, &ch, cb, cbData);
- else if (S_ISDIR(ch.mode))
- rc = createDirectory(ch.path, 000);
- else if (S_ISLNK(ch.mode))
- rc = expandSymlink(&fd, &ch);
- else if (S_ISFIFO(ch.mode))
- rc = expandFifo(&fd, &ch);
- else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
- rc = expandDevice(&fd, &ch);
- else if (S_ISSOCK(ch.mode)) {
- /* this mimicks cpio but probably isnt' right */
- rc = expandFifo(&fd, &ch);
- } else {
- rc = CPIO_INTERNAL;
- }
- }
-
- if (!rc)
- rc = setInfo(&ch);
-
- if (S_ISREG(ch.mode) && ch.nlink > 1) {
- li->createdPath = linkNum;
- li->linksLeft--;
- rc = createLinks(li, failedFile);
- }
- }
-
- if (rc && !*failedFile) {
- *failedFile = strdup(ch.path);
-
- olderr = errno;
- unlink(ch.path);
- errno = olderr;
- }
- }
-
- padinfd(&fd, 4);
-
- if (!rc && cb) {
- cbInfo.file = ch.path;
- cbInfo.fileSize = ch.size;
- cbInfo.fileComplete = ch.size;
- cbInfo.bytesProcessed = fd.pos;
- cb(&cbInfo, cbData);
- }
-
- free(ch.path);
- } while (1 && !rc);
-
- li = links;
- while (li && !rc) {
- if (li->linksLeft) {
- if (li->createdPath == -1)
- rc = CPIO_INTERNAL;
- else
- rc = createLinks(li, failedFile);
- }
-
- freeLink(li);
-
- links = li;
- li = li->next;
- free(links);
- links = li;
- }
-
- li = links;
- /* if an error got us here links will still be eating some memory */
- while (li) {
- freeLink(li);
- links = li;
- li = li->next;
- free(links);
- }
-
- return rc;
- }
-
- static int writeFile(int fd, struct stat sb, struct cpioFileMapping * map,
- size_t * sizeptr, int writeData) {
- struct cpioCrcPhysicalHeader hdr;
- char buf[8192], symbuf[2048];
- dev_t num;
- int datafd;
- size_t size, amount = 0;
- int rc, olderrno;
-
- if (!(map->mapFlags & CPIO_MAP_PATH))
- map->archivePath = map->fsPath;
- if (map->mapFlags & CPIO_MAP_MODE)
- sb.st_mode = (sb.st_mode & S_IFMT) | map->finalMode;
- if (map->mapFlags & CPIO_MAP_UID)
- sb.st_uid = map->finalUid;
- if (map->mapFlags & CPIO_MAP_GID)
- sb.st_gid = map->finalGid;
-
- if (!writeData || S_ISDIR(sb.st_mode)) {
- sb.st_size = 0;
- } else if (S_ISLNK(sb.st_mode)) {
- /* While linux puts the size of a symlink in the st_size field,
- I don't think that's a specified standard */
-
- amount = readlink(map->fsPath, symbuf, sizeof(symbuf));
- if (amount <= 0) {
- return CPIO_READLINK_FAILED;
- }
-
- sb.st_size = amount;
- }
-
- memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
- SET_NUM_FIELD(hdr.inode, sb.st_ino, buf);
- SET_NUM_FIELD(hdr.mode, sb.st_mode, buf);
- SET_NUM_FIELD(hdr.uid, sb.st_uid, buf);
- SET_NUM_FIELD(hdr.gid, sb.st_gid, buf);
- SET_NUM_FIELD(hdr.nlink, sb.st_nlink, buf);
- SET_NUM_FIELD(hdr.mtime, sb.st_mtime, buf);
- SET_NUM_FIELD(hdr.filesize, sb.st_size, buf);
-
- num = major(sb.st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
- num = minor(sb.st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
- num = major(sb.st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
- num = minor(sb.st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
-
- num = strlen(map->archivePath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
- memcpy(hdr.checksum, "00000000", 8);
-
- if ((rc = safewrite(fd, &hdr, sizeof(hdr))))
- return rc;
- if ((rc = safewrite(fd, map->archivePath, num)))
- return rc;
- size = sizeof(hdr) + num;
- if ((rc = padoutfd(fd, &size, 4)))
- return rc;
-
- if (writeData && S_ISREG(sb.st_mode)) {
- /* FIXME: we should use mmap here if it's available */
- if ((datafd = open(map->archivePath, O_RDONLY)) < 0)
- return CPIO_OPEN_FAILED;
-
- size += sb.st_size;
-
- while (sb.st_size) {
- amount = read(datafd, buf,
- sb.st_size > sizeof(buf) ? sizeof(buf) : sb.st_size);
- if (amount <= 0) {
- olderrno = errno;
- close(datafd);
- errno = olderrno;
- return CPIO_READ_FAILED;
- }
-
- if ((rc = safewrite(fd, buf, amount))) {
- olderrno = errno;
- close(datafd);
- errno = olderrno;
- return rc;
- }
-
- sb.st_size -= amount;
- }
-
- close(datafd);
- } else if (writeData && S_ISLNK(sb.st_mode)) {
- if ((rc = safewrite(fd, symbuf, amount)))
- return rc;
- size += amount;
- }
-
- /* this is a noop for most file types */
- if ((rc = padoutfd(fd, &size, 4)))
- return rc;
-
- *sizeptr = size;
-
- return 0;
- }
-
- static int writeLinkedFile(int fd, struct hardLink * hlink,
- struct cpioFileMapping * mappings,
- cpioCallback cb, void * cbData,
- size_t * sizeptr,
- char ** failedFile) {
- int i, rc;
- size_t size;
- struct cpioCallbackInfo cbinfo;
-
- *sizeptr = 0;
-
- for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
- if ((rc = writeFile(fd, hlink->sb, mappings + hlink->fileMaps[i],
- &size, 0))) {
- if (failedFile) *failedFile =
- mappings[hlink->fileMaps[i]].fsPath;
- return rc;
- }
-
- *sizeptr += size;
-
- if (cb) {
- cbinfo.file = mappings[i].archivePath;
- cb(&cbinfo, cbData);
- }
- }
-
- if ((rc = writeFile(fd, hlink->sb,
- mappings + hlink->fileMaps[hlink->linksLeft],
- &size, 1))) {
- if (failedFile)
- *failedFile = mappings[hlink->fileMaps[hlink->linksLeft]].fsPath;
- return rc;
- }
-
- *sizeptr += size;
-
- if (cb) {
- cbinfo.file = mappings[i].archivePath;
- cb(&cbinfo, cbData);
- }
-
- return 0;
- }
-
- int cpioBuildArchive(int fd, struct cpioFileMapping * mappings,
- int numMappings, cpioCallback cb, void * cbData,
- unsigned int * archiveSize, char ** failedFile) {
- size_t size, totalsize = 0;
- int rc;
- int i;
- struct cpioCallbackInfo cbinfo;
- struct cpioCrcPhysicalHeader hdr;
- struct stat sb;
- struct hardLink hlinkList = { NULL };
- struct hardLink * hlink, * parent;
-
- hlinkList.next = NULL;
-
- for (i = 0; i < numMappings; i++) {
- if (mappings[i].mapFlags & CPIO_FOLLOW_SYMLINKS)
- rc = stat(mappings[i].fsPath, &sb);
- else
- rc = lstat(mappings[i].fsPath, &sb);
-
- if (rc) {
- if (failedFile) *failedFile = mappings[i].fsPath;
- return CPIO_STAT_FAILED;
- }
-
- if (!S_ISDIR(sb.st_mode) && sb.st_nlink > 1) {
- hlink = hlinkList.next;
- while (hlink &&
- (hlink->dev != sb.st_dev || hlink->inode != sb.st_ino))
- hlink = hlink->next;
- if (!hlink) {
- hlink = malloc(sizeof(*hlink));
- hlink->next = hlinkList.next;
- hlinkList.next = hlink;
- hlink->sb = sb;
- hlink->dev = sb.st_dev;
- hlink->inode = sb.st_ino;
- hlink->nlink = sb.st_nlink;
- hlink->linksLeft = sb.st_nlink;
- hlink->fileMaps = malloc(sizeof(*hlink->fileMaps) *
- sb.st_nlink);
- }
-
- hlink->fileMaps[--hlink->linksLeft] = i;
-
- if (!hlink->linksLeft) {
- if ((rc = writeLinkedFile(fd, hlink, mappings, cb, cbData,
- &size, failedFile)))
- return rc;
-
- totalsize += size;
-
- free(hlink->fileMaps);
-
- parent = &hlinkList;
- while (parent->next != hlink) parent = parent->next;
- parent->next = parent->next->next;
- free(hlink);
- }
- } else {
- if ((rc = writeFile(fd, sb, mappings + i, &size, 1))) {
- if (failedFile) *failedFile = mappings[i].fsPath;
- return rc;
- }
-
- if (cb) {
- cbinfo.file = mappings[i].archivePath;
- cb(&cbinfo, cbData);
- }
-
- totalsize += size;
- }
- }
-
- hlink = hlinkList.next;
- while (hlink) {
- if ((rc = writeLinkedFile(fd, hlink, mappings, cb, cbData,
- &size, failedFile)))
- return rc;
- free(hlink->fileMaps);
- parent = hlink;
- hlink = hlink->next;
- free(parent);
- }
-
- memset(&hdr, '0', sizeof(hdr));
- memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
- memcpy(hdr.nlink, "00000001", 8);
- memcpy(hdr.namesize, "0000000b", 8);
- if ((rc = safewrite(fd, &hdr, sizeof(hdr))))
- return rc;
- if ((rc = safewrite(fd, "TRAILER!!!", 11)))
- return rc;
- totalsize += sizeof(hdr) + 11;
-
- /* GNU cpio pads to 512 bytes here, but we don't. I'm not sure if
- it matters or not */
-
- if ((rc = padoutfd(fd, &totalsize, 4)))
- return rc;
-
- if (archiveSize) *archiveSize = totalsize;
-
- return 0;
- }
-