Doesn't use cpio to unpack archives anymore...
authorewt <devnull@localhost>
Mon, 5 May 1997 20:46:58 +0000 (20:46 +0000)
committerewt <devnull@localhost>
Mon, 5 May 1997 20:46:58 +0000 (20:46 +0000)
CVS patchset: 1595
CVS date: 1997/05/05 20:46:58

CHANGES
config.h.in
configure.in
lib/Makefile.in
lib/cpio.c
lib/cpio.h [new file with mode: 0644]
lib/install.c
lib/misc.c
lib/misc.h

diff --git a/CHANGES b/CHANGES
index 2ebb022..eaa2978 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -27,8 +27,9 @@
          in the path
        - use dbpath for error messages with include database path in 
          their text
-       - don't owner/group if binaries installed by "make install"
+       - don't set owner/group if binaries installed by "make install"
        - include <strings.h> on SCO
+       - don't use cpio when installing packages <gulp>
 
 2.3.10 -> 2.3.11:
        - fixed newlines in --scripts output
index 6b642e6..c988557 100644 (file)
 /* Define as one if we need to include <strings.h> (along with <string.h>) */
 #define NEED_STRINGS_H 0
 
+/* Define as one if major, minor, and makedev macros are in <sys/sysmacros.h> */
+#define MAJOR_IN_SYSMACROS 0
+
+/* Define as one if major, minor, and makedev macros are in <sys/mkdev.h> */
+#define MAJOR_IN_MKDEV 0
+
 #endif
index 0d722e6..c3cd407 100644 (file)
@@ -216,6 +216,7 @@ done
 
 dnl Checks for header files we can live without.
 AC_HEADER_STDC
+AC_HEADER_MAJOR
 AC_CHECK_HEADERS(netinet/in_systm.h)
 AC_CHECK_HEADERS(alloca.h dirent.h)
 AC_CHECK_HEADERS(machine/types.h string.h)
index ef03288..6f54a18 100644 (file)
@@ -1,11 +1,15 @@
 srcdir = @srcdir@
 VPATH = $(srcdir)
 
-LIBOBJECTS = header.o misc.o messages.o rpmerr.o falloc.o \
-            var.o md5.o md5sum.o dbindex.o rpmrc.o depends.o \
-            rpmdb.o stringbuf.o rpmlead.o package.o uninstall.o \
-            oldheader.o install.o signature.o verify.o rebuilddb.o \
-            tread.o
+LIBOBJECTS =   header.o        misc.o          messages.o      \
+               rpmerr.o        falloc.o        var.o           \
+               md5.o           md5sum.o        dbindex.o       \
+               rpmrc.o         depends.o       rpmdb.o         \
+               stringbuf.o     rpmlead.o       package.o       \
+               uninstall.o     oldheader.o     install.o       \
+               signature.o     verify.o        rebuilddb.o     \
+               tread.o         cpio.o
+
 SOURCES = $(addprefix $(srcdir)/,$(subst .o,.c,$(LIBOBJECTS))) 
 TAGTABLE = tagtable.o
 LIBRPM = librpm.a
@@ -45,10 +49,10 @@ tagtable.c: rpmlib.h
        echo 'const int rpmTagTableSize = sizeof(rpmTagTable) / sizeof(struct headerTagTableEntry) - 1;' >> tagtable.c
 
 install:
-       $(INSTALL) -m 644 -o 0 -g 0 $(srcdir)/rpmlib.h $(INCDIR)
-       $(INSTALL) -m 644 -o 0 -g 0 $(srcdir)/dbindex.h $(INCDIR)
-       $(INSTALL) -m 644 -o 0 -g 0 $(srcdir)/header.h $(INCDIR)
-       $(INSTALL) -m 644 -o 0 -g 0 librpm.a $(LIBDIR)
+       $(INSTALL) -m 644 $(srcdir)/rpmlib.h $(INCDIR)
+       $(INSTALL) -m 644 $(srcdir)/dbindex.h $(INCDIR)
+       $(INSTALL) -m 644 $(srcdir)/header.h $(INCDIR)
+       $(INSTALL) -m 644 librpm.a $(LIBDIR)
 
 distclean: clean
        rm -f .depend Makefile  
index 31b2a86..ddff7a4 100644 (file)
@@ -1,9 +1,24 @@
-#include "system.h"
-
-#include <rpmio.h>
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include "config.h"
 #include "cpio.h"
+#include "miscfn.h"
+
+#if MAJOR_IN_SYSMACROS 
+#include <sys/sysmacros.h>
+#elif MAJOR_IN_MKDEV 
+#include <sys/mkdev.h>
+#endif
 
-#define CPIO_NEWC_MAGIC        "070701"
 #define CPIO_CRC_MAGIC "070702"
 #define TRAILER                "TRAILER!!!"
 
    should both be the same, but really odd things are going to happen if
    that's not true! */
 
