struct stat sb;
int dounlink;
- if (!access(path, X_OK)) {
- if (lstat(path, &sb))
- return CPIO_STAT_FAILED;
-
+ if (!lstat(path, &sb)) {
if (S_ISDIR(sb.st_mode)) {
return 0;
} else if (S_ISLNK(sb.st_mode)) {
return rc;
}
-static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr) {
+static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr,
+ cpioCallback cb, void * cbData) {
int out;
- char buf[16384];
+ char buf[8192];
int bytesRead;
int left = hdr->size;
int rc = 0;
+ struct cpioCallbackInfo cbInfo;
+ struct stat sb;
- if (!access(hdr->path, X_OK))
+ if (!lstat(hdr->path, &sb))
if (unlink(hdr->path))
return CPIO_UNLINK_FAILED;
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) {
}
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);
static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
char buf[2048];
+ struct stat sb;
- if (!access(hdr->path, X_OK))
+ if (!lstat(hdr->path, &sb))
if (unlink(hdr->path))
return CPIO_UNLINK_FAILED;
static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
struct stat sb;
- if (!access(hdr->path, X_OK)) {
- if (lstat(hdr->path, &sb))
- return CPIO_STAT_FAILED;
-
+ if (!lstat(hdr->path, &sb)) {
if (S_ISFIFO(sb.st_mode)) return 0;
if (unlink(hdr->path))
}
static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
- if (!access(hdr->path, X_OK))
+ struct stat sb;
+
+ if (!lstat(hdr->path, &sb))
if (unlink(hdr->path))
return CPIO_UNLINK_FAILED;
}
int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
- int numMappings, cpioCallback cb, char ** failedFile) {
+ int numMappings, cpioCallback cb, void * cbData,
+ char ** failedFile) {
struct cpioHeader ch;
struct ourfd fd;
int rc = 0;
struct cpioFileMapping needle;
mode_t cpioMode;
int olderr;
+ struct cpioCallbackInfo cbInfo;
fd.fd = stream;
fd.pos = 0;
if (!rc) {
if (S_ISREG(ch.mode))
- rc = expandRegular(&fd, &ch);
+ rc = expandRegular(&fd, &ch, cb, cbData);
else if (S_ISDIR(ch.mode))
rc = createDirectory(ch.path);
else if (S_ISLNK(ch.mode))
}
padfd(&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);
int mapFlags;
};
-typedef void (*cpioCallback)(char * filespec);
+struct cpioCallbackInfo {
+ char * file;
+ long fileSize; /* total file size */
+ long fileComplete; /* amount of file unpacked */
+ long bytesProcessed; /* bytes in archive read */
+};
+
+typedef void (*cpioCallback)(struct cpioCallbackInfo * filespec, void * data);
/* If no mappings are passed, this installs everything! If one is passed
it should be sorted according to cpioFileMapCmp() and only files included
for the file type. The owner/group mappings are ignored for the nonroot
user. If *failedFile is non-NULL on return, it should be free()d. */
int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
- int numMappings, cpioCallback cb, char ** failedFile);
+ int numMappings, cpioCallback cb, void * cbData,
+ char ** failedFile);
/* This is designed to be qsort/bsearch compatible */
int cpioFileMapCmp(const void * a, const void * b);
enum instActions { UNKNOWN, CREATE, BACKUP, KEEP, SAVE, SKIP };
enum fileTypes { XDIR, BDEV, CDEV, SOCK, PIPE, REG, LINK } ;
+struct callbackInfo {
+ unsigned long archiveSize;
+ rpmNotifyFunction notify;
+};
+
struct fileMemory {
char ** md5s;
char ** links;
return 0;
}
-#define BLOCKSIZE 1024
+static void callback(struct cpioCallbackInfo * cpioInfo, void * data) {
+ struct callbackInfo * ourInfo = data;
+
+ ourInfo->notify(cpioInfo->bytesProcessed, ourInfo->archiveSize);
+}
/* NULL files means install all files */
static int installArchive(char * prefix, int fd, struct fileInfo * files,
int rc, i;
struct cpioFileMapping * map;
char * failedFile;
+ struct callbackInfo info;
if (!files) {
/* install all files */
return 0;
}
+ info.archiveSize = archiveSize;
+ info.notify = notify;
+
if (specFile) *specFile = NULL;
map = alloca(sizeof(*map) * fileCount);
qsort(map, fileCount, sizeof(*map), cpioFileMapCmp);
stream = gzdopen(fd, "r");
- rc = cpioInstallArchive(stream, map, fileCount, NULL, &failedFile);
+ rc = cpioInstallArchive(stream, map, fileCount,
+ (notify && archiveSize) ? callback : NULL,
+ &info, &failedFile);
if (rc) {
/* this would probably be a good place to check if disk space
was used up - if so, we should return a different error */
- rpmError(RPMERR_CPIO, "unpacking of archive failed on file %s: %d",
- failedFile, rc);
+ rpmError(RPMERR_CPIO, "unpacking of archive failed on file %s: %d: %s",
+ failedFile, rc, strerror(errno));
return 1;
}
- if (notify)
+ if (notify && archiveSize)
notify(archiveSize, archiveSize);
+ else if (notify) {
+ notify(100, 100);
+ }
return 0;
}