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 (!access(path, X_OK)) {
152 if (lstat(path, &sb))
153 return CPIO_STAT_FAILED;
155 if (S_ISDIR(sb.st_mode)) {
157 } else if (S_ISLNK(sb.st_mode)) {
158 if (stat(path, &sb)) {
160 return CPIO_STAT_FAILED;
163 if (S_ISDIR(sb.st_mode))
171 if (dounlink && unlink(path)) {
172 return CPIO_UNLINK_FAILED;
176 if (mkdir(path, 000))
177 return CPIO_MKDIR_FAILED;
182 static int setInfo(struct cpioHeader * hdr) {
184 struct utimbuf stamp = { hdr->mtime, hdr->mtime };
186 if (!getuid() && !rc && chown(hdr->path, hdr->uid, hdr->gid))
187 rc = CPIO_CHOWN_FAILED;
189 if (!S_ISLNK(hdr->mode)) {
190 if (!rc && chmod(hdr->path, hdr->mode & 07777))
191 rc = CPIO_CHMOD_FAILED;
192 if (!rc && utime(hdr->path, &stamp))
193 rc = CPIO_UTIME_FAILED;
199 static int checkDirectory(char * filename) {
200 static char * lastDir = NULL;
201 static int lastDirLength = 0;
202 static int lastDirAlloced = 0;
203 int length = strlen(filename);
208 buf = alloca(length + 1);
209 strcpy(buf, filename);
211 for (chptr = buf + length - 1; chptr > buf; chptr--) {
212 if (*chptr == '/') break;
215 if (chptr == buf) return 0; /* /filename - no directories */
217 *chptr = '\0'; /* buffer is now just directories */
219 length = strlen(buf);
220 if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
222 if (lastDirAlloced < (length + 1)) {
223 lastDirAlloced = length + 100;
224 lastDir = realloc(lastDir, lastDirAlloced);
227 strcpy(lastDir, buf);
228 lastDirLength = length;
230 for (chptr = buf + 1; *chptr; chptr++) {
233 rc = createDirectory(buf);
238 rc = createDirectory(buf);
243 static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr) {
247 int left = hdr->size;
250 if (!access(hdr->path, X_OK))
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;
259 bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
260 if (bytesRead <= 0) {
261 rc = CPIO_READ_FAILED;
265 if (write(out, buf, bytesRead) != bytesRead) {
266 rc = CPIO_READ_FAILED;
278 static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
281 if (!access(hdr->path, X_OK))
282 if (unlink(hdr->path))
283 return CPIO_UNLINK_FAILED;
285 if ((hdr->size + 1)> sizeof(buf))
286 return CPIO_INTERNAL;
288 if (ourread(fd, buf, hdr->size) != hdr->size)
289 return CPIO_READ_FAILED;
291 buf[hdr->size] = '\0';
293 if (symlink(buf, hdr->path))
294 return CPIO_SYMLINK_FAILED;
299 static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
302 if (!access(hdr->path, X_OK)) {
303 if (lstat(hdr->path, &sb))
304 return CPIO_STAT_FAILED;
306 if (S_ISFIFO(sb.st_mode)) return 0;
308 if (unlink(hdr->path))
309 return CPIO_UNLINK_FAILED;
312 if (mkfifo(hdr->path, 0))
313 return CPIO_MKFIFO_FAILED;
318 static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
319 if (!access(hdr->path, X_OK))
320 if (unlink(hdr->path))
321 return CPIO_UNLINK_FAILED;
323 if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
324 return CPIO_MKNOD_FAILED;
329 int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
330 int numMappings, cpioCallback cb, char ** failedFile) {
331 struct cpioHeader ch;
334 struct cpioFileMapping * map = NULL;
335 struct cpioFileMapping needle;
343 if ((rc = getNextHeader(&fd, &ch))) {
344 printf("error %d reading header: %s\n", rc, strerror(errno));
348 if (!strcmp(ch.path, TRAILER)) {
354 needle.archivePath = ch.path;
355 map = bsearch(&needle, mappings, numMappings, sizeof(needle),
359 if (!mappings || map) {
363 if (map->mapFlags & CPIO_MAP_PATH) {
365 ch.path = strdup(map->finalPath);
368 if (map->mapFlags & CPIO_MAP_MODE)
369 ch.mode = map->finalMode;
370 if (map->mapFlags & CPIO_MAP_UID)
371 ch.uid = map->finalUid;
372 if (map->mapFlags & CPIO_MAP_GID)
373 ch.gid = map->finalGid;
376 rc = checkDirectory(ch.path);
379 if (S_ISREG(ch.mode))
380 rc = expandRegular(&fd, &ch);
381 else if (S_ISDIR(ch.mode))
382 rc = createDirectory(ch.path);
383 else if (S_ISLNK(ch.mode))
384 rc = expandSymlink(&fd, &ch);
385 else if (S_ISFIFO(ch.mode))
386 rc = expandFifo(&fd, &ch);
387 else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
388 rc = expandDevice(&fd, &ch);
389 else if (S_ISSOCK(ch.mode)) {
390 /* should we do something here??? */
401 *failedFile = strdup(ch.path);