1997-05-07 07:54:28 +08:00
|
|
|
#include "config.h"
|
1997-05-20 23:57:39 +08:00
|
|
|
#include "miscfn.h"
|
1997-05-07 07:54:28 +08:00
|
|
|
|
|
|
|
#if HAVE_ALLOCA_H
|
|
|
|
# include <alloca.h>
|
|
|
|
#endif
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
1998-03-05 00:52:59 +08:00
|
|
|
#include <sys/stat.h>
|
1997-05-06 04:46:58 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <utime.h>
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
#include "cpio.h"
|
1997-05-06 04:46:58 +08:00
|
|
|
|
|
|
|
#if MAJOR_IN_SYSMACROS
|
|
|
|
#include <sys/sysmacros.h>
|
|
|
|
#elif MAJOR_IN_MKDEV
|
|
|
|
#include <sys/mkdev.h>
|
|
|
|
#endif
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
#define CPIO_NEWC_MAGIC "070701"
|
1997-01-04 10:48:55 +08:00
|
|
|
#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! */
|
|
|
|
|
1997-05-07 01:38:05 +08:00
|
|
|
struct hardLink {
|
1997-07-24 02:07:46 +08:00
|
|
|
struct hardLink * next;
|
|
|
|
char ** files; /* there are nlink of these, used by install */
|
|
|
|
int * fileMaps; /* used by build */
|
1997-05-07 01:38:05 +08:00
|
|
|
dev_t dev;
|
|
|
|
ino_t inode;
|
|
|
|
int nlink;
|
|
|
|
int linksLeft;
|
|
|
|
int createdPath;
|
1997-07-24 02:07:46 +08:00
|
|
|
struct stat sb;
|
1997-05-07 01:38:05 +08:00
|
|
|
};
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
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;
|
1997-05-06 04:46:58 +08:00
|
|
|
char * path;
|
1997-01-04 10:48:55 +08:00
|
|
|
};
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static inline off_t saferead(CFD_t *cfd, void * vbuf, size_t amount) {
|
|
|
|
off_t rc = 0;
|
|
|
|
char * buf = vbuf;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
while (amount > 0) {
|
|
|
|
size_t nb;
|
|
|
|
switch (cfd->cpioIoType) {
|
|
|
|
default:
|
|
|
|
#ifdef PARANOID
|
|
|
|
fprintf(stderr, "\tsaferead(%x,%x,%x)\n", cfd, vbuf, amount);
|
|
|
|
exit(1);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case cpioIoTypeDebug:
|
|
|
|
nb = amount;
|
|
|
|
fprintf(stderr, "\tsaferead(%x,%x,%x)\n", cfd, vbuf, amount);
|
|
|
|
break;
|
|
|
|
case cpioIoTypeFd:
|
|
|
|
nb = read(cfd->cpioFd, buf, amount);
|
|
|
|
break;
|
|
|
|
case cpioIoTypeFp:
|
|
|
|
nb = fread(buf, amount, 1, cfd->cpioFp);
|
|
|
|
if (nb)
|
|
|
|
nb *= amount;
|
|
|
|
break;
|
|
|
|
case cpioIoTypeGzFd:
|
|
|
|
nb = gzread(cfd->cpioGzFd, buf, amount);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nb <= 0)
|
|
|
|
return nb;
|
|
|
|
rc += nb;
|
|
|
|
if (rc >= amount)
|
|
|
|
break;
|
|
|
|
buf += nb;
|
|
|
|
amount -= nb;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline off_t ourread(CFD_t * cfd, void * buf, size_t size) {
|
|
|
|
off_t i = saferead(cfd, buf, size);
|
|
|
|
if (i > 0)
|
|
|
|
cfd->cpioPos += i;
|
1997-01-04 10:48:55 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static inline void padinfd(CFD_t * cfd, int modulo) {
|
1997-01-04 10:48:55 +08:00
|
|
|
int buf[10];
|
|
|
|
int amount;
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
amount = (modulo - cfd->cpioPos % modulo) % modulo;
|
|
|
|
ourread(cfd, buf, amount);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static inline off_t safewrite(CFD_t *cfd, void * vbuf, size_t amount) {
|
|
|
|
off_t rc = 0;
|
1997-07-24 02:07:46 +08:00
|
|
|
char * buf = vbuf;
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
while (amount > 0) {
|
|
|
|
size_t nb;
|
|
|
|
switch (cfd->cpioIoType) {
|
|
|
|
default:
|
|
|
|
#ifdef PARANOID
|
|
|
|
fprintf(stderr, "\tsafewrite(%x,%x,%x)\n", cfd, vbuf, amount);
|
|
|
|
exit(1);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case cpioIoTypeDebug:
|
|
|
|
nb = amount;
|
|
|
|
fprintf(stderr, "\tsafewrite(%x,%x,%x)\n", cfd, vbuf, amount);
|
|
|
|
break;
|
|
|
|
case cpioIoTypeFd:
|
|
|
|
nb = write(cfd->cpioFd, buf, amount);
|
|
|
|
break;
|
|
|
|
case cpioIoTypeFp:
|
|
|
|
nb = fwrite(buf, amount, 1, cfd->cpioFp);
|
|
|
|
if (nb)
|
|
|
|
nb *= amount;
|
|
|
|
break;
|
|
|
|
case cpioIoTypeGzFd:
|
|
|
|
nb = gzwrite(cfd->cpioGzFd, buf, amount);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nb <= 0)
|
|
|
|
return nb;
|
|
|
|
rc += nb;
|
|
|
|
if (rc >= amount)
|
|
|
|
break;
|
|
|
|
buf += nb;
|
|
|
|
amount -= nb;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
return rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static inline int padoutfd(CFD_t * cfd, size_t * where, int modulo) {
|
|
|
|
static int buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1997-07-24 02:07:46 +08:00
|
|
|
int amount;
|
|
|
|
|
|
|
|
amount = (modulo - *where % modulo) % modulo;
|
|
|
|
*where += amount;
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if (safewrite(cfd, buf, amount) != amount)
|
1997-07-24 02:07:46 +08:00
|
|
|
return CPIO_WRITE_FAILED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
static int strntoul(const char * str, char ** endptr, int base, int num) {
|
1998-03-28 01:23:20 +08:00
|
|
|
char * buf, * end;
|
1998-03-28 01:41:19 +08:00
|
|
|
unsigned long ret;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
buf = alloca(num + 1);
|
|
|
|
strncpy(buf, str, num);
|
|
|
|
buf[num] = '\0';
|
|
|
|
|
1998-03-28 01:23:20 +08:00
|
|
|
ret = strtoul(buf, &end, base);
|
|
|
|
if (*end)
|
|
|
|
*endptr = str + (end - buf);
|
|
|
|
else
|
|
|
|
*endptr = "";
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
return strtoul(buf, endptr, base);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define GET_NUM_FIELD(phys, log) \
|
|
|
|
log = strntoul(phys, &end, 16, sizeof(phys)); \
|
1997-05-06 04:46:58 +08:00
|
|
|
if (*end) return CPIO_BAD_HEADER;
|
1997-07-24 02:07:46 +08:00
|
|
|
#define SET_NUM_FIELD(phys, val, space) \
|
|
|
|
sprintf(space, "%8.8lx", (unsigned long) (val)); \
|
|
|
|
memcpy(phys, space, 8);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int getNextHeader(CFD_t * cfd, struct cpioHeader * chPtr) {
|
1997-01-04 10:48:55 +08:00
|
|
|
struct cpioCrcPhysicalHeader physHeader;
|
|
|
|
int nameSize;
|
|
|
|
char * end;
|
|
|
|
int major, minor;
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if (ourread(cfd, &physHeader, sizeof(physHeader)) != sizeof(physHeader))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC)) &&
|
|
|
|
strncmp(CPIO_NEWC_MAGIC, physHeader.magic, strlen(CPIO_NEWC_MAGIC)))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_BAD_MAGIC;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
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);
|
1997-05-06 04:46:58 +08:00
|
|
|
chPtr->dev = makedev(major, minor);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
GET_NUM_FIELD(physHeader.rdevMajor, major);
|
|
|
|
GET_NUM_FIELD(physHeader.rdevMinor, minor);
|
1997-05-06 04:46:58 +08:00
|
|
|
chPtr->rdev = makedev(major, minor);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
GET_NUM_FIELD(physHeader.namesize, nameSize);
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
chPtr->path = malloc(nameSize + 1);
|
1998-07-25 23:33:15 +08:00
|
|
|
if (ourread(cfd, chPtr->path, nameSize) != nameSize) {
|
1997-01-04 10:48:55 +08:00
|
|
|
free(chPtr->path);
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_BAD_HEADER;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
/* this is unecessary chPtr->path[nameSize] = '\0'; */
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
padinfd(cfd, 4);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
int cpioFileMapCmp(const void * a, const void * b) {
|
1997-01-04 10:48:55 +08:00
|
|
|
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 */
|
1997-05-15 02:32:18 +08:00
|
|
|
static int createDirectory(char * path, mode_t perms) {
|
1997-01-04 10:48:55 +08:00
|
|
|
struct stat sb;
|
1997-05-06 04:46:58 +08:00
|
|
|
int dounlink;
|
|
|
|
|
1997-05-06 23:27:46 +08:00
|
|
|
if (!lstat(path, &sb)) {
|
1997-01-04 10:48:55 +08:00
|
|
|
if (S_ISDIR(sb.st_mode)) {
|
|
|
|
return 0;
|
|
|
|
} else if (S_ISLNK(sb.st_mode)) {
|
|
|
|
if (stat(path, &sb)) {
|
|
|
|
if (errno != ENOENT)
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_STAT_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
dounlink = 1;
|
|
|
|
} else {
|
|
|
|
if (S_ISDIR(sb.st_mode))
|
|
|
|
return 0;
|
|
|
|
dounlink = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dounlink = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dounlink && unlink(path)) {
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_UNLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mkdir(path, 000))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_MKDIR_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-05-15 02:32:18 +08:00
|
|
|
if (chmod(path, perms))
|
|
|
|
return CPIO_CHMOD_FAILED;
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
static int setInfo(struct cpioHeader * hdr) {
|
1997-01-04 10:48:55 +08:00
|
|
|
int rc = 0;
|
1998-03-05 00:52:59 +08:00
|
|
|
struct utimbuf stamp;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-03-05 00:52:59 +08:00
|
|
|
stamp.actime = hdr->mtime;
|
|
|
|
stamp.modtime = hdr->mtime;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
if (!S_ISLNK(hdr->mode)) {
|
1997-07-16 09:56:14 +08:00
|
|
|
if (!getuid() && chown(hdr->path, hdr->uid, hdr->gid))
|
1997-05-15 23:19:56 +08:00
|
|
|
rc = CPIO_CHOWN_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
if (!rc && chmod(hdr->path, hdr->mode & 07777))
|
1997-05-06 04:46:58 +08:00
|
|
|
rc = CPIO_CHMOD_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
if (!rc && utime(hdr->path, &stamp))
|
1997-05-06 04:46:58 +08:00
|
|
|
rc = CPIO_UTIME_FAILED;
|
1997-05-15 23:19:56 +08:00
|
|
|
} else {
|
1998-03-05 00:52:59 +08:00
|
|
|
# if ! CHOWN_FOLLOWS_SYMLINK
|
1997-05-20 23:28:25 +08:00
|
|
|
if (!getuid() && !rc && lchown(hdr->path, hdr->uid, hdr->gid))
|
1997-05-15 23:19:56 +08:00
|
|
|
rc = CPIO_CHOWN_FAILED;
|
1998-03-05 00:52:59 +08:00
|
|
|
# endif
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
static int checkDirectory(char * filename) {
|
|
|
|
static char * lastDir = NULL;
|
1997-01-04 10:48:55 +08:00
|
|
|
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;
|
1997-05-06 04:46:58 +08:00
|
|
|
lastDir = realloc(lastDir, lastDirAlloced);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(lastDir, buf);
|
|
|
|
lastDirLength = length;
|
|
|
|
|
|
|
|
for (chptr = buf + 1; *chptr; chptr++) {
|
|
|
|
if (*chptr == '/') {
|
|
|
|
*chptr = '\0';
|
1997-05-15 02:32:18 +08:00
|
|
|
rc = createDirectory(buf, 0755);
|
1997-01-04 10:48:55 +08:00
|
|
|
*chptr = '/';
|
|
|
|
if (rc) return rc;
|
|
|
|
}
|
|
|
|
}
|
1997-05-15 02:32:18 +08:00
|
|
|
rc = createDirectory(buf, 0755);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int expandRegular(CFD_t * cfd, struct cpioHeader * hdr,
|
1997-05-06 23:27:46 +08:00
|
|
|
cpioCallback cb, void * cbData) {
|
1997-05-06 04:46:58 +08:00
|
|
|
int out;
|
1997-05-06 23:27:46 +08:00
|
|
|
char buf[8192];
|
1997-01-04 10:48:55 +08:00
|
|
|
int bytesRead;
|
|
|
|
int left = hdr->size;
|
|
|
|
int rc = 0;
|
1997-05-06 23:27:46 +08:00
|
|
|
struct cpioCallbackInfo cbInfo;
|
|
|
|
struct stat sb;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-05-06 23:27:46 +08:00
|
|
|
if (!lstat(hdr->path, &sb))
|
1997-05-06 04:46:58 +08:00
|
|
|
if (unlink(hdr->path))
|
|
|
|
return CPIO_UNLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
out = open(hdr->path, O_CREAT | O_WRONLY, 0);
|
|
|
|
if (out < 0)
|
|
|
|
return CPIO_OPEN_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-05-06 23:27:46 +08:00
|
|
|
cbInfo.file = hdr->path;
|
|
|
|
cbInfo.fileSize = hdr->size;
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
while (left) {
|
1998-07-25 23:33:15 +08:00
|
|
|
bytesRead = ourread(cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
|
1997-01-04 10:48:55 +08:00
|
|
|
if (bytesRead <= 0) {
|
1997-05-06 04:46:58 +08:00
|
|
|
rc = CPIO_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
if (write(out, buf, bytesRead) != bytesRead) {
|
|
|
|
rc = CPIO_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
left -= bytesRead;
|
1997-05-06 23:27:46 +08:00
|
|
|
|
|
|
|
/* don't call this with fileSize == fileComplete */
|
|
|
|
if (!rc && cb && left) {
|
|
|
|
cbInfo.fileComplete = hdr->size - left;
|
1998-07-25 23:33:15 +08:00
|
|
|
cbInfo.bytesProcessed = cfd->cpioPos;
|
1997-05-06 23:27:46 +08:00
|
|
|
cb(&cbInfo, cbData);
|
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
close(out);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int expandSymlink(CFD_t * cfd, struct cpioHeader * hdr) {
|
1997-07-16 09:56:14 +08:00
|
|
|
char buf[2048], buf2[2048];
|
1997-05-06 23:27:46 +08:00
|
|
|
struct stat sb;
|
1997-07-16 09:56:14 +08:00
|
|
|
int len;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
if ((hdr->size + 1)> sizeof(buf))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_INTERNAL;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if (ourread(cfd, buf, hdr->size) != hdr->size)
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
buf[hdr->size] = '\0';
|
|
|
|
|
1997-07-16 09:56:14 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1997-07-16 09:38:55 +08:00
|
|
|
if (symlink(buf, hdr->path) < 0)
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_SYMLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int expandFifo(CFD_t * cfd, struct cpioHeader * hdr) {
|
1997-01-04 10:48:55 +08:00
|
|
|
struct stat sb;
|
|
|
|
|
1997-05-06 23:27:46 +08:00
|
|
|
if (!lstat(hdr->path, &sb)) {
|
1997-01-04 10:48:55 +08:00
|
|
|
if (S_ISFIFO(sb.st_mode)) return 0;
|
|
|
|
|
|
|
|
if (unlink(hdr->path))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_UNLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mkfifo(hdr->path, 0))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_MKFIFO_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int expandDevice(CFD_t * cfd, struct cpioHeader * hdr) {
|
1997-05-06 23:27:46 +08:00
|
|
|
struct stat sb;
|
|
|
|
|
1997-07-16 09:56:14 +08:00
|
|
|
if (!lstat(hdr->path, &sb)) {
|
|
|
|
if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) &&
|
|
|
|
(sb.st_rdev == hdr->rdev))
|
|
|
|
return 0;
|
1997-01-04 10:48:55 +08:00
|
|
|
if (unlink(hdr->path))
|
1997-05-06 04:46:58 +08:00
|
|
|
return CPIO_UNLINK_FAILED;
|
1997-07-16 09:56:14 +08:00
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
|
|
|
|
return CPIO_MKNOD_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1997-05-07 01:38:05 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int eatBytes(CFD_t * cfd, int amount) {
|
1997-05-23 23:18:15 +08:00
|
|
|
char buf[4096];
|
|
|
|
int bite;
|
|
|
|
|
|
|
|
while (amount) {
|
|
|
|
bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
|
1998-07-25 23:33:15 +08:00
|
|
|
if (ourread(cfd, buf, bite) != bite)
|
1997-05-23 23:18:15 +08:00
|
|
|
return CPIO_READ_FAILED;
|
|
|
|
amount -= bite;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
int cpioInstallArchive(CFD_t *cfd, struct cpioFileMapping * mappings,
|
1997-05-06 23:27:46 +08:00
|
|
|
int numMappings, cpioCallback cb, void * cbData,
|
|
|
|
char ** failedFile) {
|
1997-01-04 10:48:55 +08:00
|
|
|
struct cpioHeader ch;
|
|
|
|
int rc = 0;
|
1997-05-07 01:38:05 +08:00
|
|
|
int linkNum = 0;
|
1997-01-04 10:48:55 +08:00
|
|
|
struct cpioFileMapping * map = NULL;
|
|
|
|
struct cpioFileMapping needle;
|
|
|
|
mode_t cpioMode;
|
|
|
|
int olderr;
|
1997-05-06 23:27:46 +08:00
|
|
|
struct cpioCallbackInfo cbInfo;
|
1997-05-07 01:38:05 +08:00
|
|
|
struct hardLink * links = NULL;
|
|
|
|
struct hardLink * li = NULL;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
cfd->cpioPos = 0;
|
1997-05-07 01:38:05 +08:00
|
|
|
*failedFile = NULL;
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
do {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = getNextHeader(cfd, &ch))) {
|
1997-05-06 04:46:58 +08:00
|
|
|
printf("error %d reading header: %s\n", rc, strerror(errno));
|
|
|
|
exit(1);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(ch.path, TRAILER)) {
|
1997-05-06 04:46:58 +08:00
|
|
|
free(ch.path);
|
1997-01-04 10:48:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mappings) {
|
|
|
|
needle.archivePath = ch.path;
|
|
|
|
map = bsearch(&needle, mappings, numMappings, sizeof(needle),
|
|
|
|
cpioFileMapCmp);
|
|
|
|
}
|
|
|
|
|
1997-05-23 23:18:15 +08:00
|
|
|
if (mappings && !map) {
|
1998-07-25 23:33:15 +08:00
|
|
|
eatBytes(cfd, ch.size);
|
1997-05-23 23:18:15 +08:00
|
|
|
} else {
|
1997-01-04 10:48:55 +08:00
|
|
|
cpioMode = ch.mode;
|
|
|
|
|
|
|
|
if (map) {
|
|
|
|
if (map->mapFlags & CPIO_MAP_PATH) {
|
1997-05-06 04:46:58 +08:00
|
|
|
free(ch.path);
|
1997-07-24 02:07:46 +08:00
|
|
|
ch.path = strdup(map->fsPath);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1997-05-07 01:38:05 +08:00
|
|
|
/* This won't get hard linked symlinks right, but I can't seem
|
|
|
|
to create those anyway */
|
|
|
|
|
1997-08-25 22:38:48 +08:00
|
|
|
if (S_ISREG(ch.mode) && ch.nlink > 1) {
|
1997-05-07 01:38:05 +08:00
|
|
|
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;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
1997-05-07 01:38:05 +08:00
|
|
|
|
|
|
|
for (linkNum = 0; linkNum < li->nlink; linkNum++)
|
|
|
|
if (!li->files[linkNum]) break;
|
|
|
|
li->files[linkNum] = strdup(ch.path);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
1997-05-07 01:38:05 +08:00
|
|
|
|
|
|
|
if ((ch.nlink > 1) && S_ISREG(ch.mode) && !ch.size &&
|
|
|
|
li->createdPath == -1) {
|
|
|
|
/* defer file creation */
|
1997-08-26 01:45:30 +08:00
|
|
|
} else if ((ch.nlink > 1) && S_ISREG(ch.mode) &&
|
|
|
|
(li->createdPath != -1)) {
|
1997-05-07 01:38:05 +08:00
|
|
|
createLinks(li, failedFile);
|
1997-07-24 02:07:46 +08:00
|
|
|
|
|
|
|
/* 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 */
|
1998-07-25 23:33:15 +08:00
|
|
|
if (ch.size) eatBytes(cfd, ch.size);
|
1997-05-07 01:38:05 +08:00
|
|
|
} else {
|
|
|
|
rc = checkDirectory(ch.path);
|
|
|
|
|
|
|
|
if (!rc) {
|
|
|
|
if (S_ISREG(ch.mode))
|
1998-07-25 23:33:15 +08:00
|
|
|
rc = expandRegular(cfd, &ch, cb, cbData);
|
1997-05-07 01:38:05 +08:00
|
|
|
else if (S_ISDIR(ch.mode))
|
1997-05-15 02:32:18 +08:00
|
|
|
rc = createDirectory(ch.path, 000);
|
1997-05-07 01:38:05 +08:00
|
|
|
else if (S_ISLNK(ch.mode))
|
1998-07-25 23:33:15 +08:00
|
|
|
rc = expandSymlink(cfd, &ch);
|
1997-05-07 01:38:05 +08:00
|
|
|
else if (S_ISFIFO(ch.mode))
|
1998-07-25 23:33:15 +08:00
|
|
|
rc = expandFifo(cfd, &ch);
|
1997-05-07 01:38:05 +08:00
|
|
|
else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
|
1998-07-25 23:33:15 +08:00
|
|
|
rc = expandDevice(cfd, &ch);
|
1997-05-07 01:38:05 +08:00
|
|
|
else if (S_ISSOCK(ch.mode)) {
|
|
|
|
/* this mimicks cpio but probably isnt' right */
|
1998-07-25 23:33:15 +08:00
|
|
|
rc = expandFifo(cfd, &ch);
|
1997-05-07 01:38:05 +08:00
|
|
|
} else {
|
|
|
|
rc = CPIO_INTERNAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
rc = setInfo(&ch);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-08-25 22:38:48 +08:00
|
|
|
if (S_ISREG(ch.mode) && ch.nlink > 1) {
|
1997-05-07 01:38:05 +08:00
|
|
|
li->createdPath = linkNum;
|
|
|
|
li->linksLeft--;
|
|
|
|
rc = createLinks(li, failedFile);
|
|
|
|
}
|
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-05-07 01:38:05 +08:00
|
|
|
if (rc && !*failedFile) {
|
1997-05-06 04:46:58 +08:00
|
|
|
*failedFile = strdup(ch.path);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
olderr = errno;
|
|
|
|
unlink(ch.path);
|
|
|
|
errno = olderr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
padinfd(cfd, 4);
|
1997-05-06 23:27:46 +08:00
|
|
|
|
|
|
|
if (!rc && cb) {
|
|
|
|
cbInfo.file = ch.path;
|
|
|
|
cbInfo.fileSize = ch.size;
|
|
|
|
cbInfo.fileComplete = ch.size;
|
1998-07-25 23:33:15 +08:00
|
|
|
cbInfo.bytesProcessed = cfd->cpioPos;
|
1997-05-06 23:27:46 +08:00
|
|
|
cb(&cbInfo, cbData);
|
|
|
|
}
|
|
|
|
|
1997-05-06 04:46:58 +08:00
|
|
|
free(ch.path);
|
1997-01-04 10:48:55 +08:00
|
|
|
} while (1 && !rc);
|
|
|
|
|
1997-05-07 01:38:05 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
return rc;
|
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int writeFile(CFD_t *cfd, struct stat sb, struct cpioFileMapping * map,
|
1997-07-24 02:07:46 +08:00
|
|
|
size_t * sizeptr, int writeData) {
|
|
|
|
struct cpioCrcPhysicalHeader hdr;
|
|
|
|
char buf[8192], symbuf[2048];
|
|
|
|
dev_t num;
|
|
|
|
int datafd;
|
1997-07-25 21:57:17 +08:00
|
|
|
size_t size, amount = 0;
|
1997-07-24 02:07:46 +08:00
|
|
|
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;
|
|
|
|
|
1997-07-31 22:04:56 +08:00
|
|
|
if (!writeData || S_ISDIR(sb.st_mode)) {
|
1997-07-24 02:07:46 +08:00
|
|
|
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);
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, &hdr, sizeof(hdr))) != sizeof(hdr))
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, map->archivePath, num)) != num)
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
size = sizeof(hdr) + num;
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = padoutfd(cfd, &size, 4)))
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (writeData && S_ISREG(sb.st_mode)) {
|
|
|
|
/* FIXME: we should use mmap here if it's available */
|
1997-10-14 00:39:27 +08:00
|
|
|
if ((datafd = open(map->fsPath, O_RDONLY)) < 0)
|
1997-07-24 02:07:46 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, buf, amount)) != amount) {
|
1997-07-24 02:07:46 +08:00
|
|
|
olderrno = errno;
|
|
|
|
close(datafd);
|
|
|
|
errno = olderrno;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
sb.st_size -= amount;
|
|
|
|
}
|
1997-08-01 00:02:19 +08:00
|
|
|
|
|
|
|
close(datafd);
|
1997-07-24 02:07:46 +08:00
|
|
|
} else if (writeData && S_ISLNK(sb.st_mode)) {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, symbuf, amount)) != amount)
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
size += amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this is a noop for most file types */
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = padoutfd(cfd, &size, 4)))
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
*sizeptr = size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
static int writeLinkedFile(CFD_t *cfd, struct hardLink * hlink,
|
1997-07-24 02:07:46 +08:00
|
|
|
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--) {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = writeFile(cfd, hlink->sb, mappings + hlink->fileMaps[i],
|
1997-07-24 02:07:46 +08:00
|
|
|
&size, 0))) {
|
|
|
|
if (failedFile) *failedFile =
|
|
|
|
mappings[hlink->fileMaps[i]].fsPath;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
*sizeptr += size;
|
|
|
|
|
|
|
|
if (cb) {
|
|
|
|
cbinfo.file = mappings[i].archivePath;
|
|
|
|
cb(&cbinfo, cbData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = writeFile(cfd, hlink->sb,
|
1997-07-24 02:07:46 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
1997-08-01 00:25:34 +08:00
|
|
|
return 0;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
int cpioBuildArchive(CFD_t *cfd, struct cpioFileMapping * mappings,
|
1997-07-24 02:07:46 +08:00
|
|
|
int numMappings, cpioCallback cb, void * cbData,
|
1997-08-25 22:38:48 +08:00
|
|
|
unsigned int * archiveSize, char ** failedFile) {
|
1997-07-24 02:07:46 +08:00
|
|
|
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;
|
|
|
|
|
1997-07-31 22:04:56 +08:00
|
|
|
hlinkList.next = NULL;
|
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
for (i = 0; i < numMappings; i++) {
|
1997-07-31 22:04:56 +08:00
|
|
|
if (mappings[i].mapFlags & CPIO_FOLLOW_SYMLINKS)
|
|
|
|
rc = stat(mappings[i].fsPath, &sb);
|
|
|
|
else
|
|
|
|
rc = lstat(mappings[i].fsPath, &sb);
|
|
|
|
|
1997-08-01 00:02:19 +08:00
|
|
|
if (rc) {
|
|
|
|
if (failedFile) *failedFile = mappings[i].fsPath;
|
1997-07-24 02:07:46 +08:00
|
|
|
return CPIO_STAT_FAILED;
|
1997-08-01 00:02:19 +08:00
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1997-07-31 22:04:56 +08:00
|
|
|
if (!S_ISDIR(sb.st_mode) && sb.st_nlink > 1) {
|
1997-07-24 02:07:46 +08:00
|
|
|
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) {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
|
1997-07-24 02:07:46 +08:00
|
|
|
&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 {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = writeFile(cfd, sb, mappings + i, &size, 1))) {
|
1997-07-24 02:07:46 +08:00
|
|
|
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) {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
|
1997-07-24 02:07:46 +08:00
|
|
|
&size, failedFile)))
|
|
|
|
return rc;
|
|
|
|
free(hlink->fileMaps);
|
|
|
|
parent = hlink;
|
|
|
|
hlink = hlink->next;
|
|
|
|
free(parent);
|
1997-10-04 00:08:20 +08:00
|
|
|
|
|
|
|
totalsize += size;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&hdr, '0', sizeof(hdr));
|
|
|
|
memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
|
|
|
|
memcpy(hdr.nlink, "00000001", 8);
|
|
|
|
memcpy(hdr.namesize, "0000000b", 8);
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, &hdr, sizeof(hdr))) != sizeof(hdr))
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, "TRAILER!!!", 11)) != 11)
|
1997-07-24 02:07:46 +08:00
|
|
|
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 */
|
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = padoutfd(cfd, &totalsize, 4)))
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
|
1997-08-25 22:38:48 +08:00
|
|
|
if (archiveSize) *archiveSize = totalsize;
|
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|