16 #if MAJOR_IN_SYSMACROS
17 #include <sys/sysmacros.h>
19 #include <sys/mkdev.h>
22 #define CPIO_CRC_MAGIC "070702"
23 #define TRAILER "TRAILER!!!"
25 /* FIXME: We don't translate between cpio and system mode bits! These
26 should both be the same, but really odd things are going to happen if
29 /* We need to maintain our oun file pointer to allow padding */
36 char ** files; /* there are nlink of these */
42 struct hardLink * next;
45 struct cpioCrcPhysicalHeader {
59 char checksum[8]; /* ignored !! */
74 static inline loff_t ourread(struct ourfd * thefd, void * buf, size_t size) {
77 i = gzread(thefd->fd, buf, size);
83 static inline void padfd(struct ourfd * fd, int modulo) {
87 amount = (modulo - fd->pos % modulo) % modulo;
88 ourread(fd, buf, amount);
91 static int strntoul(const char * str, char ** endptr, int base, int num) {
94 buf = alloca(num + 1);
95 strncpy(buf, str, num);
98 return strtoul(buf, endptr, base);
101 #define GET_NUM_FIELD(phys, log) \
102 log = strntoul(phys, &end, 16, sizeof(phys)); \
103 if (*end) return CPIO_BAD_HEADER;
105 static int getNextHeader(struct ourfd * fd, struct cpioHeader * chPtr) {
106 struct cpioCrcPhysicalHeader physHeader;
111 if (ourread(fd, &physHeader, sizeof(physHeader)) != sizeof(physHeader))
112 return CPIO_READ_FAILED;
114 if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC)))
115 return CPIO_BAD_MAGIC;
118 GET_NUM_FIELD(physHeader.inode, chPtr->inode);
119 GET_NUM_FIELD(physHeader.mode, chPtr->mode);
120 GET_NUM_FIELD(physHeader.uid, chPtr->uid);
121 GET_NUM_FIELD(physHeader.gid, chPtr->gid);
122 GET_NUM_FIELD(physHeader.nlink, chPtr->nlink);
123 GET_NUM_FIELD(physHeader.mtime, chPtr->mtime);
124 GET_NUM_FIELD(physHeader.filesize, chPtr->size);
126 GET_NUM_FIELD(physHeader.devMajor, major);
127 GET_NUM_FIELD(physHeader.devMinor, minor);
128 chPtr->dev = makedev(major, minor);
130 GET_NUM_FIELD(physHeader.rdevMajor, major);
131 GET_NUM_FIELD(physHeader.rdevMinor, minor);
132 chPtr->rdev = makedev(major, minor);
134 GET_NUM_FIELD(physHeader.namesize, nameSize);
136 chPtr->path = malloc(nameSize + 1);
137 if (ourread(fd, chPtr->path, nameSize) != nameSize) {
139 return CPIO_BAD_HEADER;
142 chPtr->path[nameSize] = '\0';
149 int cpioFileMapCmp(const void * a, const void * b) {
150 const struct cpioFileMapping * first = a;
151 const struct cpioFileMapping * second = b;
153 return (strcmp(first->archivePath, second->archivePath));
156 /* This could trash files in the path! I'm not sure that's a good thing */
157 static int createDirectory(char * path) {
161 if (!lstat(path, &sb)) {
162 if (S_ISDIR(sb.st_mode)) {
164 } else if (S_ISLNK(sb.st_mode)) {
165 if (stat(path, &sb)) {
167 return CPIO_STAT_FAILED;
170 if (S_ISDIR(sb.st_mode))
178 if (dounlink && unlink(path)) {
179 return CPIO_UNLINK_FAILED;
183 if (mkdir(path, 000))
184 return CPIO_MKDIR_FAILED;
189 static int setInfo(struct cpioHeader * hdr) {
191 struct utimbuf stamp = { hdr->mtime, hdr->mtime };
193 if (!getuid() && !rc && chown(hdr->path, hdr->uid, hdr->gid))
194 rc = CPIO_CHOWN_FAILED;
196 if (!S_ISLNK(hdr->mode)) {
197 if (!rc && chmod(hdr->path, hdr->mode & 07777))
198 rc = CPIO_CHMOD_FAILED;
199 if (!rc && utime(hdr->path, &stamp))
200 rc = CPIO_UTIME_FAILED;
206 static int checkDirectory(char * filename) {
207 static char * lastDir = NULL;
208 static int lastDirLength = 0;
209 static int lastDirAlloced = 0;
210 int length = strlen(filename);
215 buf = alloca(length + 1);
216 strcpy(buf, filename);
218 for (chptr = buf + length - 1; chptr > buf; chptr--) {
219 if (*chptr == '/') break;
222 if (chptr == buf) return 0; /* /filename - no directories */
224 *chptr = '\0'; /* buffer is now just directories */
226 length = strlen(buf);
227 if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
229 if (lastDirAlloced < (length + 1)) {
230 lastDirAlloced = length + 100;
231 lastDir = realloc(lastDir, lastDirAlloced);
234 strcpy(lastDir, buf);
235 lastDirLength = length;
237 for (chptr = buf + 1; *chptr; chptr++) {
240 rc = createDirectory(buf);
245 rc = createDirectory(buf);
250 static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr,
251 cpioCallback cb, void * cbData) {
255 int left = hdr->size;
257 struct cpioCallbackInfo cbInfo;
260 if (!lstat(hdr->path, &sb))
261 if (unlink(hdr->path))
262 return CPIO_UNLINK_FAILED;
264 out = open(hdr->path, O_CREAT | O_WRONLY, 0);
266 return CPIO_OPEN_FAILED;
268 cbInfo.file = hdr->path;
269 cbInfo.fileSize = hdr->size;
272 bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
273 if (bytesRead <= 0) {
274 rc = CPIO_READ_FAILED;
278 if (write(out, buf, bytesRead) != bytesRead) {
279 rc = CPIO_READ_FAILED;
285 /* don't call this with fileSize == fileComplete */
286 if (!rc && cb && left) {
287 cbInfo.fileComplete = hdr->size - left;
288 cbInfo.bytesProcessed = fd->pos;
298 static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
302 if (!lstat(hdr->path, &sb))
303 if (unlink(hdr->path))
304 return CPIO_UNLINK_FAILED;
306 if ((hdr->size + 1)> sizeof(buf))
307 return CPIO_INTERNAL;
309 if (ourread(fd, buf, hdr->size) != hdr->size)
310 return CPIO_READ_FAILED;
312 buf[hdr->size] = '\0';
314 if (symlink(buf, hdr->path))
315 return CPIO_SYMLINK_FAILED;
320 static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
323 if (!lstat(hdr->path, &sb)) {
324 if (S_ISFIFO(sb.st_mode)) return 0;
326 if (unlink(hdr->path))
327 return CPIO_UNLINK_FAILED;
330 if (mkfifo(hdr->path, 0))
331 return CPIO_MKFIFO_FAILED;
336 static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
339 if (!lstat(hdr->path, &sb))
340 if (unlink(hdr->path))
341 return CPIO_UNLINK_FAILED;
343 if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
344 return CPIO_MKNOD_FAILED;
349 static void freeLink(struct hardLink * li) {
352 for (i = 0; i < li->nlink; i++) {
353 if (li->files[i]) free(li->files[i]);
358 static int createLinks(struct hardLink * li, char ** failedFile) {
362 for (i = 0; i < li->nlink; i++) {
363 if (i == li->createdPath) continue;
364 if (!li->files[i]) continue;
366 if (!lstat(li->files[i], &sb)) {
367 if (unlink(li->files[i])) {
368 *failedFile = strdup(li->files[i]);
369 return CPIO_UNLINK_FAILED;
373 if (link(li->files[li->createdPath], li->files[i])) {
374 *failedFile = strdup(li->files[i]);
375 return CPIO_LINK_FAILED;
386 int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
387 int numMappings, cpioCallback cb, void * cbData,
388 char ** failedFile) {
389 struct cpioHeader ch;
393 struct cpioFileMapping * map = NULL;
394 struct cpioFileMapping needle;
397 struct cpioCallbackInfo cbInfo;
398 struct hardLink * links = NULL;
399 struct hardLink * li = NULL;
407 if ((rc = getNextHeader(&fd, &ch))) {
408 printf("error %d reading header: %s\n", rc, strerror(errno));
412 if (!strcmp(ch.path, TRAILER)) {
418 needle.archivePath = ch.path;
419 map = bsearch(&needle, mappings, numMappings, sizeof(needle),
423 if (!mappings || map) {
427 if (map->mapFlags & CPIO_MAP_PATH) {
429 ch.path = strdup(map->finalPath);
432 if (map->mapFlags & CPIO_MAP_MODE)
433 ch.mode = map->finalMode;
434 if (map->mapFlags & CPIO_MAP_UID)
435 ch.uid = map->finalUid;
436 if (map->mapFlags & CPIO_MAP_GID)
437 ch.gid = map->finalGid;
440 /* This won't get hard linked symlinks right, but I can't seem
441 to create those anyway */
445 for (li = links; li; li = li->next) {
446 if (li->inode == ch.inode && li->dev == ch.dev) break;
450 li = malloc(sizeof(*li));
451 li->inode = ch.inode;
453 li->nlink = ch.nlink;
454 li->linksLeft = ch.nlink;
455 li->createdPath = -1;
456 li->files = calloc(sizeof(char *), li->nlink);
461 for (linkNum = 0; linkNum < li->nlink; linkNum++)
462 if (!li->files[linkNum]) break;
463 li->files[linkNum] = strdup(ch.path);
466 if ((ch.nlink > 1) && S_ISREG(ch.mode) && !ch.size &&
467 li->createdPath == -1) {
468 /* defer file creation */
469 } else if ((ch.nlink > 1) && (li->createdPath != -1)) {
470 createLinks(li, failedFile);
472 rc = checkDirectory(ch.path);
475 if (S_ISREG(ch.mode))
476 rc = expandRegular(&fd, &ch, cb, cbData);
477 else if (S_ISDIR(ch.mode))
478 rc = createDirectory(ch.path);
479 else if (S_ISLNK(ch.mode))
480 rc = expandSymlink(&fd, &ch);
481 else if (S_ISFIFO(ch.mode))
482 rc = expandFifo(&fd, &ch);
483 else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
484 rc = expandDevice(&fd, &ch);
485 else if (S_ISSOCK(ch.mode)) {
486 /* this mimicks cpio but probably isnt' right */
487 rc = expandFifo(&fd, &ch);
497 li->createdPath = linkNum;
499 rc = createLinks(li, failedFile);
503 if (rc && !*failedFile) {
504 *failedFile = strdup(ch.path);
515 cbInfo.file = ch.path;
516 cbInfo.fileSize = ch.size;
517 cbInfo.fileComplete = ch.size;
518 cbInfo.bytesProcessed = fd.pos;
528 if (li->createdPath == -1)
531 rc = createLinks(li, failedFile);
543 /* if an error got us here links will still be eating some memory */