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 */
35 struct cpioCrcPhysicalHeader {
49 char checksum[8]; /* ignored !! */
64 static inline loff_t ourread(struct ourfd * thefd, void * buf, size_t size) {
67 i = gzread(thefd->fd, buf, size);
73 static inline void padfd(struct ourfd * fd, int modulo) {
77 amount = (modulo - fd->pos % modulo) % modulo;
78 ourread(fd, buf, amount);
81 static int strntoul(const char * str, char ** endptr, int base, int num) {
84 buf = alloca(num + 1);
85 strncpy(buf, str, num);
88 return strtoul(buf, endptr, base);
91 #define GET_NUM_FIELD(phys, log) \
92 log = strntoul(phys, &end, 16, sizeof(phys)); \
93 if (*end) return CPIO_BAD_HEADER;
95 static int getNextHeader(struct ourfd * fd, struct cpioHeader * chPtr) {
96 struct cpioCrcPhysicalHeader physHeader;
101 if (ourread(fd, &physHeader, sizeof(physHeader)) != sizeof(physHeader))
102 return CPIO_READ_FAILED;
104 if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC)))
105 return CPIO_BAD_MAGIC;
108 GET_NUM_FIELD(physHeader.inode, chPtr->inode);
109 GET_NUM_FIELD(physHeader.mode, chPtr->mode);
110 GET_NUM_FIELD(physHeader.uid, chPtr->uid);
111 GET_NUM_FIELD(physHeader.gid, chPtr->gid);
112 GET_NUM_FIELD(physHeader.nlink, chPtr->nlink);
113 GET_NUM_FIELD(physHeader.mtime, chPtr->mtime);
114 GET_NUM_FIELD(physHeader.filesize, chPtr->size);
116 GET_NUM_FIELD(physHeader.devMajor, major);
117 GET_NUM_FIELD(physHeader.devMinor, minor);
118 chPtr->dev = makedev(major, minor);
120 GET_NUM_FIELD(physHeader.rdevMajor, major);
121 GET_NUM_FIELD(physHeader.rdevMinor, minor);
122 chPtr->rdev = makedev(major, minor);
124 GET_NUM_FIELD(physHeader.namesize, nameSize);
126 chPtr->path = malloc(nameSize + 1);
127 if (ourread(fd, chPtr->path, nameSize) != nameSize) {
129 return CPIO_BAD_HEADER;
132 chPtr->path[nameSize] = '\0';
139 int cpioFileMapCmp(const void * a, const void * b) {
140 const struct cpioFileMapping * first = a;
141 const struct cpioFileMapping * second = b;
143 return (strcmp(first->archivePath, second->archivePath));
146 /* This could trash files in the path! I'm not sure that's a good thing */
147 static int createDirectory(char * path) {
151 if (!lstat(path, &sb)) {
152 if (S_ISDIR(sb.st_mode)) {
154 } else if (S_ISLNK(sb.st_mode)) {
155 if (stat(path, &sb)) {
157 return CPIO_STAT_FAILED;
160 if (S_ISDIR(sb.st_mode))
168 if (dounlink && unlink(path)) {
169 return CPIO_UNLINK_FAILED;
173 if (mkdir(path, 000))
174 return CPIO_MKDIR_FAILED;
179 static int setInfo(struct cpioHeader * hdr) {
181 struct utimbuf stamp = { hdr->mtime, hdr->mtime };
183 if (!getuid() && !rc && chown(hdr->path, hdr->uid, hdr->gid))
184 rc = CPIO_CHOWN_FAILED;
186 if (!S_ISLNK(hdr->mode)) {
187 if (!rc && chmod(hdr->path, hdr->mode & 07777))
188 rc = CPIO_CHMOD_FAILED;
189 if (!rc && utime(hdr->path, &stamp))
190 rc = CPIO_UTIME_FAILED;
196 static int checkDirectory(char * filename) {
197 static char * lastDir = NULL;
198 static int lastDirLength = 0;
199 static int lastDirAlloced = 0;
200 int length = strlen(filename);
205 buf = alloca(length + 1);
206 strcpy(buf, filename);
208 for (chptr = buf + length - 1; chptr > buf; chptr--) {
209 if (*chptr == '/') break;
212 if (chptr == buf) return 0; /* /filename - no directories */
214 *chptr = '\0'; /* buffer is now just directories */
216 length = strlen(buf);
217 if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
219 if (lastDirAlloced < (length + 1)) {
220 lastDirAlloced = length + 100;
221 lastDir = realloc(lastDir, lastDirAlloced);
224 strcpy(lastDir, buf);
225 lastDirLength = length;
227 for (chptr = buf + 1; *chptr; chptr++) {
230 rc = createDirectory(buf);
235 rc = createDirectory(buf);
240 static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr,
241 cpioCallback cb, void * cbData) {
245 int left = hdr->size;
247 struct cpioCallbackInfo cbInfo;
250 if (!lstat(hdr->path, &sb))
251 if (unlink(hdr->path))
252 return CPIO_UNLINK_FAILED;
254 out = open(hdr->path, O_CREAT | O_WRONLY, 0);
256 return CPIO_OPEN_FAILED;
258 cbInfo.file = hdr->path;
259 cbInfo.fileSize = hdr->size;
262 bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
263 if (bytesRead <= 0) {
264 rc = CPIO_READ_FAILED;
268 if (write(out, buf, bytesRead) != bytesRead) {
269 rc = CPIO_READ_FAILED;
275 /* don't call this with fileSize == fileComplete */
276 if (!rc && cb && left) {
277 cbInfo.fileComplete = hdr->size - left;
278 cbInfo.bytesProcessed = fd->pos;
288 static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
292 if (!lstat(hdr->path, &sb))
293 if (unlink(hdr->path))
294 return CPIO_UNLINK_FAILED;
296 if ((hdr->size + 1)> sizeof(buf))
297 return CPIO_INTERNAL;
299 if (ourread(fd, buf, hdr->size) != hdr->size)
300 return CPIO_READ_FAILED;
302 buf[hdr->size] = '\0';
304 if (symlink(buf, hdr->path))
305 return CPIO_SYMLINK_FAILED;
310 static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
313 if (!lstat(hdr->path, &sb)) {
314 if (S_ISFIFO(sb.st_mode)) return 0;
316 if (unlink(hdr->path))
317 return CPIO_UNLINK_FAILED;
320 if (mkfifo(hdr->path, 0))
321 return CPIO_MKFIFO_FAILED;
326 static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
329 if (!lstat(hdr->path, &sb))
330 if (unlink(hdr->path))
331 return CPIO_UNLINK_FAILED;
333 if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
334 return CPIO_MKNOD_FAILED;
339 int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
340 int numMappings, cpioCallback cb, void * cbData,
341 char ** failedFile) {
342 struct cpioHeader ch;
345 struct cpioFileMapping * map = NULL;
346 struct cpioFileMapping needle;
349 struct cpioCallbackInfo cbInfo;
355 if ((rc = getNextHeader(&fd, &ch))) {
356 printf("error %d reading header: %s\n", rc, strerror(errno));
360 if (!strcmp(ch.path, TRAILER)) {
366 needle.archivePath = ch.path;
367 map = bsearch(&needle, mappings, numMappings, sizeof(needle),
371 if (!mappings || map) {
375 if (map->mapFlags & CPIO_MAP_PATH) {
377 ch.path = strdup(map->finalPath);
380 if (map->mapFlags & CPIO_MAP_MODE)
381 ch.mode = map->finalMode;
382 if (map->mapFlags & CPIO_MAP_UID)
383 ch.uid = map->finalUid;
384 if (map->mapFlags & CPIO_MAP_GID)
385 ch.gid = map->finalGid;
388 rc = checkDirectory(ch.path);
391 if (S_ISREG(ch.mode))
392 rc = expandRegular(&fd, &ch, cb, cbData);
393 else if (S_ISDIR(ch.mode))
394 rc = createDirectory(ch.path);
395 else if (S_ISLNK(ch.mode))
396 rc = expandSymlink(&fd, &ch);
397 else if (S_ISFIFO(ch.mode))
398 rc = expandFifo(&fd, &ch);
399 else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
400 rc = expandDevice(&fd, &ch);
401 else if (S_ISSOCK(ch.mode)) {
402 /* should we do something here??? */
413 *failedFile = strdup(ch.path);
424 cbInfo.file = ch.path;
425 cbInfo.fileSize = ch.size;
426 cbInfo.fileComplete = ch.size;
427 cbInfo.bytesProcessed = fd.pos;