-struct hardLink {
-    struct hardLink * next;
-    const char ** files;       /* nlink of these, used by install */
-    int * fileMaps;            /* used by build */
-    dev_t dev;
-    ino_t inode;
-    int nlink;                 
-    int linksLeft;
-    int createdPath;
-    struct stat sb;
+/* We need to maintain our oun file pointer to allow padding */
+struct ourfd {
+    gzFile fd;
+    int pos;
 };
 
 struct cpioCrcPhysicalHeader {
@@ -40,8 +49,6 @@ struct cpioCrcPhysicalHeader {
     char checksum[8];                  /* ignored !! */
 };
 
-#define        PHYS_HDR_SIZE   110             /* don't depend on sizeof(struct) */
-
 struct cpioHeader {
     ino_t inode;
     mode_t mode;
@@ -51,119 +58,53 @@ struct cpioHeader {
     time_t mtime;
     long size;
     dev_t dev, rdev;
-    /*@owned@*/char * path;
+    char * path;
 };
 
-static inline off_t saferead(FD_t cfd, /*@out@*/void * vbuf, size_t amount)
-{
-    off_t rc = 0;
-    char * buf = vbuf;
-
-    while (amount > 0) {
-       size_t nb;
-
-       nb = Fread(buf, sizeof(buf[0]), amount, cfd);
-       if (nb <= 0)
-               return nb;
-       rc += nb;
-       if (rc >= amount)
-               break;
-       buf += nb;
-       amount -= nb;
-    }
-    return rc;
-}
+static inline loff_t ourread(struct ourfd * thefd, void * buf, size_t size) {
+    loff_t i;
 
-static inline off_t ourread(FD_t cfd, /*@out@*/void * buf, size_t size)
-{
-    off_t i = saferead(cfd, buf, size);
-    if (i > 0)
-       fdSetCpioPos(cfd, fdGetCpioPos(cfd) + i);
+    i = gzread(thefd->fd, buf, size);
+    thefd->pos += i;
+    
     return i;
 }
 
-static inline void padinfd(FD_t cfd, int modulo)
-{
+static inline void padfd(struct ourfd * fd, int modulo) {
     int buf[10];
     int amount;
     
-    amount = (modulo - fdGetCpioPos(cfd) % modulo) % modulo;
-    (void)ourread(cfd, buf, amount);
+    amount = (modulo - fd->pos % modulo) % modulo;
+    ourread(fd, buf, amount);
 }
 
-static inline off_t safewrite(FD_t cfd, const void * vbuf, size_t amount)
-{
-    off_t rc = 0;
-    const char * buf = vbuf;
-
-    while (amount > 0) {
-       size_t nb;
-
-       nb = Fwrite(buf, sizeof(buf[0]), amount, cfd);
-       if (nb <= 0)
-               return nb;
-       rc += nb;
-       if (rc >= amount)
-               break;
-       buf += nb;
-       amount -= nb;
-    }
-
-    return rc; 
-}
-
-static inline int padoutfd(FD_t cfd, size_t * where, int modulo)
-{
-    static int buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-    int amount;
-    
-    amount = (modulo - *where % modulo) % modulo;
-    *where += amount;
-
-    if (safewrite(cfd, buf, amount) != amount) 
-       return CPIOERR_WRITE_FAILED;
-    return 0;
-}
-
-static int strntoul(const char *str, /*@out@*/char **endptr, int base, int num)
-{
-    char * buf, * end;
-    unsigned long ret;
+static int strntoul(const char * str, char ** endptr, int base, int num) {
+    char * buf;
 
     buf = alloca(num + 1);
     strncpy(buf, str, num);
     buf[num] = '\0';
 
-    ret = strtoul(buf, &end, base);
-    if (*end)
-       *endptr = ((char *)str) + (end - buf);  /* XXX discards const */
-    else
-       *endptr = ((char *)str) + strlen(str);
-
     return strtoul(buf, endptr, base);
 }
 
 #define GET_NUM_FIELD(phys, log) \
        log = strntoul(phys, &end, 16, sizeof(phys)); \
-       if (*end) return CPIOERR_BAD_HEADER;
-#define SET_NUM_FIELD(phys, val, space) \
-       sprintf(space, "%8.8lx", (unsigned long) (val)); \
-       memcpy(phys, space, 8);
+       if (*end) return CPIO_BAD_HEADER;
 
-static int getNextHeader(FD_t cfd, /*@out@*/ struct cpioHeader * chPtr)
-{
+static int getNextHeader(struct ourfd * fd, struct cpioHeader * chPtr) {
     struct cpioCrcPhysicalHeader physHeader;
     int nameSize;
     char * end;
     int major, minor;
 
-    if (ourread(cfd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE
-       return CPIOERR_READ_FAILED;
+    if (ourread(fd, &physHeader, sizeof(physHeader)) != sizeof(physHeader)
+       return CPIO_READ_FAILED;
 
-    if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
-       strncmp(CPIO_NEWC_MAGIC, physHeader.magic, sizeof(CPIO_NEWC_MAGIC)-1))
-       return CPIOERR_BAD_MAGIC;
+    if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC))) 
+       return CPIO_BAD_MAGIC;
 
+    
     GET_NUM_FIELD(physHeader.inode, chPtr->inode);
     GET_NUM_FIELD(physHeader.mode, chPtr->mode);
     GET_NUM_FIELD(physHeader.uid, chPtr->uid);
@@ -174,30 +115,28 @@ static int getNextHeader(FD_t cfd, /*@out@*/ struct cpioHeader * chPtr)
 
     GET_NUM_FIELD(physHeader.devMajor, major);
     GET_NUM_FIELD(physHeader.devMinor, minor);
-    chPtr->dev = /*@-shiftsigned@*/ makedev(major, minor) /*@=shiftsigned@*/ ;
+    chPtr->dev = makedev(major, minor);
 
     GET_NUM_FIELD(physHeader.rdevMajor, major);
     GET_NUM_FIELD(physHeader.rdevMinor, minor);
-    chPtr->rdev = /*@-shiftsigned@*/ makedev(major, minor) /*@=shiftsigned@*/ ;
+    chPtr->rdev = makedev(major, minor);
 
     GET_NUM_FIELD(physHeader.namesize, nameSize);
 
-    chPtr->path = xmalloc(nameSize + 1);
-    if (ourread(cfd, chPtr->path, nameSize) != nameSize) {
+    chPtr->path = malloc(nameSize + 1);
+    if (ourread(fd, chPtr->path, nameSize) != nameSize) {
        free(chPtr->path);
-       chPtr->path = NULL;
-       return CPIOERR_BAD_HEADER;
+       return CPIO_BAD_HEADER;
     }
 
-    /* this is unecessary chPtr->path[nameSize] = '\0'; */
+    chPtr->path[nameSize] = '\0';
 
-    padinfd(cfd, 4);
+    padfd(fd, 4);
 
     return 0;
 }
 
-int cpioFileMapCmp(const void * a, const void * b)
-{
+int cpioFileMapCmp(const void * a, const void * b) {
     const struct cpioFileMapping * first = a;
     const struct cpioFileMapping * second = b;
 
@@ -205,18 +144,20 @@ int cpioFileMapCmp(const void * a, const void * b)
 }
 
 /* This could trash files in the path! I'm not sure that's a good thing */
-static int createDirectory(char * path, mode_t perms)
-{
+static int createDirectory(char * path) {
     struct stat sb;
+    int dounlink;
+
+    if (!access(path, X_OK)) {
+       if (lstat(path, &sb))
+           return CPIO_STAT_FAILED;
 
-    if (!lstat(path, &sb)) {
-       int dounlink = 0;       /* XXX eliminate, dounlink==1 on all paths */
        if (S_ISDIR(sb.st_mode)) {
            return 0;
        } else if (S_ISLNK(sb.st_mode)) {
            if (stat(path, &sb)) {
                if (errno != ENOENT) 
-                   return CPIOERR_STAT_FAILED;
+                   return CPIO_STAT_FAILED;
                dounlink = 1;
            } else {
                if (S_ISDIR(sb.st_mode))
@@ -228,47 +169,35 @@ static int createDirectory(char * path, mode_t perms)
        }
 
        if (dounlink && unlink(path)) {
-           return CPIOERR_UNLINK_FAILED;
+           return CPIO_UNLINK_FAILED;
        }
     }
 
     if (mkdir(path, 000))
-       return CPIOERR_MKDIR_FAILED;
-
-    if (chmod(path, perms))
-       return CPIOERR_CHMOD_FAILED;
+       return CPIO_MKDIR_FAILED;
 
     return 0;
 }
 
-static int setInfo(struct cpioHeader * hdr)
-{
+static int setInfo(struct cpioHeader * hdr) {
     int rc = 0;
-    struct utimbuf stamp;
+    struct utimbuf stamp = { hdr->mtime, hdr->mtime };
 
-    stamp.actime = hdr->mtime; 
-    stamp.modtime = hdr->mtime;
+    if (!getuid() && !rc && chown(hdr->path, hdr->uid, hdr->gid))
+       rc = CPIO_CHOWN_FAILED;
 
     if (!S_ISLNK(hdr->mode)) {
-       if (!getuid() && chown(hdr->path, hdr->uid, hdr->gid))
-           rc = CPIOERR_CHOWN_FAILED;
        if (!rc && chmod(hdr->path, hdr->mode & 07777))
-           rc = CPIOERR_CHMOD_FAILED;
+           rc = CPIO_CHMOD_FAILED;
        if (!rc && utime(hdr->path, &stamp))
-           rc = CPIOERR_UTIME_FAILED;
-    } else {
-#       if ! CHOWN_FOLLOWS_SYMLINK
-           if (!getuid() && !rc && lchown(hdr->path, hdr->uid, hdr->gid))
-               rc = CPIOERR_CHOWN_FAILED;
-#       endif
+           rc = CPIO_UTIME_FAILED;
     }
 
     return rc;
 }
 
-static int checkDirectory(const char * filename)
-{
-    /*@only@*/ static char * lastDir = NULL;   /* XXX memory leak */
+static int checkDirectory(char * filename) {
+    static char * lastDir = NULL;
     static int lastDirLength = 0;
     static int lastDirAlloced = 0;
     int length = strlen(filename);
@@ -292,7 +221,7 @@ static int checkDirectory(const char * filename)
 
     if (lastDirAlloced < (length + 1)) {
        lastDirAlloced = length + 100;
-       lastDir = xrealloc(lastDir, lastDirAlloced);    /* XXX memory leak */
+       lastDir = realloc(lastDir, lastDirAlloced);
     }
 
     strcpy(lastDir, buf);
@@ -301,236 +230,123 @@ static int checkDirectory(const char * filename)
     for (chptr = buf + 1; *chptr; chptr++) {
        if (*chptr == '/') {
            *chptr = '\0';
-           rc = createDirectory(buf, 0755);
+           rc = createDirectory(buf);
            *chptr = '/';
            if (rc) return rc;
        }
     }
-    rc = createDirectory(buf, 0755);
+    rc = createDirectory(buf);
 
     return rc;
 }
 
-static int expandRegular(FD_t cfd, struct cpioHeader * hdr,
-                        cpioCallback cb, void * cbData)
-{
-    FD_t ofd;
-    char buf[BUFSIZ];
+static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr) {
+    int out;
+    char buf[16384];
     int bytesRead;
     int left = hdr->size;
     int rc = 0;
-    struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
-    struct stat sb;
-
-    /* Rename the old file before attempting unlink to avoid EBUSY errors */
-    if (!lstat(hdr->path, &sb)) {
-       strcpy(buf, hdr->path);
-       strcat(buf, "-RPMDELETE");
-       if (rename(hdr->path, buf)) {
-           fprintf(stderr, _("can't rename %s to %s: %s\n"),
-               hdr->path, buf, strerror(errno));
-            return CPIOERR_UNLINK_FAILED;
-       }
-
-       if (unlink(buf)) {
-           fprintf(stderr, _("can't unlink %s: %s\n"),
-               buf, strerror(errno));
-#if 0
-           return CPIOERR_UNLINK_FAILED;
-#endif
-       }
-    }
 
-    ofd = Fopen(hdr->path, "w.ufdio");
-    if (ofd == NULL || Ferror(ofd))
-       return CPIOERR_OPEN_FAILED;
+    if (!access(hdr->path, X_OK))
+       if (unlink(hdr->path))
+           return CPIO_UNLINK_FAILED;
 
-    cbInfo.file = hdr->path;
-    cbInfo.fileSize = hdr->size;
+    out = open(hdr->path, O_CREAT | O_WRONLY, 0);
+    if (out < 0) 
+       return CPIO_OPEN_FAILED;
 
     while (left) {
-       bytesRead = ourread(cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
+       bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
        if (bytesRead <= 0) {
-           rc = CPIOERR_READ_FAILED;
+           rc = CPIO_READ_FAILED;
            break;
        }
 
-       if (Fwrite(buf, sizeof(buf[0]), bytesRead, ofd) != bytesRead) {
-           rc = CPIOERR_COPY_FAILED;
+       if (write(out, buf, bytesRead) != bytesRead) {
+           rc = CPIO_READ_FAILED;
            break;
        }
 
        left -= bytesRead;
-
-       /* don't call this with fileSize == fileComplete */
-       if (!rc && cb && left) {
-           cbInfo.fileComplete = hdr->size - left;
-           cbInfo.bytesProcessed = fdGetCpioPos(cfd);
-           cb(&cbInfo, cbData);
-       }
     }
 
-    Fclose(ofd);
+    close(out);
     
     return rc;
 }
 
-static int expandSymlink(FD_t cfd, struct cpioHeader * hdr)
-{
-    char buf[2048], buf2[2048];
-    struct stat sb;
-    int len;
+static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
+    char buf[2048];
+
+    if (!access(hdr->path, X_OK))
+       if (unlink(hdr->path))
+           return CPIO_UNLINK_FAILED;
 
     if ((hdr->size + 1)> sizeof(buf))
-       return CPIOERR_HDR_SIZE;
+       return CPIO_INTERNAL;
 
-    if (ourread(cfd, buf, hdr->size) != hdr->size)
-       return CPIOERR_READ_FAILED;
+    if (ourread(fd, buf, hdr->size) != hdr->size)
+       return CPIO_READ_FAILED;
 
     buf[hdr->size] = '\0';
 
-    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 CPIOERR_UNLINK_FAILED;
-    }
-
-    if (symlink(buf, hdr->path) < 0)
-       return CPIOERR_SYMLINK_FAILED;
+    if (symlink(buf, hdr->path))
+       return CPIO_SYMLINK_FAILED;
 
     return 0;
 }
 
-static int expandFifo( /*@unused@*/ FD_t cfd, struct cpioHeader * hdr)
-{
+static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
     struct stat sb;
 
-    if (!lstat(hdr->path, &sb)) {
+    if (!access(hdr->path, X_OK)) {
+       if (lstat(hdr->path, &sb))
+           return CPIO_STAT_FAILED;
+
        if (S_ISFIFO(sb.st_mode)) return 0;
 
        if (unlink(hdr->path))
-           return CPIOERR_UNLINK_FAILED;
+           return CPIO_UNLINK_FAILED;
     }
 
     if (mkfifo(hdr->path, 0))
-       return CPIOERR_MKFIFO_FAILED;
+       return CPIO_MKFIFO_FAILED;
 
     return 0; 
 }
 
-static int expandDevice( /*@unused@*/ FD_t cfd, struct cpioHeader * hdr)
-{
-    struct stat sb;
-
-    if (!lstat(hdr->path, &sb)) {
-       if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) && 
-               (sb.st_rdev == hdr->rdev))
-           return 0;
+static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
+    if (!access(hdr->path, X_OK))
        if (unlink(hdr->path))
-           return CPIOERR_UNLINK_FAILED;
-    }
+           return CPIO_UNLINK_FAILED;
 
-    if ( /*@-unrecog@*/ mknod(hdr->path, hdr->mode & (~0777), hdr->rdev) /*@=unrecog@*/ )
-       return CPIOERR_MKNOD_FAILED;
+    if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
+       return CPIO_MKNOD_FAILED;
     
     return 0;
 }
 
-static void freeLink( /*@only@*/ struct hardLink * li)
-{
-    int i;
-
-    for (i = 0; i < li->nlink; i++) {
-       if (li->files[i] == NULL) continue;
-       /*@-unqualifiedtrans@*/ free((void *)li->files[i]) /*@=unqualifiedtrans@*/ ;
-       li->files[i] = NULL;
-    }
-    free(li->files);
-}
-
-static int createLinks(struct hardLink * li, /*@out@*/const 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])) {
-               if (failedFile)
-                   *failedFile = xstrdup(li->files[i]);
-               return CPIOERR_UNLINK_FAILED;
-           }
-       }
-
-       if (link(li->files[li->createdPath], li->files[i])) {
-           if (failedFile)
-               *failedFile = xstrdup(li->files[i]);
-           return CPIOERR_LINK_FAILED;
-       }
-
-       /*@-unqualifiedtrans@*/ free((void *)li->files[i]) /*@=unqualifiedtrans@*/ ;
-       li->files[i] = NULL;
-       li->linksLeft--;
-    }
-
-    return 0;
-}
-
-static int eatBytes(FD_t cfd, int amount)
-{
-    char buf[4096];
-    int bite;
-   
-    while (amount) {
-       bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
-       if (ourread(cfd, buf, bite) != bite)
-           return CPIOERR_READ_FAILED;
-       amount -= bite;
-    }
-
-    return 0;
-}
-
-int cpioInstallArchive(FD_t cfd, struct cpioFileMapping * mappings, 
-                      int numMappings, cpioCallback cb, void * cbData,
-                      const char ** failedFile)
-{
+int cpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings, 
+                      int numMappings, cpioCallback cb, char ** failedFile) {
     struct cpioHeader ch;
+    struct ourfd fd;
     int rc = 0;
-    int linkNum = 0;
     struct cpioFileMapping * map = NULL;
     struct cpioFileMapping needle;
     mode_t cpioMode;
     int olderr;
-    struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
-    struct hardLink * links = NULL;
-    struct hardLink * li = NULL;
 
-    fdSetCpioPos(cfd, 0);
-    if (failedFile)
-       *failedFile = NULL;
+    fd.fd = stream;
+    fd.pos = 0;
 
-    ch.path = NULL;
     do {
-       if ((rc = getNextHeader(cfd, &ch))) {
-#if 0  /* XXX this is the failure point for an unreadable rpm */
-           fprintf(stderr, _("getNextHeader: %s\n"), cpioStrerror(rc));
-#endif
-           return rc;
+       if ((rc = getNextHeader(&fd, &ch))) {
+           printf("error %d reading header: %s\n", rc, strerror(errno));
+           exit(1);
        }
 
        if (!strcmp(ch.path, TRAILER)) {
-           if (ch.path) free(ch.path);
+           free(ch.path);
            break;
        }
 
@@ -540,15 +356,13 @@ int cpioInstallArchive(FD_t cfd, struct cpioFileMapping * mappings,
                          cpioFileMapCmp);
        }
 
-       if (mappings && !map) {
-           eatBytes(cfd, ch.size);
-       } else {
+       if (!mappings || map) {
            cpioMode = ch.mode;
 
            if (map) {
                if (map->mapFlags & CPIO_MAP_PATH) {
-                   if (ch.path) free(ch.path);
-                   ch.path = xstrdup(map->fsPath);
+                   free(ch.path);
+                   ch.path = strdup(map->finalPath);
                } 
 
                if (map->mapFlags & CPIO_MAP_MODE)
@@ -559,78 +373,32 @@ int cpioInstallArchive(FD_t cfd, struct cpioFileMapping * mappings,
                    ch.gid = map->finalGid;
            }
 
-           /* This won't get hard linked symlinks right, but I can't seem 
-              to create those anyway */
-
-           if (S_ISREG(ch.mode) && ch.nlink > 1) {
-               for (li = links; li; li = li->next) {
-                   if (li->inode == ch.inode && li->dev == ch.dev) break;
+           rc = checkDirectory(ch.path);
+
+           if (!rc) {
+               if (S_ISREG(ch.mode))
+                   rc = expandRegular(&fd, &ch);
+               else if (S_ISDIR(ch.mode))
+                   rc = createDirectory(ch.path);
+               else if (S_ISLNK(ch.mode))
+                   rc = expandSymlink(&fd, &ch);
+               else if (S_ISFIFO(ch.mode))
+                   rc = expandFifo(&fd, &ch);
+               else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
+                   rc = expandDevice(&fd, &ch);
+               else if (S_ISSOCK(ch.mode)) {
+                   /* should we do something here??? */
+                   rc = 0;
+               } else {
+                   rc = CPIO_INTERNAL;
                }
-
-               if (li == NULL) {
-                   li = xmalloc(sizeof(*li));
-                   li->inode = ch.inode;
-                   li->dev = ch.dev;
-                   li->nlink = ch.nlink;
-                   li->linksLeft = ch.nlink;
-                   li->createdPath = -1;
-                   li->files = xcalloc(li->nlink,(sizeof(*li->files)));
-                   li->next = links;
-                   links = li;
-               }
-
-               for (linkNum = 0; linkNum < li->nlink; linkNum++)
-                   if (!li->files[linkNum]) break;
-               li->files[linkNum] = xstrdup(ch.path);
            }
-               
-           if ((ch.nlink > 1) && S_ISREG(ch.mode) && !ch.size &&
-               li->createdPath == -1) {
-               /* defer file creation */
-           } else if ((ch.nlink > 1) && S_ISREG(ch.mode) && 
-                      (li->createdPath != -1)) {
-               createLinks(li, failedFile);
-
-               /* 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 */
-               if (ch.size) eatBytes(cfd, ch.size);
-           } else {
-               rc = checkDirectory(ch.path);
-
-               if (!rc) {
-                   if (S_ISREG(ch.mode))
-                       rc = expandRegular(cfd, &ch, cb, cbData);
-                   else if (S_ISDIR(ch.mode))
-                       rc = createDirectory(ch.path, 000);
-                   else if (S_ISLNK(ch.mode))
-                       rc = expandSymlink(cfd, &ch);
-                   else if (S_ISFIFO(ch.mode))
-                       rc = expandFifo(cfd, &ch);
-                   else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
-                       rc = expandDevice(cfd, &ch);
-                   else if (S_ISSOCK(ch.mode)) {
-                       /* this mimicks cpio but probably isnt' right */
-                       rc = expandFifo(cfd, &ch);
-                   } else {
-                       rc = CPIOERR_UNKNOWN_FILETYPE;
-                   }
-               }
-
-               if (!rc)
-                   rc = setInfo(&ch);
 
-               if (S_ISREG(ch.mode) && ch.nlink > 1) {
-                   li->createdPath = linkNum;
-                   li->linksLeft--;
-                   rc = createLinks(li, failedFile);
-               }
-           }
+           if (!rc)
+               rc = setInfo(&ch);
 
-           if (rc && failedFile && *failedFile == NULL) {
-               *failedFile = xstrdup(ch.path);
+           if (rc) {
+               *failedFile = strdup(ch.path);
 
                olderr = errno;
                unlink(ch.path);
@@ -638,395 +406,9 @@ int cpioInstallArchive(FD_t cfd, struct cpioFileMapping * mappings,
            }
        }
 
-       padinfd(cfd, 4);
-
-       if (!rc && cb) {
-           cbInfo.file = ch.path;
-           cbInfo.fileSize = ch.size;
-           cbInfo.fileComplete = ch.size;
-           cbInfo.bytesProcessed = fdGetCpioPos(cfd);
-           cb(&cbInfo, cbData);
-       }
-
-       if (ch.path) free(ch.path);
-       ch.path = NULL;
+       padfd(&fd, 4);
+       free(ch.path);
     } while (1 && !rc);
 
-    li = links;
-    while (li && !rc) {
-       if (li->linksLeft) {
-           if (li->createdPath == -1)
-               rc = CPIOERR_MISSING_HARDLINK;
-           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);
-    }
-
     return rc;
 }
-
-static int writeFile(FD_t cfd, struct stat sb, struct cpioFileMapping * map, 
-                    /*@out@*/size_t * sizep, int writeData)
-{
-    struct cpioCrcPhysicalHeader hdr;
-    char buf[8192], symbuf[2048];
-    dev_t num;
-    FD_t datafd;
-    size_t size, amount = 0;
-    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;
-
-    if (!writeData || S_ISDIR(sb.st_mode)) {
-       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 CPIOERR_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((unsigned)sb.st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
-    num = minor((unsigned)sb.st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
-    num = major((unsigned)sb.st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
-    num = minor((unsigned)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);
-
-    if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
-       return rc;
-    if ((rc = safewrite(cfd, map->archivePath, num)) != num)
-       return rc;
-    size = PHYS_HDR_SIZE + num;
-    if ((rc = padoutfd(cfd, &size, 4)))
-       return rc;
-       
-    if (writeData && S_ISREG(sb.st_mode)) {
-       char *b;
-#if HAVE_MMAP
-       void *mapped;
-       size_t nmapped;
-#endif
-
-       /* XXX unbuffered mmap generates *lots* of fdio debugging */
-       datafd = Fopen(map->fsPath, "r.ufdio");
-       if (datafd == NULL || Ferror(datafd))
-           return CPIOERR_OPEN_FAILED;
-
-#if HAVE_MMAP
-       nmapped = 0;
-       mapped = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, Fileno(datafd), 0);
-       if (mapped != (void *)-1) {
-           b = (char *)mapped;
-           nmapped = sb.st_size;
-       } else
-#endif
-       {
-           b = buf;
-       }
-
-       size += sb.st_size;
-
-       while (sb.st_size) {
-#if HAVE_MMAP
-         if (mapped != (void *)-1) {
-           amount = nmapped;
-         } else
-#endif
-         {
-           amount = Fread(b, sizeof(buf[0]),
-                       (sb.st_size > sizeof(buf) ? sizeof(buf) : sb.st_size),
-                       datafd);
-           if (amount <= 0) {
-               olderrno = errno;
-               Fclose(datafd);
-               errno = olderrno;
-               return CPIOERR_READ_FAILED;
-           }
-         }
-
-           if ((rc = safewrite(cfd, b, amount)) != amount) {
-               olderrno = errno;
-               Fclose(datafd);
-               errno = olderrno;
-               return rc;
-           }
-
-           sb.st_size -= amount;
-       }
-
-#if HAVE_MMAP
-       if (mapped != (void *)-1) {
-           munmap(mapped, nmapped);
-       }
-#endif
-
-       Fclose(datafd);
-    } else if (writeData && S_ISLNK(sb.st_mode)) {
-       if ((rc = safewrite(cfd, symbuf, amount)) != amount)
-           return rc;
-       size += amount;
-    }
-
-    /* this is a noop for most file types */
-    if ((rc = padoutfd(cfd, &size, 4)))
-       return rc;
-
-    if (sizep)
-       *sizep = size;
-
-    return 0;
-}
-
-static int writeLinkedFile(FD_t cfd, struct hardLink * hlink, 
-                          struct cpioFileMapping * mappings,
-                          cpioCallback cb, void * cbData,
-                          /*@out@*/size_t * sizep,
-                          /*@out@*/const char ** failedFile)
-{
-    int i, rc;
-    size_t size, total;
-    struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
-
-    total = 0;
-
-    for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
-       if ((rc = writeFile(cfd, hlink->sb, mappings + hlink->fileMaps[i], 
-                           &size, 0))) {
-           if (failedFile)
-               *failedFile = xstrdup(mappings[hlink->fileMaps[i]].fsPath);
-           return rc;
-       }
-
-       total += size;
-
-       if (cb) {
-           cbInfo.file = mappings[i].archivePath;
-           cb(&cbInfo, cbData);
-       }
-    }
-
-    if ((rc = writeFile(cfd, hlink->sb, 
-                       mappings + hlink->fileMaps[hlink->linksLeft], 
-                       &size, 1))) {
-       if (sizep)
-           *sizep = total;
-       if (failedFile) 
-           *failedFile = xstrdup(mappings[hlink->fileMaps[hlink->linksLeft]].fsPath);
-       return rc;
-    }
-    total += size;
-
-    if (sizep)
-       *sizep = total;
-
-    if (cb) {
-       cbInfo.file = mappings[i].archivePath;
-       cb(&cbInfo, cbData);
-    }
-
-    return 0;
-}
-
-int cpioBuildArchive(FD_t cfd, struct cpioFileMapping * mappings, 
-                    int numMappings, cpioCallback cb, void * cbData,
-                    unsigned int * archiveSize, const char ** failedFile)
-{
-    size_t size, totalsize = 0;
-    int rc;
-    int i;
-    struct cpioCallbackInfo cbInfo = { NULL, 0, 0, 0 };
-    struct cpioCrcPhysicalHeader hdr;
-    struct stat sb;
-/*@-fullinitblock@*/
-    struct hardLink hlinkList = { NULL };
-/*@=fullinitblock@*/
-    struct hardLink * hlink, * parent;
-
-    hlinkList.next = NULL;
-
-    for (i = 0; i < numMappings; i++) {
-       if (mappings[i].mapFlags & CPIO_FOLLOW_SYMLINKS)
-           rc = Stat(mappings[i].fsPath, &sb);
-       else
-           rc = Lstat(mappings[i].fsPath, &sb);
-
-       if (rc) {
-           if (failedFile)
-               *failedFile = xstrdup(mappings[i].fsPath);
-           return CPIOERR_STAT_FAILED;
-       }
-
-       if (!S_ISDIR(sb.st_mode) && sb.st_nlink > 1) {
-           hlink = hlinkList.next;
-           while (hlink && 
-                  (hlink->dev != sb.st_dev || hlink->inode != sb.st_ino))
-               hlink = hlink->next;
-           if (!hlink) {
-               hlink = xmalloc(sizeof(*hlink));
-               hlink->next = hlinkList.next;
-               hlinkList.next = hlink;
-               hlink->sb = sb;         /* structure assignment */
-               hlink->dev = sb.st_dev;
-               hlink->inode = sb.st_ino;
-               hlink->nlink = sb.st_nlink;
-               hlink->linksLeft = sb.st_nlink;
-               hlink->fileMaps = xmalloc(sizeof(*hlink->fileMaps) * 
-                                               sb.st_nlink);
-           }
-
-           hlink->fileMaps[--hlink->linksLeft] = i;
-
-           if (!hlink->linksLeft) {
-               if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
-                                         &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 {
-           if ((rc = writeFile(cfd, sb, mappings + i, &size, 1))) {
-               if (failedFile)
-                   *failedFile = xstrdup(mappings[i].fsPath);
-               return rc;
-           }
-
-           if (cb) {
-               cbInfo.file = mappings[i].archivePath;
-               cb(&cbInfo, cbData);
-           }
-
-           totalsize += size;
-       }
-    }    
-
-    hlink = hlinkList.next;
-    while (hlink) {
-       if ((rc = writeLinkedFile(cfd, hlink, mappings, cb, cbData,
-                                 &size, failedFile)))
-           return rc;
-       free(hlink->fileMaps);
-       parent = hlink;
-       hlink = hlink->next;
-       free(parent);
-
-       totalsize += size;
-    }
-
-    memset(&hdr, '0', PHYS_HDR_SIZE);
-    memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
-    memcpy(hdr.nlink, "00000001", 8);
-    memcpy(hdr.namesize, "0000000b", 8);
-    if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
-       return rc;
-    if ((rc = safewrite(cfd, "TRAILER!!!", 11)) != 11)
-       return rc;
-    totalsize += PHYS_HDR_SIZE + 11;
-
-    /* GNU cpio pads to 512 bytes here, but we don't. I'm not sure if
-       it matters or not */
-    
-    if ((rc = padoutfd(cfd, &totalsize, 4)))
-       return rc;
-
-    if (archiveSize) *archiveSize = totalsize;
-
-    return 0;
-}
-
-const char * cpioStrerror(int rc)
-{
-    static char msg[256];
-    char *s;
-    int l, myerrno = errno;
-
-    strcpy(msg, "cpio: ");
-    switch (rc) {
-    default:
-       s = msg + strlen(msg);
-       sprintf(s, _("(error 0x%x)"), (unsigned)rc);
-       s = NULL;
-       break;
-    case CPIOERR_BAD_MAGIC:    s = _("Bad magic");             break;
-    case CPIOERR_BAD_HEADER:   s = _("Bad/unreadable  header");break;
-
-    case CPIOERR_OPEN_FAILED:  s = "open";     break;
-    case CPIOERR_CHMOD_FAILED: s = "chmod";    break;
-    case CPIOERR_CHOWN_FAILED: s = "chown";    break;
-    case CPIOERR_WRITE_FAILED: s = "write";    break;
-    case CPIOERR_UTIME_FAILED: s = "utime";    break;
-    case CPIOERR_UNLINK_FAILED:        s = "unlink";   break;
-    case CPIOERR_SYMLINK_FAILED: s = "symlink";        break;
-    case CPIOERR_STAT_FAILED:  s = "stat";     break;
-    case CPIOERR_MKDIR_FAILED: s = "mkdir";    break;
-    case CPIOERR_MKNOD_FAILED: s = "mknod";    break;
-    case CPIOERR_MKFIFO_FAILED:        s = "mkfifo";   break;
-    case CPIOERR_LINK_FAILED:  s = "link";     break;
-    case CPIOERR_READLINK_FAILED: s = "readlink";      break;
-    case CPIOERR_READ_FAILED:  s = "read";     break;
-    case CPIOERR_COPY_FAILED:  s = "copy";     break;
-
-    case CPIOERR_HDR_SIZE:     s = _("Header size too big");   break;
-    case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
-    case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link"); break;
-    case CPIOERR_INTERNAL:     s = _("Internal error");        break;
-    }
-
-    l = sizeof(msg) - strlen(msg) - 1;
-    if (s != NULL) {
-       if (l > 0) strncat(msg, s, l);
-       l -= strlen(s);
-    }
-    if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
-       s = _(" failed - ");
-       if (l > 0) strncat(msg, s, l);
-       l -= strlen(s);
-       if (l > 0) strncat(msg, strerror(myerrno), l);
-    }
-    return msg;
-}
diff --git a/lib/cpio.h b/lib/cpio.h
new file mode 100644 (file)
index 0000000..2105d9a
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef H_CPIO
+#define H_CPIO
+
+#include <zlib.h>
+
+/* Note the "high" bit is set only if errno is valid */
+#define CPIO_CHECK_ERRNO       0x80000000
+#define CPIO_READ_FAILED       (-1)
+#define CPIO_BAD_MAGIC         (-2                     )
+#define CPIO_BAD_HEADER                (-3                     )
+#define CPIO_OPEN_FAILED       (-4   | CPIO_CHECK_ERRNO)
+#define CPIO_CHMOD_FAILED      (-5   | CPIO_CHECK_ERRNO)
+#define CPIO_CHOWN_FAILED      (-6   | CPIO_CHECK_ERRNO)
+#define CPIO_WRITE_FAILED      (-7   | CPIO_CHECK_ERRNO)
+#define CPIO_UTIME_FAILED      (-8   | CPIO_CHECK_ERRNO)
+#define CPIO_UNLINK_FAILED     (-9   | CPIO_CHECK_ERRNO)
+#define CPIO_INTERNAL          (-10                    )
+#define CPIO_SYMLINK_FAILED    (-11  | CPIO_CHECK_ERRNO)
+#define CPIO_STAT_FAILED       (-12  | CPIO_CHECK_ERRNO)
+#define CPIO_MKDIR_FAILED      (-13  | CPIO_CHECK_ERRNO)
+#define CPIO_MKNOD_FAILED      (-14  | CPIO_CHECK_ERRNO)
+#define CPIO_MKFIFO_FAILED     (-15  | CPIO_CHECK_ERRNO)
+
+/* Don't think this behaves just like standard cpio. It's pretty close, but
+   it has some behaviors which are more to RPM's liking. I tried to document
+   them inline in cpio.c, but I may have missed some. */
+
+#define CPIO_MAP_PATH  (1 << 0)
+#define CPIO_MAP_MODE  (1 << 1)
+#define CPIO_MAP_UID   (1 << 2)
+#define CPIO_MAP_GID   (1 << 3)
+
+struct cpioFileMapping {
+    char * archivePath;
+    char * finalPath;
+    mode_t finalMode;
+    uid_t finalUid;
+    gid_t finalGid;
+    int mapFlags;
+};
+
+typedef void (*cpioCallback)(char * filespec);
+
+/* If no mappings are passed, this installs everything! If one is passed
+   it should be sorted according to cpioFileMapCmp() and only files included
+   in the map are installed. Files are installed relative to the current
+   directory unless a mapping is given which specifies an absolute 
+   directory. The mode mapping is only used for the permission bits, not
+   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);
+
+/* This is designed to be qsort/bsearch compatible */
+int cpioFileMapCmp(const void * a, const void * b);
+
+#endif
index 7512522..a87cd81 100644 (file)
 #include <utime.h>
 #include <zlib.h>
 
+#include "cpio.h"
 #include "header.h"
 #include "install.h"
 #include "md5.h"
+#include "messages.h"
 #include "misc.h"
 #include "miscfn.h"
 #include "rpmdb.h"
 #include "rpmlib.h"
-#include "messages.h"
 
-enum instActions { CREATE, BACKUP, KEEP, SAVE, SKIP };
+enum instActions { UNKNOWN, CREATE, BACKUP, KEEP, SAVE, SKIP };
 enum fileTypes { XDIR, BDEV, CDEV, SOCK, PIPE, REG, LINK } ;
 
-struct fileToInstall {
-    char * fileName;
-    int size;
+struct fileMemory {
+    char ** md5s;
+    char ** links;
+    char ** names;
+    struct fileInfo * files;
+};
+
+struct fileInfo {
+    char * cpioPath;
+    char * relativePath;               /* relative to root */
+    char * rootedPath;                 /* absolute relative to / */
+    char * md5;
+    char * link;
+    uid_t uid;
+    gid_t gid;
+    uint_32 flags;
+    uint_32 size;
+    mode_t mode;
+    char state;
+    enum instActions action;
+    int install;
 } ;
 
 struct replacedFile {
@@ -44,27 +63,15 @@ static int filecmp(short mode1, char * md51, char * link1,
 static enum instActions decideFileFate(char * filespec, short dbMode, 
                                char * dbMd5, char * dbLink, short newMode, 
                                char * newMd5, char * newLink, int brokenMd5);
-static int installArchive(char * prefix, int fd, struct fileToInstall * files,
-                         int fileCount, rpmNotifyFunction notify,
-                         char ** installArchive, char * tmpPath,
-                         int archiveSize);
+static int installArchive(char * prefix, int fd, struct fileInfo * files,
+                         int fileCount, rpmNotifyFunction notify, 
+                         char ** specFile, int archiveSize);
 static int packageAlreadyInstalled(rpmdb db, char * name, char * version, 
                                   char * release, int * recOffset, int flags);
-static int setFileOwnerships(char * rootdir, char ** fileList, 
-                            char ** fileOwners, char ** fileGroups, 
-                            int_16 * fileModes, 
-                            enum instActions * instActions, int fileCount);
-static int setFileOwner(char * file, char * owner, char * group, int_16 mode);
-static int createDirectories(char ** fileList, uint_32 * modesList, 
-                            uint_32 * mtimesList, int fileCount);
-static int mkdirIfNone(char * directory, mode_t perms, uint_32 stamp);
-static int instHandleSharedFiles(rpmdb db, int ignoreOffset, char ** fileList, 
-                                char ** fileMd5List, int_16 * fileModeList,
-                                char ** fileLinkList, uint_32 * fileFlagsList,
-                                int fileCount, enum instActions * instActions, 
-                                char ** prootdirootdir, int * notErrors,
+static int instHandleSharedFiles(rpmdb db, int ignoreOffset, 
+                                struct fileInfo * files,
+                                int fileCount, int * notErrors,
                                 struct replacedFile ** repListPtr, int flags);
-static int fileCompare(const void * one, const void * two);
 static int installSources(Header h, char * rootdir, int fd, 
                          char ** specFilePtr, rpmNotifyFunction notify,
                          char * labelFormat);
@@ -75,8 +82,11 @@ static int archOkay(Header h);
 static int osOkay(Header h);
 static int moveFile(char * sourceName, char * destName);
 static int copyFile(char * sourceName, char * destName);
-static void unglobFilename(char * dptr, char * sptr);
 static int ensureOlder(rpmdb db, Header new, int dbOffset);
+static void assembleFileList(Header h, struct fileMemory * mem, 
+                            int * fileCountPtr, struct fileInfo ** files, 
+                            int stripPrefixLength);
+static void freeFileMemory(struct fileMemory fileMem);
 
 /* 0 success */
 /* 1 bad magic */
@@ -107,6 +117,78 @@ int rpmInstallSourcePackage(char * rootdir, int fd, char ** specFile,
     return rc;
 }
 
+static void freeFileMemory(struct fileMemory fileMem) {
+    free(fileMem.files);
+    free(fileMem.md5s);
+    free(fileMem.links);
+    free(fileMem.names);
+}
+
+/* files should not be preallocated */
+static void assembleFileList(Header h, struct fileMemory * mem, 
+                            int * fileCountPtr, struct fileInfo ** filesPtr, 
+                            int stripPrefixLength) {
+    char ** fileOwners;
+    char ** fileGroups;
+    uint_32 * fileFlags;
+    uint_32 * fileSizes;
+    uint_16 * fileModes;
+    struct fileInfo * files;
+    struct fileInfo * file;
+    int fileCount;
+    int i;
+
+    headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &mem->names, 
+                  fileCountPtr);
+    fileCount = *fileCountPtr;
+    files = *filesPtr = mem->files = malloc(sizeof(*mem->files) * fileCount);
+    
+    headerGetEntry(h, RPMTAG_FILEMD5S, NULL, (void **) &mem->md5s, NULL);
+    headerGetEntry(h, RPMTAG_FILEUSERNAME, NULL, (void **) &fileOwners, NULL);
+    headerGetEntry(h, RPMTAG_FILEGROUPNAME, NULL, (void **) &fileGroups, NULL);
+    headerGetEntry(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
+    headerGetEntry(h, RPMTAG_FILEMODES, NULL, (void **) &fileModes, NULL);
+    headerGetEntry(h, RPMTAG_FILESIZES, NULL, (void **) &fileSizes, NULL);
+    headerGetEntry(h, RPMTAG_FILELINKTOS, NULL, (void **) &mem->links, NULL);
+
+    for (i = 0, file = files; i < fileCount; i++, file++) {
+       /* It would be nice to take care of assembling the rooted 
+          path here, but making the caller do it lets us use alloca()
+          and makes the memory management easier. */
+       file->rootedPath = NULL;
+       file->state = RPMFILE_STATE_NORMAL;
+       file->action = UNKNOWN;
+       file->install = 1;
+
+       file->relativePath = mem->names[i];
+       file->cpioPath = mem->names[i] + stripPrefixLength;
+       file->mode = fileModes[i];
+       file->md5 = mem->md5s[i];
+       file->link = mem->links[i];
+       file->size = fileSizes[i];
+       file->flags = fileFlags[i];
+
+       if (unameToUid(fileOwners[i], &files[i].uid)) {
+           rpmError(RPMERR_NOUSER, "user %s does not exist - using root", 
+                       fileOwners[i]);
+           files[i].uid = 0;
+           /* turn off the suid bit */
+           files[i].mode &= ~S_ISUID;
+       }
+
+       if (gnameToGid(fileGroups[i], &files[i].gid)) {
+           rpmError(RPMERR_NOGROUP, "user %s does not exist - using root", 
+                       fileGroups[i]);
+           files[i].gid = 0;
+           /* turn off the sgid bit */
+           files[i].mode &= ~S_ISGID;
+       }
+    }
+
+    free(fileOwners);
+    free(fileGroups);
+}
+
 /* 0 success */
 /* 1 bad magic */
 /* 2 error */
@@ -117,26 +199,14 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
     char * name, * version, * release;
     Header h;
     int fileCount, type, count;
-    char ** fileList;
-    char ** fileOwners, ** fileGroups, ** fileMd5s, ** fileLinkList;
-    uint_32 * fileFlagsList;
-    uint_32 * fileSizesList, * fileMtimesList;
-    int_16 * fileModesList;
+    struct fileInfo * files;
     int_32 installTime;
-    char * fileStatesList = NULL;
-    struct fileToInstall * files;
-    enum instActions * instActions = NULL;
+    char * fileStates;
     int i;
-    int archiveFileCount = 0;
     int installFile = 0;
     int otherOffset = 0;
     char * ext = NULL, * newpath;
     int rootLength = strlen(rootdir);
-    char ** rootedFileList = NULL;
-    char ** finalFileList = NULL;
-    char ** mkdirFileList = NULL;
-    int mkdirFileCount = 0;
-    uint_32 * mkdirModesList, * mkdirMtimesList;
     struct replacedFile * replacedList = NULL;
     char * defaultPrefix;
     dbiIndexSet matches;
@@ -147,6 +217,8 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
     int hasOthers = 0;
     int relocationSize = 1;            /* strip at least first / for cpio */
     uint_32 * archiveSizePtr;
+    struct fileMemory fileMem;
+    int freeFileMem = 0;
 
     oldVersions = alloca(sizeof(int));
     *oldVersions = 0;
@@ -156,7 +228,8 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
 
     if (isSource) {
        if (flags & RPMINSTALL_TEST) {
-           rpmMessage(RPMMESS_DEBUG, "stopping install as we're running --test\n");
+           rpmMessage(RPMMESS_DEBUG, 
+                       "stopping install as we're running --test\n");
            return 0;
        }
 
@@ -172,8 +245,6 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
        return rc;
     }
 
-    /* Do this now so we can give error messages, even though we'll just
-       do it again after relocating everything */
     headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &fileCount);
     headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &fileCount);
     headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &fileCount);
@@ -286,113 +357,91 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
     if (hasOthers) 
        dbiFreeIndexRecord(matches);
 
-    fileList = NULL;
-    if (headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList, 
-                &fileCount)) {
+    if (headerIsEntry(h, RPMTAG_FILENAMES)) {
        char ** netsharedPaths;
        char ** nsp;
 
+       freeFileMem = 1;
+       assembleFileList(h, &fileMem, &fileCount, &files, relocationSize);
+
        if (netsharedPath) 
            netsharedPaths = splitString(netsharedPath, 
                                         strlen(netsharedPath), ':');
        else
            netsharedPaths = NULL;
 
-       instActions = alloca(sizeof(enum instActions) * fileCount);
-       rootedFileList = alloca(sizeof(char *) * fileCount);
-       fileStatesList = alloca(sizeof(*fileStatesList) * fileCount);
-
-       headerGetEntry(h, RPMTAG_FILEMD5S, &type, (void **) &fileMd5s, &fileCount);
-       headerGetEntry(h, RPMTAG_FILEFLAGS, &type, (void **) &fileFlagsList, 
-                &fileCount);
-       headerGetEntry(h, RPMTAG_FILEMODES, &type, (void **) &fileModesList, 
-                &fileCount);
-       headerGetEntry(h, RPMTAG_FILELINKTOS, &type, (void **) &fileLinkList, 
-                &fileCount);
-
        /* check for any config files that already exist. If they do, plan
           on making a backup copy. If that's not the right thing to do
           instHandleSharedFiles() below will take care of the problem */
        for (i = 0; i < fileCount; i++) {
            if (rootLength > 1) {
-               rootedFileList[i] = alloca(strlen(fileList[i]) + 
+               files[i].rootedPath = alloca(strlen(files[i].relativePath) + 
                                rootLength + 3);
-               strcpy(rootedFileList[i], rootdir);
-               strcat(rootedFileList[i], fileList[i]);
+               strcpy(files[i].rootedPath, rootdir);
+               strcat(files[i].rootedPath, files[i].relativePath);
            } else 
-               rootedFileList[i] = fileList[i];
+               files[i].rootedPath = files[i].relativePath;
 
            /* netsharedPaths are not relative to the current root (though 
               they do need to take the package prefix into account */
            for (nsp = netsharedPaths; nsp && *nsp; nsp++) 
-               if (!strncmp(fileList[i], *nsp, strlen(*nsp))) break;
+               if (!strncmp(files[i].relativePath, *nsp, strlen(*nsp))) 
+                   break;
 
            if (nsp && *nsp) {
                rpmMessage(RPMMESS_DEBUG, "file %s in netshared path\n", 
-                       rootedFileList[i]);
-               instActions[i] = SKIP;
-               fileStatesList[i] = RPMFILE_STATE_NETSHARED;
-           } else if ((fileFlagsList[i] & RPMFILE_DOC) && 
+                               files[i].rootedPath);
+               files[i].action = SKIP;
+               files[i].state = RPMFILE_STATE_NETSHARED;
+           } else if ((files[i].flags & RPMFILE_DOC) && 
                        (flags & RPMINSTALL_NODOCS)) {
-               instActions[i] = SKIP;
-               fileStatesList[i] = RPMFILE_STATE_NOTINSTALLED;
+               files[i].action = SKIP;
+               files[i].state = RPMFILE_STATE_NOTINSTALLED;
            } else {
-               fileStatesList[i] = RPMFILE_STATE_NORMAL;
+               files[i].state = RPMFILE_STATE_NORMAL;
 
-               instActions[i] = CREATE;
-               if ((fileFlagsList[i] & RPMFILE_CONFIG) &&
-                   !S_ISDIR(fileModesList[i])) {
-                   if (exists(rootedFileList[i])) {
+               files[i].action = CREATE;
+               if ((files[i].flags & RPMFILE_CONFIG) &&
+                   !S_ISDIR(files[i].mode)) {
+                   if (exists(files[i].rootedPath)) {
                        rpmMessage(RPMMESS_DEBUG, "%s exists - backing up\n", 
-                                   rootedFileList[i]);
-                       instActions[i] = BACKUP;
+                                   files[i].rootedPath);
+                       files[i].action = BACKUP;
                    }
                }
            }
        }
 
-       rc = instHandleSharedFiles(db, 0, fileList, fileMd5s, fileModesList,
-                                  fileLinkList, fileFlagsList, fileCount, 
-                                  instActions, rootedFileList, oldVersions, 
-                                  &replacedList, flags);
+       rc = instHandleSharedFiles(db, otherOffset, files, fileCount, 
+                                  oldVersions, &replacedList, flags);
 
-       free(fileMd5s);
-       free(fileLinkList);
        if (rc) {
            if (replacedList) free(replacedList);
-           free(fileList);
+           if (freeFileMem) freeFileMemory(fileMem);
            return 2;
        }
+    } else {
+       files = NULL;
     }
     
     if (flags & RPMINSTALL_TEST) {
        rpmMessage(RPMMESS_DEBUG, "stopping install as we're running --test\n");
-       free(fileList);
        if (replacedList) free(replacedList);
+       if (freeFileMem) freeFileMemory(fileMem);
        return 0;
     }
 
     rpmMessage(RPMMESS_DEBUG, "running preinstall script (if any)\n");
     if (runScript(rootdir, h, RPMTAG_PREIN, scriptArg, 
                  flags & RPMINSTALL_NOSCRIPTS)) {
-       free(fileList);
        if (replacedList) free(replacedList);
+       if (freeFileMem) freeFileMemory(fileMem);
        return 2;
     }
 
-    if (fileList) {
-       headerGetEntry(h, RPMTAG_FILESIZES, &type, (void **) &fileSizesList, 
-                &fileCount);
-       headerGetEntry(h, RPMTAG_FILEMTIMES, &type, (void **) &fileMtimesList, 
-                &fileCount);
-
-       files = alloca(sizeof(struct fileToInstall) * fileCount);
-       finalFileList = alloca(sizeof(char *) * fileCount);
-       mkdirFileList = alloca(sizeof(char *) * fileCount);
-       mkdirModesList = alloca(sizeof(*mkdirModesList) * fileCount);
-       mkdirMtimesList = alloca(sizeof(*mkdirMtimesList) * fileCount);
+    if (files) {
        for (i = 0; i < fileCount; i++) {
-           switch (instActions[i]) {
+           switch (files[i].action) {
              case BACKUP:
                ext = ".rpmorig";
                installFile = 1;
@@ -417,54 +466,29 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
                installFile = 0;
                ext = NULL;
                break;
+
+             case UNKNOWN:
+               break;
            }
 
            if (ext) {
-               newpath = alloca(strlen(rootedFileList[i]) + 20);
-               strcpy(newpath, rootedFileList[i]);
+               newpath = alloca(strlen(files[i].rootedPath) + 20);
+               strcpy(newpath, files[i].rootedPath);
                strcat(newpath, ext);
                rpmError(RPMMESS_BACKUP, "warning: %s saved as %s", 
-                       rootedFileList[i], newpath);
+                       files[i].rootedPath, newpath);
 
-               if (rename(rootedFileList[i], newpath)) {
+               if (rename(files[i].rootedPath, newpath)) {
                    rpmError(RPMERR_RENAME, "rename of %s to %s failed: %s",
-                         rootedFileList[i], newpath, strerror(errno));
+                         files[i].rootedPath, newpath, strerror(errno));
                    if (replacedList) free(replacedList);
+                   if (freeFileMem) freeFileMemory(fileMem);
                    return 2;
                }
            }
 
-           if (installFile) {
-               /* if we are using a relocateable package, we need to strip
-                  off whatever part of the (already relocated!) filelist
-
-                  we also need to strip globbing characters, as cpio
-                  globs the patterns we pass to it against the filenames
-                  in the archive */
-
-               files[archiveFileCount].fileName = 
-                       alloca((strlen(fileList[i]) * 2) + 1);
-
-               unglobFilename(files[archiveFileCount].fileName, 
-                               fileList[i] + relocationSize);
-               files[archiveFileCount].size = fileSizesList[i];
-
-
-               /* both of these list what files need to be installed and 
-                  where they end up *after* any relocations have been done 
-                  the mkdir list includes direcories though, while the final
-                  list does *not -- we don't let cpio expand directories as
-                  it has a bad habit of replacing symlinks with directories
-                  when we'd rather it didn't */
-               mkdirFileList[mkdirFileCount] = rootedFileList[i];
-               mkdirModesList[mkdirFileCount] = fileModesList[i];
-               mkdirMtimesList[mkdirFileCount] = fileMtimesList[i];
-               mkdirFileCount++;
-
-               if (!S_ISDIR(fileModesList[i])) {
-                   finalFileList[archiveFileCount] = rootedFileList[i];
-                   archiveFileCount++;
-               }
+           if (!installFile) {
+               files[i].install = 0;
            }
        }
 
@@ -476,53 +500,35 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
        } else
            tmpPath = rpmGetVar(RPMVAR_TMPPATH);
 
-       if (!headerGetEntry(h, RPMTAG_ARCHIVESIZE, &type, (void *) &archiveSizePtr, 
-                     &count))
+       if (!headerGetEntry(h, RPMTAG_ARCHIVESIZE, &type, 
+                               (void *) &archiveSizePtr, &count))
            archiveSizePtr = NULL;
 
-       if (createDirectories(mkdirFileList, mkdirModesList, mkdirMtimesList,
-                             mkdirFileCount)) {
-           headerFree(h);
-           free(fileList);
-           if (replacedList) free(replacedList);
-           return 2;
-       }
-
        if (labelFormat) {
            printf(labelFormat, name, version, release);
            fflush(stdout);
        }
 
        /* the file pointer for fd is pointing at the cpio archive */
-       if (installArchive(archivePrefix, fd, files, archiveFileCount, notify, 
-                          NULL, tmpPath, 
-                          archiveSizePtr ? *archiveSizePtr : 0)) {
+       if (installArchive(archivePrefix, fd, files, fileCount, notify, 
+                          NULL, archiveSizePtr ? *archiveSizePtr : 0)) {
            headerFree(h);
-           free(fileList);
            if (replacedList) free(replacedList);
+           if (freeFileMem) freeFileMemory(fileMem);
            return 2;
        }
 
-       if (headerGetEntry(h, RPMTAG_FILEUSERNAME, &type, (void **) &fileOwners, 
-                    &fileCount)) {
-           if (headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type, (void **) &fileGroups, 
-                        &fileCount)) {
-               if (setFileOwnerships(rootdir, fileList, fileOwners, fileGroups, 
-                               fileModesList, instActions, fileCount)) {
-                   free(fileOwners);
-                   free(fileGroups);
-                   free(fileList);
-                   if (replacedList) free(replacedList);
+       if (files) {
+           fileStates = malloc(sizeof(*fileStates) * fileCount);
+           for (i = 0; i < fileCount; i++)
+               fileStates[i] = files[i].state;
 
-                   return 2;
-               }
-               free(fileGroups);
-           }
-           free(fileOwners);
-       }
-       free(fileList);
+           headerAddEntry(h, RPMTAG_FILESTATES, RPM_CHAR_TYPE, fileStates, 
+                           fileCount);
 
-       headerAddEntry(h, RPMTAG_FILESTATES, RPM_CHAR_TYPE, fileStatesList, fileCount);
+           free(fileStates);
+           if (freeFileMem) freeFileMemory(fileMem);
+       }
 
        installTime = time(NULL);
        headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &installTime, 1);
@@ -569,244 +575,54 @@ int rpmInstallPackage(char * rootdir, rpmdb db, int fd, char * location,
 
 #define BLOCKSIZE 1024
 
-/* -1 fileCount means install all files */
-static int installArchive(char * prefix, int fd, struct fileToInstall * files,
+/* NULL files means install all files */
+static int installArchive(char * prefix, int fd, struct fileInfo * files,
                          int fileCount, rpmNotifyFunction notify, 
-                         char ** specFile, char * tmpPath, int archiveSize) {
+                         char ** specFile, int archiveSize) {
     gzFile stream;
-    char buf[BLOCKSIZE];
-    pid_t child;
-    int p[2];
-    int statusPipe[2];
-    int bytesRead;
-    int bytes;
-    int status;
-    int cpioFailed = 0;
-    void * oldhandler;
-    int needSecondPipe;
-    char line[1024];
-    int j;
-    int i = 0;
-    int childGotStatus = 0;
-    unsigned long totalSize = 0;
-    unsigned long sizeInstalled = 0;
-    struct fileToInstall fileInstalled;
-    struct fileToInstall * file;
-    char * chptr, * filelist;
-    char ** args;
-    FILE * f;
-    int len;
-    int childDead = 0;
-
-    /* no files to install */
-    if (!fileCount) return 0;
-
-    /* install all files, so don't pass a filelist to cpio */
-    if (fileCount == -1) fileCount = 0;
-
-    /* fd should be a gzipped cpio archive */
-
-    rpmMessage(RPMMESS_DEBUG, "installing archive into %s\n", prefix);
-
-    needSecondPipe = (notify != NULL && !archiveSize) || specFile;
-
-    if (specFile) *specFile = NULL;
-    
-    args = alloca(sizeof(char *) * (fileCount + 10));
-
-    args[i++] = rpmGetVar(RPMVAR_CPIOBIN);
-    args[i++] = "--extract";
-    args[i++] = "--unconditional";
-    args[i++] = "--preserve-modification-time";
-    args[i++] = "--make-directories";
-    args[i++] = "--quiet";
-
-    if (!args[0]) args[0] = "cpio";
-
-    if (needSecondPipe)
-       args[i++] = "--verbose";
-
-    /* note - if fileCount == 0, all files get installed */
-    /* if fileCount > 500, we use a temporary file to pass the file
-       list to cpio rather then args because we're in danger of passing
-       too much argv/env stuff */
-
-    if (fileCount > 500) {
-       filelist = alloca(strlen(tmpPath) + 40);
-
-       rpmMessage(RPMMESS_DEBUG, "using a %s filelist\n", tmpPath);
-       sprintf(filelist, "%s/rpm-cpiofilelist.%d.tmp", tmpPath, 
-               (int) getpid());
-       f = fopen(filelist, "w");
-       if (!f) {
-           rpmError(RPMERR_CREATE, "failed to create %s: %s", filelist,
-                 strerror(errno));
-           return 1;
-       }
-       
-       for (j = 0; j < fileCount; j++) {
-           if ((fputs(files[j].fileName, f) == EOF) || 
-               (fputs("\n", f) == EOF)) {
-               if (errno == ENOSPC) {
-                   rpmError(RPMERR_NOSPACE, "out of space on device");
-               } else {
-                   rpmError(RPMERR_CREATE, "failed to create %s: %s", filelist,
-                         strerror(errno));
-               }
-
-               fclose(f);
-               unlink(filelist);
-               return 1;
-           }
-       }
-
-       fclose(f);
-
-       args[i++] = "--pattern-file";
-       args[i++] = filelist;
-    } else {
-       filelist = NULL;
-       for (j = 0; j < fileCount; j++)
-           args[i++] = files[j].fileName;
-    }
-
-    args[i++] = NULL;
-    
-    stream = gzdopen(fd, "r");
-    pipe(p);
-
-    if (needSecondPipe) {
-       pipe(statusPipe);
-       for (i = 0; i < fileCount; i++)
-           totalSize += files[i].size;
-       qsort(files, fileCount, sizeof(struct fileToInstall), fileCompare);
+    int rc, i;
+    struct cpioFileMapping * map;
+    char * failedFile;
+
+    if (!files) {
+       /* install all files */
+       fileCount = 0;
+    } else if (!fileCount) {
+       /* no files to install */
+       return 0;
     }
 
-    oldhandler = signal(SIGPIPE, SIG_IGN);
-
-    child = fork();
-    if (!child) {
-       chdir(prefix);
-
-       close(p[1]);   /* we don't need to write to it */
-       close(0);      /* stdin will come from the pipe instead */
-       dup2(p[0], 0);
-       close(p[0]);
-
-       if (needSecondPipe) {
-           close(statusPipe[0]);   /* we don't need to read from it*/
-           close(2);               /* stderr will go to a pipe instead */
-           dup2(statusPipe[1], 2);
-           close(statusPipe[1]);
-       }
-
-       execvp(args[0], args);
-
-       _exit(-1);
-    }
+    if (specFile) *specFile = NULL;
 
-    close(p[0]);
-    if (needSecondPipe) {
-       close(statusPipe[1]);
-       fcntl(statusPipe[0], F_SETFL, O_NONBLOCK);
+    map = alloca(sizeof(*map) * fileCount);
+    for (i = 0; i < fileCount; i++) {
+       map[i].archivePath = files[i].cpioPath;
+       map[i].finalPath = files[i].rootedPath;
+       map[i].finalMode = files[i].mode;
+       map[i].finalUid = files[i].uid;
+       map[i].finalGid = files[i].gid;
+       map[i].mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID |
+                         CPIO_MAP_GID;
     }
 
-    do {
-       if (waitpid(child, &status, WNOHANG)) childDead = 1;
-       
-       bytesRead = gzread(stream, buf, sizeof(buf));
-       if (bytesRead < 0) {
-            cpioFailed = 1;
-            childDead = 1;
-            kill(child, SIGTERM);
-       } else if (bytesRead == 0) {
-            /* if it's not dead yet, it will be when we close the pipe */
-            waitpid(child, &status, 0);
-            childDead = 1;
-            childGotStatus = 1;
-       } else if (bytesRead && write(p[1], buf, bytesRead) != bytesRead) {
-            cpioFailed = 1;
-            childDead = 1;
-            kill(child, SIGTERM);
-       }
-
-       if (needSecondPipe) {
-           bytes = read(statusPipe[0], line, sizeof(line));
-
-           while (bytes > 0) {
-               /* the sooner we erase this, the better. less chance
-                  of leaving it sitting around after a SIGINT
-                  (or SIGSEGV!) */
-               if (filelist) {
-                   unlink(filelist);
-                   filelist = NULL;
-               }
-
-               fileInstalled.fileName = line;
-
-               while ((chptr = (strchr(fileInstalled.fileName, '\n')))) {
-                   *chptr = '\0';
-
-                   rpmMessage(RPMMESS_DEBUG, "file \"%s\" complete\n", 
-                               fileInstalled.fileName);
-
-                   if (notify && !archiveSize) {
-                       file = bsearch(&fileInstalled, files, fileCount, 
-                                      sizeof(struct fileToInstall), 
-                                      fileCompare);
-                       if (file) {
-                           sizeInstalled += file->size;
-                           notify(sizeInstalled, totalSize);
-                       }
-                   }
-
-                   if (specFile) {
-                       len = strlen(fileInstalled.fileName);
-                       if (fileInstalled.fileName[len - 1] == 'c' &&
-                           fileInstalled.fileName[len - 2] == 'e' &&
-                           fileInstalled.fileName[len - 3] == 'p' &&
-                           fileInstalled.fileName[len - 4] == 's' &&
-                           fileInstalled.fileName[len - 5] == '.') {
-
-                           if (*specFile) free(*specFile);
-                           *specFile = strdup(fileInstalled.fileName);
-                       }
-                   }
-                
-                   fileInstalled.fileName = chptr + 1;
-               }
-
-               bytes = read(statusPipe[0], line, sizeof(line));
-           }
-       } 
-
-       if (notify && archiveSize) {
-           sizeInstalled += bytesRead;
-           notify(sizeInstalled, archiveSize);
-       }
-    } while (!childDead);
-
-    gzclose(stream);
-    close(p[1]);
-    if (needSecondPipe) close(statusPipe[0]);
-    signal(SIGPIPE, oldhandler);
+    if (notify)
+       notify(0, archiveSize);
 
-    if (!childGotStatus)
-       waitpid(child, &status, 0);
+    qsort(map, fileCount, sizeof(*map), cpioFileMapCmp);
 
-    if (filelist) {
-       unlink(filelist);
-    }
+    stream = gzdopen(fd, "r");
+    rc = cpioInstallArchive(stream, map, fileCount, NULL, &failedFile);
 
-    if (cpioFailed || !WIFEXITED(status) || WEXITSTATUS(status)) {
+    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");
+       rpmError(RPMERR_CPIO, "unpacking of archive failed on file %s: %d", 
+                failedFile, rc);
        return 1;
     }
 
     if (notify)
-       notify(totalSize, totalSize);
+       notify(archiveSize, archiveSize);
 
     return 0;
 }
@@ -851,212 +667,6 @@ static int packageAlreadyInstalled(rpmdb db, char * name, char * version,
     return 0;
 }
 
-static int setFileOwnerships(char * rootdir, char ** fileList, 
-                            char ** fileOwners, char ** fileGroups, 
-                            int_16 * fileModesList,
-                            enum instActions * instActions, int fileCount) {
-    int i;
-    char * chptr;
-    int doFork = 0;
-    pid_t child;
-    int status;
-
-    rpmMessage(RPMMESS_DEBUG, "setting file owners and groups by name (not id)\n");
-
-    chptr = rootdir;
-    while (*chptr && *chptr == '/') 
-       chptr++;
-
-    if (*chptr) {
-       rpmMessage(RPMMESS_DEBUG, "forking child to setid's in chroot() "
-               "environment\n");
-       doFork = 1;
-
-       if ((child = fork())) {
-           waitpid(child, &status, 0);
-           return 0;
-       } else {
-           chroot(rootdir);
-       }
-    }
-
-    for (i = 0; i < fileCount; i++) {
-       if (instActions[i] != SKIP) {
-           /* ignore errors here - setFileOwner handles them reasonable
-              and we want to keep running */
-           setFileOwner(fileList[i], fileOwners[i], fileGroups[i],
-                        fileModesList[i]);
-       }
-    }
-
-    if (doFork)
-       _exit(0);
-
-    return 0;
-}
-
-/* setFileOwner() is really poorly implemented. It really ought to use 
-   hash tables. I just made the guess that most files would be owned by 
-   root or the same person/group who owned the last file. Those two values 
-   are cached, everything else is looked up via getpw() and getgr() functions. 
-   If this performs too poorly I'll have to implement it properly :-( */
-
-static int setFileOwner(char * file, char * owner, char * group, 
-                       int_16 mode ) {
-    uid_t uid;
-    gid_t gid;
-
-    if ((uid = unameToUid(owner)) == -1) {
-       rpmError(RPMERR_NOUSER, "user %s does not exist - using root", owner);
-       uid = 0;
-       /* turn off the suid bit */
-       mode &= ~S_ISUID;
-    } 
-       
-    if ((gid = gnameToGid(group)) == -1) {
-       rpmError(RPMERR_NOUSER, "group %s does not exist - using root", group);
-       gid = 0;
-       /* turn off the sgid bit */
-       mode &= ~S_ISGID;
-    } 
-
-    rpmMessage(RPMMESS_DEBUG, "%s owned by %s (%d), group %s (%d) mode %o\n",
-               file, owner, uid, group, gid, mode & 07777);
-    if (chown(file, uid, gid)) {
-       rpmError(RPMERR_CHOWN, "cannot set owner and group for %s - %s",
-               file, strerror(errno));
-       /* screw with the permissions so it's not SUID and 0.0 */
-       chmod(file, mode & ~S_ISUID & ~S_ISGID);
-       return 1;
-    }
-    /* Also set the mode according to what is stored in the header */
-    if (! S_ISLNK(mode)) {
-       if (chmod(file, mode & 07777)) {
-           rpmError(RPMERR_CHOWN, "cannot change mode for %s - %s",
-                 file, strerror(errno));
-           /* try to screw with the permissions so it's not SUID and 0.0 */
-           chmod(file, mode & ~S_ISUID & ~S_ISGID);
-           return 1;
-       }
-    }
-
-    return 0;
-}
-
-/* This could be more efficient. A brute force tokenization and mkdir's
-   seems like horrible overkill. I did make it know better then trying to 
-   create the same directory string twice in a row though. That should make it 
-   perform adequatally thanks to the sorted filelist.
-
-   This could create directories that should be symlinks :-( RPM building
-   should probably resolve symlinks in paths. 
-
-   This creates directories which are always 0755, despite the current umask */
-
-static int createDirectories(char ** fileList, uint_32 * modesList, 
-                            uint_32 * fileMtimesList, int fileCount) {
-    int i;
-    char * lastDirectory;
-    char * buffer;
-    int bufferLength;
-    int neededLength;
-    char * chptr;
-
-    lastDirectory = malloc(1);
-    lastDirectory[0] = '\0';
-
-    bufferLength = 1000;               /* should be more then adequate */
-    buffer = malloc(bufferLength);
-
-    for (i = 0; i < fileCount; i++) {
-       neededLength = strlen(fileList[i]) + 1;
-       if (neededLength > bufferLength) { 
-           free(buffer);
-           bufferLength = neededLength * 2;
-           buffer = malloc(bufferLength);
-       }
-       strcpy(buffer, fileList[i]);
-       
-       for (chptr = buffer + strlen(buffer) - 1; *chptr; chptr--) {
-           if (*chptr == '/') break;
-       }
-
-       if (! *chptr) continue;         /* no path, just filename */
-       if (chptr == buffer) continue;  /* /filename - no directories */
-
-       *chptr = '\0';                  /* buffer is now just directories */
-
-       if (strcmp(buffer, lastDirectory)) {
-           for (chptr = buffer + 1; *chptr; chptr++) {
-               if (*chptr == '/') {
-                   if (*(chptr -1) != '/') {
-                       *chptr = '\0';
-                       if (mkdirIfNone(buffer, 0755, 0)) {
-                           free(lastDirectory);
-                           free(buffer);
-                           return 1;
-                       }
-                       *chptr = '/';
-                   }
-               }
-           }
-
-           if (mkdirIfNone(buffer, 0755, 0)) {
-               free(lastDirectory);
-               free(buffer);
-               return 1;
-           }
-
-           free(lastDirectory);
-           lastDirectory = strdup(buffer);
-       }
-
-       if (S_ISDIR(modesList[i])) {
-           if (mkdirIfNone(fileList[i], 0755, fileMtimesList[i])) {
-               free(lastDirectory);
-               free(buffer);
-               return 1;
-           }
-       }
-    }
-
-    free(lastDirectory);
-    free(buffer);
-
-    return 0;
-}
-
-static int mkdirIfNone(char * directory, mode_t perms, uint_32 mtime) {
-    int rc;
-    char * chptr;
-    struct utimbuf stamp;
-
-    for (chptr = directory; *chptr; chptr++)
-       if (*chptr != '/') break;
-    if (!*chptr) return 0;
-
-    if (exists(directory)) {
-       return 0;
-    }
-
-    rpmMessage(RPMMESS_DEBUG, "trying to make %s\n", directory);
-
-    rc = mkdir(directory, perms);
-    if (!rc) {
-       if (mtime) {
-           stamp.actime = mtime;
-           stamp.modtime = mtime;
-           utime(directory, &stamp);
-       }
-       return 0;
-    }
-
-    rpmError(RPMERR_MKDIR, "failed to create %s - %s", directory, 
-         strerror(errno));
-
-    return errno;
-}
-
 static int filecmp(short mode1, char * md51, char * link1, 
                   short mode2, char * md52, char * link2) {
     enum fileTypes what1, what2;
@@ -1167,11 +777,9 @@ static enum instActions decideFileFate(char * filespec, short dbMode,
 /* return 0: okay, continue install */
 /* return 1: problem, halt install */
 
-static int instHandleSharedFiles(rpmdb db, int ignoreOffset, char ** fileList, 
-                                char ** fileMd5List, int_16 * fileModesList,
-                                char ** fileLinkList, uint_32 * fileFlagsList,
-                                int fileCount, enum instActions * instActions, 
-                                char ** prefixedFileList, int * notErrors,
+static int instHandleSharedFiles(rpmdb db, int ignoreOffset,
+                                struct fileInfo * files,
+                                int fileCount, int * notErrors,
                                 struct replacedFile ** repListPtr, int flags) {
     struct sharedFile * sharedList;
     int secNum, mainNum;
@@ -1190,19 +798,24 @@ static int instHandleSharedFiles(rpmdb db, int ignoreOffset, char ** fileList,
     struct replacedFile * replacedList;
     int numReplacedFiles, numReplacedAlloced;
     char state;
+    char ** fileList;
+
+    fileList = malloc(sizeof(*fileList) * fileCount);
+    for (i = 0; i < fileCount; i++)
+       fileList[i] = files[i].rootedPath;
 
     if (findSharedFiles(db, 0, fileList, fileCount, &sharedList, 
                        &sharedCount)) {
+       free(fileList);
        return 1;
     }
+    free(fileList);
     
     numReplacedAlloced = 10;
     numReplacedFiles = 0;
     replacedList = malloc(sizeof(*replacedList) * numReplacedAlloced);
 
     for (i = 0; i < sharedCount; i++) {
-       if (sharedList[i].secRecOffset == ignoreOffset) continue;
-
        if (secOffset != sharedList[i].secRecOffset) {
            if (secOffset) {
                headerFree(sech);
@@ -1273,13 +886,14 @@ static int instHandleSharedFiles(rpmdb db, int ignoreOffset, char ** fileList,
            continue;
        }
 
-       if (filecmp(fileModesList[mainNum], fileMd5List[mainNum]
-                   fileLinkList[mainNum], secFileModesList[secNum],
+       if (filecmp(files[mainNum].mode, files[mainNum].md5
+                   files[mainNum].link, secFileModesList[secNum],
                    secFileMd5List[secNum], secFileLinksList[secNum])) {
            if (!(flags & RPMINSTALL_REPLACEFILES) && !(*intptr)) {
                rpmError(RPMERR_PKGINSTALLED, "%s conflicts with file from "
-                     "%s-%s-%s", fileList[sharedList[i].mainFileNumber],
-                     name, version, release);
+                        "%s-%s-%s", 
+                        files[sharedList[i].mainFileNumber].relativePath,
+                        name, version, release);
                rc = 1;
            } else {
                if (numReplacedFiles == numReplacedAlloced) {
@@ -1296,20 +910,20 @@ static int instHandleSharedFiles(rpmdb db, int ignoreOffset, char ** fileList,
                numReplacedFiles++;
 
                rpmMessage(RPMMESS_DEBUG, "%s from %s-%s-%s will be replaced\n", 
-                       fileList[sharedList[i].mainFileNumber],
+                       files[sharedList[i].mainFileNumber].relativePath,
                        name, version, release);
            }
        }
 
        /* if this is a config file, we need to be carefull here */
-       if (fileFlagsList[sharedList[i].mainFileNumber] & RPMFILE_CONFIG ||
+       if (files[sharedList[i].mainFileNumber].flags & RPMFILE_CONFIG ||
            secFileFlagsList[sharedList[i].secFileNumber] & RPMFILE_CONFIG) {
-           instActions[sharedList[i].mainFileNumber] = 
-               decideFileFate(prefixedFileList[mainNum]
+           files[sharedList[i].mainFileNumber].action = 
+               decideFileFate(files[mainNum].rootedPath
                               secFileModesList[secNum],
                               secFileMd5List[secNum], secFileLinksList[secNum],
-                              fileModesList[mainNum], fileMd5List[mainNum],
-                              fileLinkList[mainNum]
+                              files[mainNum].mode, files[mainNum].md5,
+                              files[mainNum].link
                               !headerIsEntry(sech, RPMTAG_RPMVERSION));
        }
     }
@@ -1333,11 +947,6 @@ static int instHandleSharedFiles(rpmdb db, int ignoreOffset, char ** fileList,
     return rc;
 }
 
-static int fileCompare(const void * one, const void * two) {
-    return strcmp(((struct fileToInstall *) one)->fileName,
-                 ((struct fileToInstall *) two)->fileName);
-}
-
 /* 0 success */
 /* 1 bad magic */
 /* 2 error */
@@ -1392,17 +1001,21 @@ static int installSources(Header h, char * rootdir, int fd,
        headerGetEntry(h, RPMTAG_NAME, &type, (void *) &name, &count);
        headerGetEntry(h, RPMTAG_VERSION, &type, (void *) &version, &count);
        headerGetEntry(h, RPMTAG_RELEASE, &type, (void *) &release, &count);
-       if (!headerGetEntry(h, RPMTAG_ARCHIVESIZE, &type, (void *) &archiveSizePtr, 
-                     &count))
+       if (!headerGetEntry(h, RPMTAG_ARCHIVESIZE, &type, 
+                               (void *) &archiveSizePtr, &count))
            archiveSizePtr = NULL;
        printf(labelFormat, name, version, release);
        fflush(stdout);
     }
 
+/*
+    FIXME
+
     if (installArchive(realSourceDir, fd, NULL, -1, notify, &specFile, 
                       tmpPath, archiveSizePtr ? *archiveSizePtr : 0)) {
        return 2;
     }
+*/
 
     if (!specFile) {
        rpmError(RPMERR_NOSPEC, "source package contains no .spec file");
@@ -1421,7 +1034,8 @@ static int installSources(Header h, char * rootdir, int fd,
     strcat(correctSpecFile, "/");
     strcat(correctSpecFile, specFile);
 
-    rpmMessage(RPMMESS_DEBUG, "renaming %s to %s\n", instSpecFile, correctSpecFile);
+    rpmMessage(RPMMESS_DEBUG, 
+               "renaming %s to %s\n", instSpecFile, correctSpecFile);
     if (rename(instSpecFile, correctSpecFile)) {
        /* try copying the file */
        if (moveFile(instSpecFile, correctSpecFile))
@@ -1460,8 +1074,8 @@ static int markReplacedFiles(rpmdb db, struct replacedFile * replList) {
                headerFree(sh);
            }
 
-           headerGetEntry(secHeader, RPMTAG_FILESTATES, &type, (void **) &secStates, 
-                    &count);
+           headerGetEntry(secHeader, RPMTAG_FILESTATES, &type, 
+                          (void **) &secStates, &count);
        }
 
        /* by now, secHeader is the right header to modify, secStates is
@@ -1718,16 +1332,3 @@ static int copyFile(char * sourceName, char * destName) {
 
     return 0;
 }
-
-static void unglobFilename(char * dptr, char * sptr) {
-    while (*sptr) {
-       switch (*sptr) {
-         case '*': case '[': case ']': case '?': case '\\':
-           *dptr++ = '\\';
-           /*fallthrough*/
-         default:
-           *dptr++ = *sptr++;
-       }
-    }
-    *dptr++ = *sptr;
-}
index d2827c8..43505d3 100644 (file)
@@ -179,7 +179,7 @@ int dosetenv(const char *name, const char *value, int overwrite) {
    is looked up via getpw() and getgr() functions.  If this performs
    too poorly I'll have to implement it properly :-( */
 
-uid_t unameToUid(char * thisUname) {
+int unameToUid(char * thisUname, uid_t * uid) {
     static char * lastUname = NULL;
     static int lastUnameLen = 0;
     static int lastUnameAlloced;
@@ -203,17 +203,18 @@ uid_t unameToUid(char * thisUname) {
 
        pwent = getpwnam(thisUname);
        if (!pwent) {
-           lastUnameLen = 0;
-           lastUid = -1;
+           return -1;
        } else {
            lastUid = pwent->pw_uid;
        }
     }
 
-    return lastUid;
+    *uid = lastUid;
+
+    return 0;
 }
 
-uid_t gnameToGid(char * thisGname) {
+int gnameToGid(char * thisGname, gid_t * gid) {
     static char * lastGname = NULL;
     static int lastGnameLen = 0;
     static int lastGnameAlloced;
@@ -237,14 +238,15 @@ uid_t gnameToGid(char * thisGname) {
 
        grent = getgrnam(thisGname);
        if (!grent) {
-           lastGnameLen = 0;
-           lastGid = -1;
+           return -1;
        } else {
            lastGid = grent->gr_gid;
        }
     }
 
-    return lastGid;
+    *gid = lastGid;
+
+    return 0;
 }
 
 char * uidToUname(uid_t uid) {
index 8948a1f..d170da9 100644 (file)
@@ -18,8 +18,8 @@ int doputenv(const char * str);
 
 /* These may be called w/ a NULL argument to flush the cache -- they return
    -1 if the user can't be found */
-uid_t unameToUid(char * thisUname);
-uid_t gnameToGid(char * thisGname);
+int unameToUid(char * thisUname, uid_t * uid);
+int gnameToGid(char * thisGname, gid_t * gid);
 
 /* Call w/ -1 to flush the cache, returns NULL if the user can't be found */
 char * uidToUname(uid_t uid);