Commit to install file state machine.
authorjbj <devnull@localhost>
Mon, 29 Jan 2001 22:53:48 +0000 (22:53 +0000)
committerjbj <devnull@localhost>
Mon, 29 Jan 2001 22:53:48 +0000 (22:53 +0000)
CVS patchset: 4509
CVS date: 2001/01/29 22:53:48

lib/cpio.c
lib/cpio.h
lib/header.h
lib/install.c
lib/rollback.c
lib/rollback.h
lib/transaction.c
lib/uninstall.c
po/rpm.pot
rpm.c

index 042cd8e..5aaf16a 100644 (file)
@@ -17,6 +17,7 @@
 /*@access FD_t@*/
 /*@access rpmTransactionSet@*/
 /*@access TFI_t@*/
+/*@access FSM_t@*/
 
 #define CPIO_NEWC_MAGIC        "070701"
 #define CPIO_CRC_MAGIC "070702"
 
 #define        alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
 
+static inline /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
+    if (this)  free((void *)this);
+    return NULL;
+}
+
+int _fsm_debug = 0;
+
 /** \ingroup payload
  * Defines a single file to be included in a cpio payload.
  */
 struct cpioFileMapping {
 /*@dependent@*/ const char * archivePath; /*!< Path to store in cpio archive. */
 /*@dependent@*/ const char * dirName;  /*!< Payload file directory. */
-/*@dependent@*/ const char * subdir;
 /*@dependent@*/ const char * baseName; /*!< Payload file base name. */
-/*@dependent@*/ const char * suffix;
 /*@dependent@*/ const char * md5sum;   /*!< File MD5 sum (NULL disables). */
     fileAction action;
     int commit;
@@ -87,34 +93,6 @@ struct cpioCrcPhysicalHeader {
 
 #define        PHYS_HDR_SIZE   110             /*!< Don't depend on sizeof(struct) */
 
-/** \ingroup payload
- * File name and stat information.
- */
-struct cpioHeader {
-/*@owned@*/ const char * path;
-/*@owned@*/ const char * opath;
-    FD_t cfd;
-/*@owned@*/ void * mapi;
-/*@dependent@*/ const void * map;
-/*@owned@*/ struct hardLink * links;
-/*@dependent@*/ struct hardLink * li;
-/*@dependent@*/ const char ** failedFile;
-    const char * subdir;
-    char subbuf[64];
-    const char * suffix;
-    char sufbuf[64];
-    int postpone;
-    mode_t dperms;
-    mode_t fperms;
-    int rc;
-    int action;
-    fileStage a;
-    struct stat sb;
-};
-
-/* Forward reference. */
-static int hdrStage(struct cpioHeader * hdr, fileStage a);
-
 #if 0
 static void prtli(const char *msg, struct hardLink * li)
 {
@@ -127,28 +105,28 @@ static void prtli(const char *msg, struct hardLink * li)
  */
 static int mapFlags(const void * this, cpioMapFlags mask) {
     const struct cpioFileMapping * map = this;
-    return (map->mapFlags & mask);
+    return (map ? (map->mapFlags & mask) : 0);
 }
 
 /**
  */
 static int mapCommit(const void * this) {
     const struct cpioFileMapping * map = this;
-    return map->commit;
+    return (map ? map->commit : 0);
 }
 
 /**
  */
 static int mapAction(const void * this) {
     const struct cpioFileMapping * map = this;
-    return map->action;
+    return (map ? map->action : FA_UNKNOWN);
 }
 
 /**
  */
 static /*@only@*/ const char * mapArchivePath(const void * this) {
     const struct cpioFileMapping * map = this;
-    return xstrdup(map->archivePath);
+    return (map ? xstrdup(map->archivePath) : NULL);
 }
 
 /**
@@ -156,21 +134,26 @@ static /*@only@*/ const char * mapArchivePath(const void * this) {
  * @param st                   path mode type (dirs map differently)
  */
 static /*@only@*/ const char * mapFsPath(const void * this,
-       const struct stat * st)
+       const struct stat * st, const char * subdir, const char * suffix)
 {
     const struct cpioFileMapping * map = this;
-    int nb = strlen(map->dirName) +
-       (st && map->subdir && !S_ISDIR(st->st_mode) ? strlen(map->subdir) : 0) +
-       (st && map->suffix && !S_ISDIR(st->st_mode) ? strlen(map->suffix) : 0) +
-       strlen(map->baseName) + 1;
-    char * t = xmalloc(nb);
-    const char * s = t;
-    t = stpcpy(t, map->dirName);
-    if (st && map->subdir && !S_ISDIR(st->st_mode))
-       t = stpcpy(t, map->subdir);
-    t = stpcpy(t, map->baseName);
-    if (st && map->suffix && !S_ISDIR(st->st_mode))
-       t = stpcpy(t, map->suffix);
+    const char * s = NULL;
+
+    if (map) {
+       int nb;
+       char * t;
+       nb = strlen(map->dirName) +
+           (st && subdir && !S_ISDIR(st->st_mode) ? strlen(subdir) : 0) +
+           (st && suffix && !S_ISDIR(st->st_mode) ? strlen(suffix) : 0) +
+           strlen(map->baseName) + 1;
+       s = t = xmalloc(nb);
+       t = stpcpy(t, map->dirName);
+       if (st && subdir && !S_ISDIR(st->st_mode))
+           t = stpcpy(t, subdir);
+       t = stpcpy(t, map->baseName);
+       if (st && suffix && !S_ISDIR(st->st_mode))
+           t = stpcpy(t, suffix);
+    }
     return s;
 }
 
@@ -178,28 +161,28 @@ static /*@only@*/ const char * mapFsPath(const void * this,
  */
 static mode_t mapFinalMode(const void * this) {
     const struct cpioFileMapping * map = this;
-    return map->finalMode;
+    return (map ? map->finalMode : 0);
 }
 
 /**
  */
 static uid_t mapFinalUid(const void * this) {
     const struct cpioFileMapping * map = this;
-    return map->finalUid;
+    return (map ? map->finalUid : 0);
 }
 
 /**
  */
 static gid_t mapFinalGid(const void * this) {
     const struct cpioFileMapping * map = this;
-    return map->finalGid;
+    return (map ? map->finalGid : 0);
 }
 
 /**
  */
 static /*@observer@*/ const char * const mapMd5sum(const void * this) {
     const struct cpioFileMapping * map = this;
-    return map->md5sum;
+    return (map ? map->md5sum : NULL);
 }
 
 /**
@@ -213,41 +196,86 @@ struct mapi {
 
 /**
  */
-static const void * mapLink(const void * this) {
+static /*@null@*/ void * mapLink(const void * this) {
     const struct cpioFileMapping * omap = this;
-    struct cpioFileMapping * nmap = xcalloc(1, sizeof(*nmap));
-    *nmap = *omap;     /* structure assignment */
+    struct cpioFileMapping * nmap = NULL;
+    if (omap) {
+       nmap = xcalloc(1, sizeof(*nmap));
+       *nmap = *omap;  /* structure assignment */
+    }
     return nmap;
 }
 
 /**
  */
-static void mapFree(/*@only@*/ const void * this) {
-    free((void *)this);
+static inline /*@null@*/ void * mapFree(/*@only@*/ const void * this) {
+    return _free((void *)this);
 }
 
+struct dnli {
+/*@dependent@*/ TFI_t fi;
+/*@only@*/ char * active;
+    int dc;
+    int i;
+};
+
 /**
  */
-static void mapFreeIterator(/*@only@*/ const void * this)
+static /*@null@*/ void * dnlFreeIterator(/*@only@*/ const void * this)
 {
-    struct mapi * mapi;
-    rpmTransactionSet ts;
-    TFI_t fi;
+    if (this) {
+       struct dnli * dnli = (void *)this;
+       if (dnli->active) free(dnli->active);
+    }
+    return _free(this);
+}
 
-    if (this == NULL)
-       return;
+static int dnlCount(void * this)
+{
+    struct dnli * dnli = this;
+    return dnli->dc;
+}
+/**
+ */
+static /*@only@*/ void * dnlInitIterator(/*@null@*/ const void * this)
+{
+    const struct mapi * mapi = this;
+    struct dnli * dnli;
+    TFI_t fi;
+    int i;
 
-    mapi = (void *)this;
-    ts = mapi->ts;
+    if (mapi == NULL)
+       return NULL;
     fi = mapi->fi;
+    dnli = xcalloc(1, sizeof(*dnli));
+    dnli->fi = fi;
+    dnli->i = fi->dc;
+    dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
+    for (i = 0; i < fi->fc; i++)
+        if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
+    for (i = 0, dnli->dc = 0; i < fi->dc; i++)
+       if (dnli->active[i]) dnli->dc++;
+    return dnli;
+}
 
-    if (ts && ts->notify) {
-       unsigned int archiveSize = (fi->archiveSize ? fi->archiveSize : 100);
-       (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
-                       archiveSize, archiveSize,
-                       (fi->ap ? fi->ap->key : NULL), ts->notifyData);
-    }
-    free((void *)this);
+/**
+ */
+static const char * dnlNextIterator(void * this) {
+    struct dnli * dnli = this;
+    TFI_t fi = dnli->fi;
+    int i;
+
+    do {
+       i = --dnli->i;
+    } while (i >= 0 && !dnli->active[i]);
+    return (i >= 0 ? fi->dnl[i] : NULL);
+}
+
+/**
+ */
+static /*@null@*/ void * mapFreeIterator(/*@only@*/ /*@null@*/ const void * this)
+{
+    return _free((void *)this);
 }
 
 /**
@@ -307,6 +335,126 @@ static const void * mapNextIterator(void * this) {
     return map;
 }
 
+#define        SUFFIX_RPMORIG  ".rpmorig"
+#define        SUFFIX_RPMSAVE  ".rpmsave"
+#define        SUFFIX_RPMNEW   ".rpmnew"
+
+int pkgAction(const rpmTransactionSet ts, TFI_t fi, int i, fileStage a)
+{
+    int nb = (!ts->chrootDone ? strlen(ts->rootDir) : 0);
+    char * opath = alloca(nb + fi->dnlmax + fi->bnlmax + 64);
+    char * o = (!ts->chrootDone ? stpcpy(opath, ts->rootDir) : opath);
+    char * npath = alloca(nb + fi->dnlmax + fi->bnlmax + 64);
+    char * n = (!ts->chrootDone ? stpcpy(npath, ts->rootDir) : npath);
+    char * ext = NULL;
+    char * t;
+    int rc = 0;
+
+    rpmMessage(RPMMESS_DEBUG, _("   file: %s%s action: %s\n"),
+               fi->dnl[fi->dil[i]], fi->bnl[i],
+               fileActionString((fi->actions ? fi->actions[i] : FA_UNKNOWN)) );
+
+    switch (fi->actions[i]) {
+    case FA_SKIP:
+    case FA_SKIPMULTILIB:
+    case FA_UNKNOWN:
+       return 0;
+       /*@notreached@*/ break;
+
+    case FA_CREATE:
+       assert(fi->type == TR_ADDED);
+       return 0;
+       /*@notreached@*/ break;
+
+    case FA_SKIPNSTATE:
+       if (fi->type == TR_ADDED)
+           fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
+       return 0;
+       /*@notreached@*/ break;
+
+    case FA_SKIPNETSHARED:
+       if (fi->type == TR_ADDED)
+               fi->fstates[i] = RPMFILE_STATE_NETSHARED;
+       return 0;
+       /*@notreached@*/ break;
+    case FA_BACKUP:
+       ext = (fi->type == TR_ADDED ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE);
+       break;
+
+    case FA_ALTNAME:
+       assert(fi->type == TR_ADDED);
+       ext = SUFFIX_RPMNEW;
+       t = xmalloc(strlen(fi->bnl[i]) + strlen(ext) + 1);
+       (void)stpcpy(stpcpy(t, fi->bnl[i]), ext);
+       rpmMessage(RPMMESS_WARNING, _("%s: %s%s created as %s\n"),
+                       fiTypeString(fi), fi->dnl[fi->dil[i]], fi->bnl[i], t);
+       fi->bnl[i] = t;         /* XXX memory leak iff i = 0 */
+       return 0;
+       /*@notreached@*/ break;
+
+    case FA_SAVE:
+       assert(fi->type == TR_ADDED);
+       ext = SUFFIX_RPMSAVE;
+       break;
+
+    case FA_REMOVE:
+       assert(fi->type == TR_REMOVED);
+       /* Append file name to (possible) root dir. */
+       (void) stpcpy( stpcpy(o, fi->dnl[fi->dil[i]]), fi->bnl[i]);
+       if (S_ISDIR(fi->fmodes[i])) {
+           rc = rmdir(opath);
+           if (!rc) return rc;
+           switch (errno) {
+           case ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
+           case ENOTEMPTY:
+#ifdef NOTYET
+               if (fi->fflags[i] & RPMFILE_MISSINGOK)
+                   return 0;
+#endif
+               rpmError(RPMERR_RMDIR, 
+                       _("%s: cannot remove %s - directory not empty\n"), 
+                               fiTypeString(fi), o);
+               break;
+           default:
+               rpmError(RPMERR_RMDIR,
+                               _("%s rmdir of %s failed: %s\n"),
+                               fiTypeString(fi), o, strerror(errno));
+               break;
+           }
+           return 1;
+           /*@notreached@*/ break;
+       }
+       rc = unlink(opath);
+       if (!rc) return rc;
+       if (errno == ENOENT && (fi->fflags[i] & RPMFILE_MISSINGOK))
+           return 0;
+       rpmError(RPMERR_UNLINK, _("%s removal of %s failed: %s\n"),
+                               fiTypeString(fi), o, strerror(errno));
+       return 1;
+    }
+
+    if (ext == NULL) return 0;
+
+    /* Append file name to (possible) root dir. */
+    (void) stpcpy( stpcpy(o, fi->dnl[fi->dil[i]]), fi->bnl[i]);
+
+    /* XXX TR_REMOVED dinna do this. */
+    rc = access(opath, F_OK);
+    if (rc != 0) return 0;
+
+    (void) stpcpy( stpcpy(n, o), ext);
+    rpmMessage(RPMMESS_WARNING, _("%s: %s saved as %s\n"),
+                       fiTypeString(fi), o, n);
+
+    rc = rename(opath, npath);
+    if (!rc) return rc;
+
+    rpmError(RPMERR_RENAME, _("%s rename of %s to %s failed: %s\n"),
+                       fiTypeString(fi), o, n, strerror(errno));
+    return 1;
+
+}
+
 /**
  */
 static int cpioStrCmp(const void * a, const void * b) {
@@ -326,14 +474,14 @@ static int cpioStrCmp(const void * a, const void * b) {
 
 /**
  */
-static const void * mapFind(void * this, const char * hdrPath) {
+static const void * mapFind(void * this, const char * fsmPath) {
     struct mapi * mapi = this;
     const TFI_t fi = mapi->fi;
     const char ** p;
 
-    p = bsearch(&hdrPath, fi->apath, fi->fc, sizeof(hdrPath), cpioStrCmp);
+    p = bsearch(&fsmPath, fi->apath, fi->fc, sizeof(fsmPath), cpioStrCmp);
     if (p == NULL) {
-       fprintf(stderr, "*** not mapped %s\n", hdrPath);
+       fprintf(stderr, "*** not mapped %s\n", fsmPath);
        return NULL;
     }
     mapi->i = p - fi->apath;
@@ -341,6 +489,114 @@ static const void * mapFind(void * this, const char * hdrPath) {
 }
 
 /**
+ * Create and initialize set of hard links.
+ * @param st           link stat info
+ * @param hltype       type of hard link set to create
+ * @return             pointer to set of hard links
+ */
+static /*@only@*/ struct hardLink * newHardLink(const struct stat * st,
+                               enum hardLinkType hltype)       /*@*/
+{
+    struct hardLink * li = xcalloc(1, sizeof(*li));
+
+    li->next = NULL;
+    li->nlink = st->st_nlink;
+    li->dev = st->st_dev;
+    li->inode = st->st_ino;
+    li->createdPath = -1;
+
+    switch (hltype) {
+    case HARDLINK_INSTALL:
+       li->linksLeft = st->st_nlink;
+       li->fileMaps = xcalloc(st->st_nlink, sizeof(li->fileMaps[0]));
+       li->files = NULL;
+       break;
+    case HARDLINK_BUILD:
+       li->linksLeft = 0;
+       li->fileMaps = NULL;
+       li->files = xcalloc(st->st_nlink, sizeof(*li->files));
+       break;
+    }
+
+    {  struct stat * myst = (struct stat *) &li->sb;
+       *myst = *st;    /* structure assignment */
+    }
+
+    return li;
+}
+
+/**
+ * Destroy set of hard links.
+ * @param li           set of hard links
+ */
+static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink * li)
+{
+    if (li) {
+       if (li->files) {
+           int i;
+           for (i = 0; i < li->nlink; i++) {
+               /*@-unqualifiedtrans@*/
+               li->files[i] = _free(li->files[i]);
+               /*@=unqualifiedtrans@*/
+           }
+       }
+       li->files = _free(li->files);
+       li->fileMaps = _free(li->fileMaps);
+    }
+    return _free(li);
+}
+
+/** \ingroup payload
+ * File name and stat information.
+ */
+struct cpioHeader {
+/*@owned@*/ const char * path;
+/*@owned@*/ const char * opath;
+    FD_t cfd;
+/*@owned@*/ void * mapi;
+/*@dependent@*/ const void * map;
+/*@owned@*/ struct hardLink * links;
+/*@dependent@*/ struct hardLink * li;
+/*@dependent@*/ const char ** failedFile;
+/*@owned@*/ short * dnlx;
+/*@shared@*/ const char * subdir;
+    char subbuf[64];   /* XXX eliminate */
+/*@shared@*/ const char * suffix;
+    char sufbuf[64];   /* XXX eliminate */
+/*@only@*/ char * ldn;
+    int ldnlen;
+    int ldnalloc;
+    int postpone;
+    mode_t dperms;
+    mode_t fperms;
+    int rc;
+    fileAction action;
+    fileStage stage;
+    struct stat sb;
+};
+
+FSM_t newFSM(void) {
+    FSM_t fsm = xcalloc(1, sizeof(*fsm));
+    return fsm;
+}
+
+FSM_t freeFSM(FSM_t fsm)
+{
+    if (fsm) {
+       if (fsm->path)  free((void *)fsm->path);
+       while ((fsm->li = fsm->links) != NULL) {
+           fsm->links = fsm->li->next;
+           fsm->li->next = NULL;
+           fsm->li = freeHardLink(fsm->li);
+       }
+       fsm->dnlx = _free(fsm->dnlx);
+       fsm->ldn = _free(fsm->ldn);
+       fsm->mapi = mapFreeIterator(fsm->mapi);
+    }
+    return _free(fsm);
+}
+
+/**
  * Read data from payload.
  * @param cfd          payload file handle
  * @retval vbuf                data from read
@@ -350,18 +606,18 @@ static const void * mapFind(void * this, const char * hdrPath) {
 static inline off_t saferead(FD_t cfd, /*@out@*/void * vbuf, size_t amount)
        /*@modifies cfd, *vbuf @*/
 {
-    off_t rc = 0;
     char * buf = vbuf;
+    off_t rc = 0;
 
     while (amount > 0) {
        size_t nb;
 
        nb = Fread(buf, sizeof(buf[0]), amount, cfd);
        if (nb <= 0)
-               return nb;
+           return nb;
        rc += nb;
        if (rc >= amount)
-               break;
+           break;
        buf += nb;
        amount -= nb;
     }
@@ -385,21 +641,6 @@ static inline off_t ourread(FD_t cfd, /*@out@*/void * buf, size_t size)
 }
 
 /**
- * Align input payload handle, skipping input bytes.
- * @param cfd          payload file handle
- * @param modulo       data alignment
- */
-static inline void padinfd(FD_t cfd, int modulo)
-       /*@modifies cfd @*/
-{
-    int buf[10];
-    int amount;
-
-    amount = (modulo - fdGetCpioPos(cfd) % modulo) % modulo;
-    (void)ourread(cfd, buf, amount);
-}
-
-/**
  * Write data to payload.
  * @param cfd          payload file handle
  * @param vbuf         data to write
@@ -409,18 +650,18 @@ static inline void padinfd(FD_t cfd, int modulo)
 static inline off_t safewrite(FD_t cfd, const void * vbuf, size_t amount)
        /*@modifies cfd @*/
 {
-    off_t rc = 0;
     const char * buf = vbuf;
+    off_t rc = 0;
 
     while (amount > 0) {
        size_t nb;
 
        nb = Fwrite(buf, sizeof(buf[0]), amount, cfd);
        if (nb <= 0)
-               return nb;
+           return nb;
        rc += nb;
        if (rc >= amount)
-               break;
+           break;
        buf += nb;
        amount -= nb;
     }
@@ -437,10 +678,10 @@ static inline off_t safewrite(FD_t cfd, const void * vbuf, size_t amount)
 static inline int padoutfd(FD_t cfd, size_t * where, int modulo)
        /*@modifies cfd, *where @*/
 {
-    static int buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    static int buf[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
     int amount;
 
-    amount = (modulo - *where % modulo) % modulo;
+    amount = (modulo - (*where % modulo)) % modulo;
     *where += amount;
 
     if (safewrite(cfd, buf, amount) != amount)
@@ -484,19 +725,18 @@ static int strntoul(const char *str, /*@out@*/char **endptr, int base, int num)
 
 /**
  * Process next cpio heasder.
- * @retval hdr         file path and stat info
+ * @retval fsm         file path and stat info
  * @return             0 on success
  */
-static int getNextHeader(struct cpioHeader * hdr)
-       /*@modifies hdr->cfd, hdr->path, hdr->sb  @*/
+static int getNextHeader(FSM_t fsm, struct stat * st)
+       /*@modifies fsm->cfd, fsm->path, *st @*/
 {
     struct cpioCrcPhysicalHeader physHeader;
-    struct stat * st = &hdr->sb;
     int nameSize;
     char * end;
     int major, minor;
 
-    if (ourread(hdr->cfd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE)
+    if (ourread(fsm->cfd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE)
        return CPIOERR_READ_FAILED;
 
     if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
@@ -522,122 +762,44 @@ static int getNextHeader(struct cpioHeader * hdr)
     GET_NUM_FIELD(physHeader.namesize, nameSize);
 
     {  char * t = xmalloc(nameSize + 1);
-       if (ourread(hdr->cfd, t, nameSize) != nameSize) {
+       if (ourread(fsm->cfd, t, nameSize) != nameSize) {
            free(t);
-           hdr->path = NULL;
+           fsm->path = NULL;
            return CPIOERR_BAD_HEADER;
        }
-       hdr->path = t;
+       fsm->path = t;
     }
 
-    /* this is unecessary hdr->path[nameSize] = '\0'; */
+    /* this is unecessary fsm->path[nameSize] = '\0'; */
 
-    padinfd(hdr->cfd, 4);
+    (void) fsmStage(fsm, FSM_POS);
 
     return 0;
 }
 
-/* This could trash files in the path! I'm not sure that's a good thing */
-/**
- * @param hdr          file path and stat info
- * @return             0 on success
- */
-static int createDirectory(struct cpioHeader * hdr)
-       /*@modifies fileSystem @*/
-{
-    int rc = 0;
-
-    {  mode_t st_mode = hdr->sb.st_mode;
-       hdr->sb.st_mode = S_IFDIR | 0000;
-       rc = hdrStage(hdr, FI_VERIFY);
-       hdr->sb.st_mode = st_mode;
-    }
-    if (rc != CPIOERR_LSTAT_FAILED) return rc;
-    rc = 0;
-
-    {  mode_t st_mode = hdr->sb.st_mode;
-       hdr->sb.st_mode = S_IFDIR | 0000;       /* XXX abuse hdr->sb.st_mode */
-       rc = hdrStage(hdr, FI_MKDIR);
-       hdr->sb.st_mode = st_mode;      /* XXX restore hdr->sb.st_mode */
-       if (rc) return rc;
-    }
-
-    {  mode_t st_mode = hdr->sb.st_mode;
-       hdr->sb.st_mode = S_IFDIR | hdr->dperms;/* XXX abuse hdr->sb.st_mode */
-       rc = hdrStage(hdr, FI_CHMOD);
-       hdr->sb.st_mode = st_mode;      /* XXX restore hdr->sb.st_mode */
-       if (rc) return rc;
-    }
-
-    return rc;
-}
-
-/**
- * Create directories in file path (like "mkdir -p").
- * @param hdr          file path and stat info
- * @return             0 on success
- */
-static int inline checkDirectory(struct cpioHeader * hdr)      /*@*/
-{
-/*@only@*/ static char * lastDir = NULL;       /* XXX memory leak */
-    static int lastDirLength = 0;
-    static int lastDirAlloced = 0;
-    char * dn = alloca_strdup(hdr->path);
-    char * te = strrchr(dn, '/');
-    int dnlen = (te ? (te - dn) : 0);
-    int rc = 0;
-
-    if (dnlen == 0) return rc; /* /filename - no directories */
-
-    *te = '\0';                        /* buffer is now just directories */
-
-    if (lastDirLength == dnlen && !strcmp(dn, lastDir)) return 0;
-    if (lastDirAlloced < (dnlen + 1)) {
-       lastDirAlloced = dnlen + 100;
-       lastDir = xrealloc(lastDir, lastDirAlloced);    /* XXX memory leak */
-    }
-    strcpy(lastDir, dn);
-    lastDirLength = dnlen;
-
-    {  const char * path = hdr->path;
-       hdr->path = dn;         /* XXX abuse hdr->path */
-       for (te = dn + 1; *te; te++) {
-           if (*te != '/') continue;
-           *te = '\0';
-           rc = createDirectory(hdr);
-           *te = '/';
-           if (rc) break;
-       }
-       if (!rc) rc = createDirectory(hdr);
-       hdr->path = path;               /* XXX restore hdr->path */
-    }
-
-    return rc;
-}
-
 /**
  * Create file from payload stream.
  * @todo Legacy: support brokenEndian MD5 checks?
- * @param hdr          file path and stat info
+ * @param fsm          file path and stat info
  * @return             0 on success
  */
-static int expandRegular(struct cpioHeader * hdr)
-               /*@modifies fileSystem, hdr->cfd @*/
+static int expandRegular(FSM_t fsm)
+               /*@modifies fileSystem, fsm->cfd @*/
 {
     const char * filemd5;
     FD_t ofd;
     char buf[BUFSIZ];
     int bytesRead;
-    const struct stat * st = &hdr->sb;
+    const struct stat * st = &fsm->sb;
     int left = st->st_size;
     int rc = 0;
 
-    filemd5 = mapMd5sum(hdr->map);
-    rc = hdrStage(hdr, FI_VERIFY);
+    filemd5 = mapMd5sum(fsm->map);
+    rc = fsmStage(fsm, FSM_VERIFY);
     if (rc != CPIOERR_LSTAT_FAILED) return rc;
     rc = 0;
 
-    ofd = Fopen(hdr->path, "w.ufdio");
+    ofd = Fopen(fsm->path, "w.ufdio");
     if (ofd == NULL || Ferror(ofd))
        return CPIOERR_OPEN_FAILED;
 
@@ -646,7 +808,7 @@ static int expandRegular(struct cpioHeader * hdr)
        fdInitMD5(ofd, 0);
 
     while (left) {
-       bytesRead = ourread(hdr->cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
+       bytesRead = ourread(fsm->cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
        if (bytesRead <= 0) {
            rc = CPIOERR_READ_FAILED;
            break;
@@ -661,7 +823,7 @@ static int expandRegular(struct cpioHeader * hdr)
 
        /* don't call this with fileSize == fileComplete */
        if (!rc && left)
-           (void) hdrStage(hdr, FI_NOTIFY);
+           (void) fsmStage(fsm, FSM_NOTIFY);
     }
 
     if (filemd5) {
@@ -675,7 +837,7 @@ static int expandRegular(struct cpioHeader * hdr)
        } else {
            if (strcmp(md5sum, filemd5))
                rc = CPIOERR_MD5SUM_MISMATCH;
-           free((void *)md5sum);
+           md5sum = _free(md5sum);
        }
     }
 
@@ -684,234 +846,177 @@ static int expandRegular(struct cpioHeader * hdr)
     return rc;
 }
 
-/**
- * Create and initialize set of hard links.
- * @param st           link stat info
- * @param hltype       type of hard link set to create
- * @return             pointer to set of hard links
- */
-static /*@only@*/ struct hardLink * newHardLink(const struct stat * st,
-                               enum hardLinkType hltype)       /*@*/
+int fsmStage(FSM_t fsm, fileStage stage)
 {
-    struct hardLink * li = xmalloc(sizeof(*li));
+    fileStage prevStage = fsm->stage;
+    const char * const prev = fileStageString(prevStage);
+    const char * const cur = fileStageString(stage);
+    struct stat * st = &fsm->sb;
+    int rc = fsm->rc;
+    int i;
 
-    li->next = NULL;
-    li->nlink = st->st_nlink;
-    li->dev = st->st_dev;
-    li->inode = st->st_ino;
-    li->createdPath = -1;
+    if (stage & FSM_INTERNAL) {
+       if (_fsm_debug)
+           rpmMessage(RPMMESS_DEBUG, _("%8x %s:%s\t%06o%s\n"), rc, prev, cur,
+               st->st_mode, fsm->path);
+    } else {
+       fsm->stage = stage;
+       if (_fsm_debug || !(stage & FSM_QUIET))
+           rpmMessage(RPMMESS_DEBUG, _("%8x %s\t%06o %s\n"), rc, cur,
+               st->st_mode, fsm->path);
+    }
 
-    switch (hltype) {
-    case HARDLINK_INSTALL:
-       li->linksLeft = st->st_nlink;
-       li->fileMaps = xcalloc(st->st_nlink, sizeof(li->fileMaps[0]));
-       li->files = NULL;
+    switch (stage) {
+    case FSM_UNKNOWN:
        break;
-    case HARDLINK_BUILD:
-       li->linksLeft = 0;
-       li->fileMaps = NULL;
-       li->files = xcalloc(st->st_nlink, sizeof(*li->files));
+    case FSM_CREATE:
+       fsm->path = NULL;
+       fsm->ldn = _free(fsm->ldn);
+       fsm->ldnalloc = fsm->ldnlen = 0;
+       fsm->map = NULL;
+       fsm->links = NULL;
+       fsm->dnlx = NULL;
+       fsm->li = NULL;
+       errno = 0;      /* XXX get rid of EBADF */
        break;
-    }
-
-    {  struct stat * myst = (struct stat *) &li->sb;
-       *myst = *st;    /* structure assignment */
-    }
-
-    return li;
-}
-
-/**
- * Destroy set of hard links.
- * @param li           set of hard links
- */
-static void freeHardLink( /*@only@*/ struct hardLink * li)
-{
-
-    if (li->files) {
-       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);
-       li->files = NULL;
-    }
-    if (li->fileMaps) {
-       free(li->fileMaps);
-       li->fileMaps = NULL;
-    }
-    free(li);
-}
-
-/**
- * Create hard links to existing file.
- * @return             0 on success
- */
-static int createLinks(struct cpioHeader * hdr)
-       /*@modifies hdr, fileSystem @*/
-{
-    int rc = 0;
-    int i;
-
-    for (i = 0; i < hdr->li->nlink; i++) {
-       if (i == hdr->li->createdPath) continue;
-       if (hdr->li->files[i] == NULL) continue;
+    case FSM_INIT:
+       fsm->path = _free(fsm->path);
+       fsm->dnlx = _free(fsm->dnlx);
+       fsm->postpone = 0;
+       fsm->dperms = 0755;
+       fsm->fperms = 0644;
+       fsm->subdir = NULL;
+       fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
+       fsm->action = FA_UNKNOWN;
+       rc = fsmStage(fsm, FSM_NEXT);
+       break;
+    case FSM_MAP:
+       if (fsm->mapi == NULL)
+           break;
+       fsm->map = mapFind(fsm->mapi, fsm->path);
+       fsm->action = mapAction(fsm->map);
 
-       {   const char * path = hdr->path;
-           hdr->path = hdr->li->files[i];
-           rc = hdrStage(hdr, FI_VERIFY);
-           if (rc == CPIOERR_UNLINK_FAILED) {
-               if (hdr->failedFile)
-                   *hdr->failedFile = xstrdup(hdr->path);
-           }
-           hdr->path = path;
-       }
-       if (rc != CPIOERR_LSTAT_FAILED) return rc;
-       rc = 0;
-
-       /* XXX link(hdr->opath, hdr->path) */
-       {   const char * path = hdr->path;
-           const char * opath = hdr->opath;
-
-           hdr->opath = hdr->li->files[hdr->li->createdPath];
-           hdr->path = hdr->li->files[i];
-           rc = hdrStage(hdr, FI_LINK);
-           if (rc && hdr->failedFile)
-               *hdr->failedFile = xstrdup(hdr->path);
-           hdr->path = path;
-           hdr->opath = opath;
-           if (rc) return rc;
+       if (mapFlags(fsm->map, CPIO_MAP_PATH)) {
+           fsm->path = _free(fsm->path);
+           fsm->path = mapFsPath(fsm->map, st, fsm->subdir, fsm->suffix);
        }
 
-       /*@-unqualifiedtrans@*/
-       free((void *)hdr->li->files[i]);
-       /*@=unqualifiedtrans@*/
-       hdr->li->files[i] = NULL;
-       hdr->li->linksLeft--;
-    }
-
-    return 0;
-}
-
-/**
- * Skip amount bytes on input payload stream.
- * @param cfd          payload file handle
- * @param amount       no. bytes to skip
- * @return             0 on success
- */
-static int eatBytes(FD_t cfd, int amount)
-       /*@modifies cfd @*/
-{
-    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;
-}
-
-/**
- * Cpio archive extraction state machine.
- */
-static int hdrStage(struct cpioHeader * hdr, fileStage a)
-{
-    const char * const prev = fileStageString(hdr->a);
-    const char * const cur = fileStageString(a);
-    struct stat * st = &hdr->sb;
-    int rc = hdr->rc;
-
-#if 1
-    if (!(a & FI_INTERNAL))
-#else
-    if (!(a == FI_CREATE || a == FI_NOTIFY))
-#endif
-       rpmMessage(RPMMESS_DEBUG, _("%8x %s -> %s path %s\n"), rc, prev, cur,
-               hdr->path);
-
-    switch (a) {
-    case FI_CREATE:
-       hdr->path = NULL;
-       hdr->map = NULL;
-       hdr->links = NULL;
-       hdr->li = NULL;
-       errno = 0;      /* XXX get rid of EBADF */
+       if (mapFlags(fsm->map, CPIO_MAP_MODE))
+           st->st_mode = mapFinalMode(fsm->map);
+       if (mapFlags(fsm->map,  CPIO_MAP_UID))
+           st->st_uid = mapFinalUid(fsm->map);
+       if (mapFlags(fsm->map, CPIO_MAP_GID))
+           st->st_gid = mapFinalGid(fsm->map);
        break;
-    case FI_INIT:
-       if (hdr->path) {
-           free((void *)hdr->path); hdr->path = NULL;
+    case FSM_MKDIRS:
+       {   const char * path = fsm->path;
+           mode_t st_mode = st->st_mode;
+           void * dnli = dnlInitIterator(fsm->mapi);
+           char dn[BUFSIZ];            /* XXX add to fsm */
+           int dc = dnlCount(dnli);
+
+           dn[0] = '\0';
+           fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
+           while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
+               int dnlen = strlen(fsm->path);
+               char * te;
+
+               dc--;
+               fsm->dnlx[dc] = dnlen;
+               if (dnlen <= 1)
+                   continue;
+               if (fsm->ldnlen >= dnlen && !strcmp(fsm->path, fsm->ldn))
+                   continue;
+
+               if (fsm->ldnalloc < (dnlen + 1)) {
+                   fsm->ldnalloc = dnlen + 100;
+                   fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
+               }
+               strcpy(fsm->ldn, fsm->path);
+               fsm->ldnlen = dnlen;
+
+               (void) stpcpy(dn, fsm->path);
+               fsm->path = dn;
+               st->st_mode = S_IFDIR | 0000;   /* XXX abuse st->st_mode */
+               for (te = dn + 1; *te; te++) {
+                   if (*te != '/') continue;
+                   *te = '\0';
+                   rc = fsmStage(fsm, FSM_VERIFY);
+
+                   /* Move verified path location forward. */
+                   if (rc == 0)
+                       fsm->dnlx[dc] = (te - dn);
+                   else if (rc == CPIOERR_LSTAT_FAILED)
+                       rc = fsmStage(fsm, FSM_MKDIR);
+                   *te = '/';
+                   if (rc) break;
+               }
+           }
+           dnlFreeIterator(dnli);
+           fsm->path = path;
+           st->st_mode = st_mode;              /* XXX restore st->st_mode */
        }
-       hdr->postpone = 0;
-       hdr->dperms = 0755;
-       hdr->fperms = 0644;
-       hdr->subdir = NULL;
-       hdr->suffix = (hdr->sufbuf[0] != '\0' ? hdr->sufbuf : NULL);
-       hdr->action = FA_UNKNOWN;
-       rc = getNextHeader(hdr);
        break;
-    case FI_MAP:
-       if (hdr->mapi == NULL)
-           break;
-       hdr->map = mapFind(hdr->mapi, hdr->path);
-       if (hdr->map) {
-
-           hdr->action = mapAction(hdr->map);
-
-           if (mapFlags(hdr->map, CPIO_MAP_PATH)) {
-               struct cpioFileMapping * map =
-                       (struct cpioFileMapping *) hdr->map;
-               map->subdir = (hdr->subdir ? hdr->subdir : NULL);
-               map->suffix = (hdr->suffix ? hdr->suffix : NULL);
-               if (hdr->path) free((void *)hdr->path);
-               hdr->path = mapFsPath(hdr->map, st);
+    case FSM_RMDIRS:
+       if (fsm->dnlx) {
+           const char * path = fsm->path;
+           void * dnli = dnlInitIterator(fsm->mapi);
+           char dn[BUFSIZ];            /* XXX add to fsm */
+           int dc = dnlCount(dnli);
+
+           dn[0] = '\0';
+           while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
+               int dnlen = strlen(fsm->path);
+               char * te;
+               dc--;
+               if (fsm->dnlx[dc] == 0 || fsm->dnlx[dc] >= dnlen)
+                   continue;
+
+               te = stpcpy(dn, fsm->path) - 1;
+               fsm->path = dn;
+               do {
+                   if (*te == '/') {
+                       *te = '\0';
+                       rc = fsmStage(fsm, FSM_RMDIR);
+                       *te = '/';
+                   }
+                   if (rc) break;
+                   te--;
+               } while ((te - dn) > fsm->dnlx[dc]);
            }
-
-           if (mapFlags(hdr->map, CPIO_MAP_MODE))
-               st->st_mode = mapFinalMode(hdr->map);
-           if (mapFlags(hdr->map,  CPIO_MAP_UID))
-               st->st_uid = mapFinalUid(hdr->map);
-           if (mapFlags(hdr->map, CPIO_MAP_GID))
-               st->st_gid = mapFinalGid(hdr->map);
+           dnlFreeIterator(dnli);
+           fsm->path = path;
        }
        break;
-    case FI_SKIP:
-       eatBytes(hdr->cfd, st->st_size);
-       break;
-    case FI_PRE:
+    case FSM_PRE:
        /*
         * This won't get hard linked symlinks right, but I can't seem
         * to create those anyway.
         */
        if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
-           for (hdr->li = hdr->links; hdr->li; hdr->li = hdr->li->next) {
-               if (hdr->li->inode == st->st_ino && hdr->li->dev == st->st_dev)
+           for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
+               if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
                    break;
            }
 
-           if (hdr->li == NULL) {
-               hdr->li = newHardLink(st, HARDLINK_BUILD);
-               hdr->li->next = hdr->links;
-               hdr->links = hdr->li;
+           if (fsm->li == NULL) {
+               fsm->li = newHardLink(st, HARDLINK_BUILD);
+               fsm->li->next = fsm->links;
+               fsm->links = fsm->li;
            }
 
-           hdr->li->files[hdr->li->linksLeft++] = xstrdup(hdr->path);
+           fsm->li->files[fsm->li->linksLeft++] = xstrdup(fsm->path);
        }
 
        /* XXX FIXME 0 length hard linked files are broke here. */
        if (S_ISREG(st->st_mode) && st->st_nlink > 1 &&
-           !st->st_size && hdr->li->createdPath == -1)
+           !st->st_size && fsm->li->createdPath == -1)
        {
-           hdr->postpone = 1;          /* defer file creation */
+           fsm->postpone = 1;          /* defer file creation */
        } else if (S_ISREG(st->st_mode) && st->st_nlink > 1 &&
-                  hdr->li->createdPath != -1)
+                  fsm->li->createdPath != -1)
        {
-           createLinks(hdr);
+           rc = fsmStage(fsm, FSM_MKLINKS);
 
            /*
            * This only happens for cpio archives which contain
@@ -920,168 +1025,201 @@ static int hdrStage(struct cpioHeader * hdr, fileStage a)
            * shouldn't happen, but I've made it happen w/ buggy
            * code, so what the heck? GNU cpio handles this well fwiw.
            */
-           eatBytes(hdr->cfd, st->st_size);
-           hdr->postpone = 1;          /* defer file creation */
+           (void) fsmStage(fsm, FSM_EAT);
+           fsm->postpone = 1;          /* defer file creation */
        } else {
-           /* XXX keep track of created directories. */
-           rc = checkDirectory(hdr);
+           rc = fsmStage(fsm, FSM_MKDIRS);
        }
        break;
-    case FI_PROCESS:
-       if (hdr->postpone)
+    case FSM_PROCESS:
+       if (fsm->postpone)
            break;
        if (S_ISREG(st->st_mode)) {
-           rc = expandRegular(hdr);
+           /* XXX nlink > 1, insure that path/createdPath is non-skipped. */
+           rc = expandRegular(fsm);
        } else if (S_ISDIR(st->st_mode)) {
-           mode_t dperms = hdr->dperms;
-           hdr->dperms = 0000;         /* XXX abuse hdr->dperms */
-           rc = createDirectory(hdr);
-           hdr->dperms = dperms;       /* XXX restore hdr->dperms */
+           mode_t st_mode = st->st_mode;
+           rc = fsmStage(fsm, FSM_VERIFY);
+           if (rc == CPIOERR_LSTAT_FAILED) {
+               st->st_mode = S_IFDIR | 0000;   /* XXX abuse st->st_mode */
+               rc = fsmStage(fsm, FSM_MKDIR);
+               st->st_mode = st_mode;          /* XXX restore st->st_mode */
+           }
+           /* XXX check old dir perms and warn */
+           if (!rc)
+               rc = fsmStage(fsm, FSM_CHMOD);
        } else if (S_ISLNK(st->st_mode)) {
-           const char * opath = hdr->opath;
-           char buf[2048];
+           const char * opath = fsm->opath;
+           char buf[2048];                     /* XXX add to fsm */
 
            if ((st->st_size + 1)> sizeof(buf)) {
                rc = CPIOERR_HDR_SIZE;
                break;
            }
-           if (ourread(hdr->cfd, buf, st->st_size) != st->st_size) {
+           if (ourread(fsm->cfd, buf, st->st_size) != st->st_size) {
                rc = CPIOERR_READ_FAILED;
                break;
            }
            buf[st->st_size] = '\0';
 
-           /* XXX symlink(hdr->opath, hdr->path) */
-           hdr->opath = buf;           /* XXX abuse hdr->path */
-           rc = hdrStage(hdr, FI_VERIFY);
+           /* XXX symlink(fsm->opath, fsm->path) */
+           fsm->opath = buf;           /* XXX abuse fsm->path */
+           rc = fsmStage(fsm, FSM_VERIFY);
            if (rc == CPIOERR_LSTAT_FAILED)
-               rc = hdrStage(hdr, FI_SYMLINK);
-           hdr->opath = opath;         /* XXX restore hdr->path */
+               rc = fsmStage(fsm, FSM_SYMLINK);
+           fsm->opath = opath;         /* XXX restore fsm->path */
        } else if (S_ISFIFO(st->st_mode) || S_ISSOCK(st->st_mode)) {
-           mode_t st_mode = hdr->sb.st_mode;
+           mode_t st_mode = st->st_mode;
            /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
-           rc = hdrStage(hdr, FI_VERIFY);
+           rc = fsmStage(fsm, FSM_VERIFY);
            if (rc == CPIOERR_LSTAT_FAILED) {
-               hdr->sb.st_mode = 0000;         /* XXX abuse hdr->sb.st_mode */
-               rc = hdrStage(hdr, FI_MKFIFO);
-               hdr->sb.st_mode = st_mode;      /* XXX restore */
+               st->st_mode = 0000;             /* XXX abuse st->st_mode */
+               rc = fsmStage(fsm, FSM_MKFIFO);
+               st->st_mode = st_mode;  /* XXX restore st->st_mode*/
            }
        } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
-           rc = hdrStage(hdr, FI_VERIFY);
+           rc = fsmStage(fsm, FSM_VERIFY);
            if (rc == CPIOERR_LSTAT_FAILED)
-               rc = hdrStage(hdr, FI_MKNOD);
+               rc = fsmStage(fsm, FSM_MKNOD);
        } else {
            rc = CPIOERR_UNKNOWN_FILETYPE;
        }
        break;
-    case FI_POST:
-       if (hdr->postpone)
+    case FSM_POST:
+       if (fsm->postpone)
            break;
        if (S_ISLNK(st->st_mode)) {
-           if (!getuid())      rc = hdrStage(hdr, FI_LCHOWN);
+           if (!getuid())      rc = fsmStage(fsm, FSM_LCHOWN);
        } else {
-           if (!getuid())      rc = hdrStage(hdr, FI_CHOWN);
-           if (!rc)            rc = hdrStage(hdr, FI_CHMOD);
-           if (!rc)            rc = hdrStage(hdr, FI_UTIME);
+           if (!getuid())      rc = fsmStage(fsm, FSM_CHOWN);
+           if (!rc)            rc = fsmStage(fsm, FSM_CHMOD);
+           if (!rc)            rc = fsmStage(fsm, FSM_UTIME);
        }
+       /* XXX nlink > 1, insure that path/createdPath is non-skipped. */
        if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
-           hdr->li->createdPath = --hdr->li->linksLeft;
-           rc = createLinks(hdr);
+           fsm->li->createdPath = --fsm->li->linksLeft;
+           rc = fsmStage(fsm, FSM_MKLINKS);
+       }
+       break;
+    case FSM_MKLINKS:
+       {   const char * path = fsm->path;
+           const char * opath = fsm->opath;
+
+           rc = 0;
+           for (i = 0; i < fsm->li->nlink; i++) {
+               if (i == fsm->li->createdPath) continue;
+               if (fsm->li->files[i] == NULL) continue;
+
+               fsm->path = fsm->li->files[i];
+               rc = fsmStage(fsm, FSM_VERIFY);
+               if (rc != CPIOERR_LSTAT_FAILED) break;
+
+               /* XXX link(fsm->opath, fsm->path) */
+               rc = fsmStage(fsm, FSM_LINK);
+               if (rc) break;
+
+               /*@-unqualifiedtrans@*/
+               fsm->li->files[i] = _free(fsm->li->files[i]);
+               /*@=unqualifiedtrans@*/
+               fsm->li->linksLeft--;
+           }
+           if (rc && fsm->failedFile)
+               *fsm->failedFile = xstrdup(fsm->path);
+           fsm->path = path;
+           fsm->opath = opath;
        }
        break;
-    case FI_NOTIFY:
-       {   struct mapi * mapi = hdr->mapi;
+    case FSM_NOTIFY:           /* XXX move from fsm to psm -> tsm */
+       {   struct mapi * mapi = fsm->mapi;
            if (mapi) {
                rpmTransactionSet ts = mapi->ts;
                TFI_t fi = mapi->fi;
                if (ts && ts->notify)
                    (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
-                       fdGetCpioPos(hdr->cfd), fi->archiveSize,
+                       fdGetCpioPos(fsm->cfd), fi->archiveSize,
                        (fi->ap ? fi->ap->key : NULL), ts->notifyData);
            }
        }
        return rc;
        /*@notreached@*/ break;
-    case FI_UNDO:
+    case FSM_UNDO:
        {   int olderrno = errno;
            if (S_ISDIR(st->st_mode)) {
-               (void) hdrStage(hdr, FI_RMDIR);
+               (void) fsmStage(fsm, FSM_RMDIR);
            } else {
-               (void) hdrStage(hdr, FI_UNLINK);
+               (void) fsmStage(fsm, FSM_UNLINK);
            }
-           /* XXX remove created directories. */
+           if (fsm->dnlx)
+               (void) fsmStage(fsm, FSM_RMDIRS);
            errno = olderrno;
-           if (hdr->failedFile && *hdr->failedFile == NULL)
-               *hdr->failedFile = xstrdup(hdr->path);
+           if (fsm->failedFile && *fsm->failedFile == NULL)
+               *fsm->failedFile = xstrdup(fsm->path);
        }
        break;
-    case FI_COMMIT:
-       if (mapCommit(hdr->map) && (hdr->subdir || hdr->suffix)) {
-           struct cpioFileMapping * map = (struct cpioFileMapping *) hdr->map;
-           map->subdir = NULL;
-           map->suffix = NULL;
-           hdr->opath = hdr->path;
-           hdr->path = mapFsPath(hdr->map, st);
-           rc = hdrStage(hdr, FI_RENAME);
-           /* XXX remove created subdirs. */
-           free((void *)hdr->opath);
-           hdr->opath = NULL;
+    case FSM_COMMIT:
+       if (mapCommit(fsm->map) && (fsm->subdir || fsm->suffix)) {
+           fsm->opath = fsm->path;
+           fsm->path = mapFsPath(fsm->map, st, NULL, NULL);
+           rc = fsmStage(fsm, FSM_RENAME);
+           fsm->opath = _free(fsm->opath);
        }
        /* Notify on success. */
-       if (!rc)        rc = hdrStage(hdr, FI_NOTIFY);
+       if (!rc)        rc = fsmStage(fsm, FSM_NOTIFY);
        break;
-    case FI_DESTROY:
-       if (hdr->path) {
-           free((void *)hdr->path); hdr->path = NULL;
-       }
+    case FSM_DESTROY:
+       fsm->path = _free(fsm->path);
        /* Create any remaining links (if no error), and clean up. */
-       rc = hdr->rc;
-       while ((hdr->li = hdr->links) != NULL) {
-           hdr->links = hdr->li->next;
-           hdr->li->next = NULL;
+       rc = fsm->rc;
+       while ((fsm->li = fsm->links) != NULL) {
+           fsm->links = fsm->li->next;
+           fsm->li->next = NULL;
            /* XXX adjust for %lang hardlinks. */
-           if (rc == 0 && hdr->li->linksLeft)
-               rc = (hdr->li->createdPath != -1)
-                       ? createLinks(hdr) : CPIOERR_MISSING_HARDLINK;
-           freeHardLink(hdr->li);
-           hdr->li = NULL;
+           if (rc == 0 && fsm->li->linksLeft) {
+               if (fsm->li->createdPath != -1)
+                   rc = fsmStage(fsm, FSM_MKLINKS);
+           } else {
+               rc = CPIOERR_MISSING_HARDLINK;
+           }
+           fsm->li = freeHardLink(fsm->li);
        }
+       fsm->ldn = _free(fsm->ldn);
+       fsm->ldnalloc = fsm->ldnlen = 0;
        break;
-    case FI_VERIFY:
+    case FSM_VERIFY:
        {   struct stat sb;
            int saveerrno;
 
            saveerrno = errno;
-           rc = lstat(hdr->path, &sb);
+           rc = lstat(fsm->path, &sb);
            if (rc < 0 && errno == ENOENT)
                errno = saveerrno;
            if (rc < 0) return CPIOERR_LSTAT_FAILED;
 
-       /* XXX handle upgrade actions right here. */
+       /* XXX handle upgrade actions right here? */
 
            if (S_ISREG(st->st_mode)) {
-               char * path = alloca(strlen(hdr->path) + sizeof("-RPMDELETE"));
-               (void) stpcpy( stpcpy(path, hdr->path), "-RPMDELETE");
+               char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
+               (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
                /*
                 * XXX HP-UX (and other os'es) don't permit unlink on busy
                 * XXX files.
                 */
-               hdr->opath = hdr->path;
-               hdr->path = path;
-               rc = hdrStage(hdr, FI_RENAME);
+               fsm->opath = fsm->path;
+               fsm->path = path;
+               rc = fsmStage(fsm, FSM_RENAME);
                if (!rc)
-                   (void) hdrStage(hdr, FI_UNLINK);
+                   (void) fsmStage(fsm, FSM_UNLINK);
                else
                    rc = CPIOERR_UNLINK_FAILED;
-               hdr->path = hdr->opath;
-               hdr->opath = NULL;
+               fsm->path = fsm->opath;
+               fsm->opath = NULL;
                return (rc ? rc : CPIOERR_LSTAT_FAILED);
                break;
            } else if (S_ISDIR(st->st_mode)) {
                if (S_ISDIR(sb.st_mode))                return 0;
                if (S_ISLNK(sb.st_mode)) {
                    saveerrno = errno;
-                   rc = stat(hdr->path, &sb);
+                   rc = stat(fsm->path, &sb);
                    if (rc < 0 && errno != ENOENT)
                        return CPIOERR_STAT_FAILED;
                    errno = saveerrno;
@@ -1091,11 +1229,11 @@ static int hdrStage(struct cpioHeader * hdr, fileStage a)
                if (S_ISLNK(sb.st_mode)) {
                    char buf[2048];
                    saveerrno = errno;
-                   rc = readlink(hdr->path, buf, sizeof(buf) - 1);
+                   rc = readlink(fsm->path, buf, sizeof(buf) - 1);
                    errno = saveerrno;
                    if (rc > 0) {
                        buf[rc] = '\0';
-                       if (!strcmp(hdr->opath, buf))   return 0;
+                       if (!strcmp(fsm->opath, buf))   return 0;
                    }
                }
            } else if (S_ISFIFO(st->st_mode)) {
@@ -1106,93 +1244,142 @@ static int hdrStage(struct cpioHeader * hdr, fileStage a)
            } else if (S_ISSOCK(st->st_mode)) {
                if (S_ISSOCK(sb.st_mode))               return 0;
            }
+           /* XXX shouldn't do this with commit/undo. */
            rc = 0;
-           if (hdr->a == FI_PROCESS) rc = hdrStage(hdr, FI_UNLINK);
+           if (stage == FSM_PROCESS) rc = fsmStage(fsm, FSM_UNLINK);
+           if (rc == 0)        rc = CPIOERR_LSTAT_FAILED;
            return (rc ? rc : CPIOERR_LSTAT_FAILED);    /* XXX HACK */
        }
        break;
-    case FI_UNLINK:
-       rc = unlink(hdr->path);
+    case FSM_UNLINK:
+       rc = unlink(fsm->path);
        if (rc < 0)     rc = CPIOERR_UNLINK_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_RENAME:
-       rc = rename(hdr->opath, hdr->path);
+       break;
+    case FSM_RENAME:
+       rc = rename(fsm->opath, fsm->path);
        if (rc < 0)     rc = CPIOERR_RENAME_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_MKDIR:
-       rc = mkdir(hdr->path, (st->st_mode & 07777));
+       break;
+    case FSM_MKDIR:
+       rc = mkdir(fsm->path, (st->st_mode & 07777));
        if (rc < 0)     rc = CPIOERR_MKDIR_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_RMDIR:
-       rc = rmdir(hdr->path);
+       break;
+    case FSM_RMDIR:
+       rc = rmdir(fsm->path);
        if (rc < 0)     rc = CPIOERR_RMDIR_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_CHOWN:
-       rc = chown(hdr->path, st->st_uid, st->st_gid);
+       break;
+    case FSM_CHOWN:
+       rc = chown(fsm->path, st->st_uid, st->st_gid);
        if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_LCHOWN:
+       break;
+    case FSM_LCHOWN:
 #if ! CHOWN_FOLLOWS_SYMLINK
-       rc = lchown(hdr->path, st->st_uid, st->st_gid);
+       rc = lchown(fsm->path, st->st_uid, st->st_gid);
        if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
 #endif
-       return rc;
-       /*@notreached@*/ break;
-    case FI_CHMOD:
-       rc = chmod(hdr->path, (st->st_mode & 07777));
+       break;
+    case FSM_CHMOD:
+       rc = chmod(fsm->path, (st->st_mode & 07777));
        if (rc < 0)     rc = CPIOERR_CHMOD_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_UTIME:
+       break;
+    case FSM_UTIME:
        {   struct utimbuf stamp;
            stamp.actime = st->st_mtime;
            stamp.modtime = st->st_mtime;
-           rc = utime(hdr->path, &stamp);
+           rc = utime(fsm->path, &stamp);
            if (rc < 0) rc = CPIOERR_UTIME_FAILED;
        }
-       return rc;
-       /*@notreached@*/ break;
-    case FI_SYMLINK:
-       rc = symlink(hdr->opath, hdr->path);
+       break;
+    case FSM_SYMLINK:
+       rc = symlink(fsm->opath, fsm->path);
        if (rc < 0)     rc = CPIOERR_SYMLINK_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_LINK:
-       rc = link(hdr->opath, hdr->path);
+       break;
+    case FSM_LINK:
+       rc = link(fsm->opath, fsm->path);
        if (rc < 0)     rc = CPIOERR_LINK_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_MKFIFO:
-       rc = mkfifo(hdr->path, (st->st_mode & 07777));
+       break;
+    case FSM_MKFIFO:
+       rc = mkfifo(fsm->path, (st->st_mode & 07777));
        if (rc < 0)     rc = CPIOERR_MKFIFO_FAILED;
-       return rc;
-       /*@notreached@*/ break;
-    case FI_MKNOD:
+       break;
+    case FSM_MKNOD:
        /*@-unrecog@*/
-       rc = mknod(hdr->path, st->st_mode & (~0777), st->st_rdev);
+       rc = mknod(fsm->path, st->st_mode & (~0777), st->st_rdev);
        if (rc < 0)     rc = CPIOERR_MKNOD_FAILED;
        /*@=unrecog@*/
-       return rc;
-       /*@notreached@*/ break;
+       break;
+
+    case FSM_NEXT:
+       rc = getNextHeader(fsm, st);
+       if (!rc && !strcmp(fsm->path, TRAILER))
+           rc = CPIOERR_HDR_TRAILER;
+       break;
+    case FSM_EAT:
+       {   char buf[BUFSIZ];           /* XXX add to fsm */
+           int amount;
+           int bite;
+
+           rc = 0;
+           for (amount = st->st_size; amount > 0; amount -= bite) {
+               bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
+               if (ourread(fsm->cfd, buf, bite) == bite)
+                   continue;
+               rc = CPIOERR_READ_FAILED;
+               break;
+           }
+       }
+       break;
+    case FSM_POS:
+       {   int buf[16];                /* XXX add to fsm */
+           int modulo = 4;
+           int amount;
+
+           amount = (modulo - fdGetCpioPos(fsm->cfd) % modulo) % modulo;
+           (void)ourread(fsm->cfd, buf, amount);
+       }
+       break;
+    case FSM_PAD:
+       break;
+
     default:
        break;
     }
 
-    hdr->a = a;
-    hdr->rc = rc;
+    if (!(stage & FSM_INTERNAL))
+       fsm->rc = rc;
     return rc;
 }
 
-/** @todo Verify payload MD5 sum. */
-int cpioInstallArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
+int fsmSetup(FSM_t fsm, const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
                const char ** failedFile)
 {
-    struct cpioHeader ch, *hdr = &ch;
+    int rc = fsmStage(fsm, FSM_CREATE);
+
+    fsm->cfd = fdLink(cfd, "persist (fsm)");
+    fdSetCpioPos(fsm->cfd, 0);
+    fsm->mapi = mapInitIterator(ts, fi);
+    fsm->failedFile = failedFile;
+    if (fsm->failedFile)
+       *fsm->failedFile = NULL;
+    if (ts->id > 0)
+       sprintf(fsm->sufbuf, ";%08x", ts->id);
+    return rc;
+}
+
+int fsmTeardown(FSM_t fsm) {
+    int rc = 0;
+    fsm->mapi = mapFreeIterator(fsm->mapi);
+    fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
+    fsm->cfd = NULL;
+    fsm->failedFile = NULL;
+    return rc;
+}
+
+/** @todo Verify payload MD5 sum. */
+int cpioInstallArchive(FSM_t fsm)
+{
+#ifdef DYING
+    FSM_t fsm = fi->fsm;
+#endif
     int rc = 0;
 
 #ifdef NOTYET
@@ -1201,74 +1388,76 @@ int cpioInstallArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
     fdInitMD5(cfd, 0);
 #endif
 
-    /* Initialize hdr. */
-    memset(hdr, 0, sizeof(*hdr));
-    rc = hdrStage(hdr, FI_CREATE);
-    hdr->cfd = fdLink(cfd, "persist (cpioInstallArchive");
-    fdSetCpioPos(hdr->cfd, 0);
-    hdr->mapi = mapInitIterator(ts, fi);
-    hdr->failedFile = failedFile;
-    if (hdr->failedFile)
-       *hdr->failedFile = NULL;
+#ifdef DYING
+    /* Initialize fsm. */
+    rc = fsmStage(fsm, FSM_CREATE);
+
+    fsm->cfd = fdLink(cfd, "persist (cpioInstallArchive");
+    fdSetCpioPos(fsm->cfd, 0);
+    fsm->mapi = mapInitIterator(ts, fi);
+    fsm->failedFile = failedFile;
+    if (fsm->failedFile)
+       *fsm->failedFile = NULL;
     if (ts->id > 0)
-       sprintf(hdr->sufbuf, ";%08x", ts->id);
+       sprintf(fsm->sufbuf, ";%08x", ts->id);
+#endif
 
     do {
 
-       /* Clean hdr, free'ing memory. Read next archive header. */
-       rc = hdrStage(hdr, FI_INIT);
-       if (rc) {
-#if 0  /* XXX this is the failure point for an unreadable rpm */
-           rpmError(RPMERR_BADPACKAGE, _("getNextHeader: %s\n"),
-                       cpioStrerror(rc));
-#endif
-           goto exit;
-       }
+       /* Clean fsm, free'ing memory. Read next archive header. */
+       rc = fsmStage(fsm, FSM_INIT);
 
-       if (!strcmp(hdr->path, TRAILER))
+       /* Exit on end-of-payload. */
+       if (rc == CPIOERR_HDR_TRAILER) {
+           rc = 0;
            break;
+       }
+
+       /* Abort on error. */
+       if (rc)
+           goto exit;
 
        /* Remap mode/uid/gid/name of file from archive. */
-       (void) hdrStage(hdr, FI_MAP);
+       (void) fsmStage(fsm, FSM_MAP);
 
-       if (hdr->mapi && hdr->map == NULL) {
-           rc = hdrStage(hdr, FI_SKIP);
+       if (fsm->mapi && fsm->map == NULL) {
+           rc = fsmStage(fsm, FSM_EAT);
        } else {
            /* Create any directories in path. */
-           rc = hdrStage(hdr, FI_PRE);
+           rc = fsmStage(fsm, FSM_PRE);
 
            /* Extract file from archive. */
-           if (!rc)    rc = hdrStage(hdr, FI_PROCESS);
+           if (!rc)    rc = fsmStage(fsm, FSM_PROCESS);
 
            /* If successfully extracted, set final file info. */
-           if (!rc)    rc = hdrStage(hdr, FI_POST);
+           if (!rc)    rc = fsmStage(fsm, FSM_POST);
        }
 
-       padinfd(hdr->cfd, 4);
+       /* Position to next item in payload. */
+       (void) fsmStage(fsm, FSM_POS);
 
        /* Notify on success. */
-       if (!rc)        (void) hdrStage(hdr, FI_NOTIFY);
+       if (!rc)        (void) fsmStage(fsm, FSM_NOTIFY);
 
-       (void) hdrStage(hdr, (rc ? FI_UNDO : FI_COMMIT));
+       (void) fsmStage(fsm, (rc ? FSM_UNDO : FSM_COMMIT));
 
     } while (rc == 0);
 
-    rc = hdrStage(hdr, FI_DESTROY);
+    rc = fsmStage(fsm, FSM_DESTROY);
 
 #ifdef NOTYET
-    fdFiniMD5(hdr->cfd, (void **)&md5sum, NULL, 1);
+    fdFiniMD5(fsm->cfd, (void **)&md5sum, NULL, 1);
 
     if (md5sum)
        free(md5sum);
 #endif
 
 exit:
-    if (hdr->cfd) {
-       fdFree(hdr->cfd, "persist (cpioInstallArchive");
-       hdr->cfd = NULL;
-    }
-    if (hdr->mapi)
-       mapFreeIterator(hdr->mapi);
+#ifdef DYING
+    fsm->mapi = mapFreeIterator(fsm->mapi);
+    fsm->cfd = fdFree(fsm->cfd, "persist (cpioInstallArchive");
+    fsm->cfd = NULL;
+#endif
     return rc;
 }
 
@@ -1288,9 +1477,9 @@ static int writeFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
        int writeData)
        /*@modifies cfd, *sizep @*/
 {
-    const char * fsPath = mapFsPath(map, NULL);
+    const char * fsPath = mapFsPath(map, NULL, NULL, NULL);
     const char * archivePath = NULL;
-    const char * hdrPath = !mapFlags(map, CPIO_MAP_PATH)
+    const char * fsmPath = !mapFlags(map, CPIO_MAP_PATH)
                ? fsPath : (archivePath = mapArchivePath(map));
     struct cpioCrcPhysicalHeader hdr;
     char buf[8192], symbuf[2048];
@@ -1340,12 +1529,12 @@ static int writeFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
     num = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
     num = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
 
-    num = strlen(hdrPath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
+    num = strlen(fsmPath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
     memcpy(hdr.checksum, "00000000", 8);
 
     if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
        goto exit;
-    if ((rc = safewrite(cfd, hdrPath, num)) != num)
+    if ((rc = safewrite(cfd, fsmPath, num)) != num)
        goto exit;
     size = PHYS_HDR_SIZE + num;
     if ((rc = padoutfd(cfd, &size, 4)))
@@ -1436,7 +1625,7 @@ static int writeFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
     rc = 0;
 
 exit:
-    if (fsPath) free((void *)fsPath);
+    fsPath = _free(fsPath);
     return rc;
 }
 
@@ -1465,13 +1654,13 @@ static int writeLinkedFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
        map = hlink->fileMaps[i];
        if ((rc = writeFile(ts, fi, cfd, &hlink->sb, map, &size, 0)) != 0) {
            if (failedFile)
-               *failedFile = mapFsPath(map, NULL);
+               *failedFile = mapFsPath(map, NULL, NULL, NULL);
            goto exit;
        }
 
        total += size;
 
-       mapFree(map); map = NULL;
+       map = mapFree(map);
     }
 
     i = hlink->linksLeft;
@@ -1480,7 +1669,7 @@ static int writeLinkedFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
        if (sizep)
            *sizep = total;
        if (failedFile)
-           *failedFile = mapFsPath(map, NULL);
+           *failedFile = mapFsPath(map, NULL, NULL, NULL);
        goto exit;
     }
     total += size;
@@ -1491,8 +1680,7 @@ static int writeLinkedFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
     rc = 0;
 
 exit:
-    if (map)
-       mapFree(map);
+    map = mapFree(map);
     return rc;
 }
 
@@ -1515,7 +1703,7 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
     while ((map = mapNextIterator(mapi)) != NULL) {
        const char * fsPath;
 
-       fsPath = mapFsPath(map, NULL);
+       fsPath = mapFsPath(map, NULL, NULL, NULL);
 
        if (mapFlags(map, CPIO_FOLLOW_SYMLINKS))
            rc = Stat(fsPath, st);
@@ -1545,7 +1733,7 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
                struct hardLink * prev;
                rc = writeLinkedFile(ts, fi, cfd, hlink, &size, failedFile);
                if (rc) {
-                   free((void *)fsPath);
+                   fsPath = _free(fsPath);
                    return rc;
                }
 
@@ -1557,8 +1745,7 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
                        continue;
                    prev->next = hlink->next;
                    hlink->next = NULL;
-                   freeHardLink(hlink);
-                   hlink = NULL;
+                   hlink = freeHardLink(hlink);
                    break;
                } while ((prev = prev->next) != NULL);
            }
@@ -1571,21 +1758,19 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
 
            totalsize += size;
        }
-       free((void *)fsPath);
-       fsPath = NULL;
+       fsPath = _free(fsPath);
     }
-    mapFreeIterator(mapi);
+    mapi = mapFreeIterator(mapi);
 
     rc = 0;
     while ((hlink = hlinkList.next) != NULL) {
        hlinkList.next = hlink->next;
        hlink->next = NULL;
-
        if (rc == 0) {
            rc = writeLinkedFile(ts, fi, cfd, hlink, &size, failedFile);
            totalsize += size;
        }
-       freeHardLink(hlink);
+       hlink = freeHardLink(hlink);
     }
     if (rc)
        return rc;
index 4319376..ac3f247 100644 (file)
@@ -47,10 +47,11 @@ enum cpioErrorReturns {
        CPIOERR_READ_FAILED     = (20   | CPIOERR_CHECK_ERRNO),
        CPIOERR_COPY_FAILED     = (21   | CPIOERR_CHECK_ERRNO),
        CPIOERR_HDR_SIZE        = (22                   ),
-       CPIOERR_UNKNOWN_FILETYPE= (23                   ),
-       CPIOERR_MISSING_HARDLINK= (24                   ),
-       CPIOERR_MD5SUM_MISMATCH = (25                   ),
-       CPIOERR_INTERNAL        = (26                   )
+       CPIOERR_HDR_TRAILER     = (23                   ),
+       CPIOERR_UNKNOWN_FILETYPE= (24                   ),
+       CPIOERR_MISSING_HARDLINK= (25                   ),
+       CPIOERR_MD5SUM_MISMATCH = (26                   ),
+       CPIOERR_INTERNAL        = (27                   )
 };
 
 /** \ingroup payload
@@ -78,15 +79,11 @@ extern "C" {
  * used for the permission bits, not for the file type. The owner/group
  * mappings are ignored for the non-root user.
  *
- * @param ts           transaction set
- * @param fi           transaction element file info
- * @param cfd          file handle
- * @retval failedFile  (malloc'd) file name that caused failure (if any)
+ * @param fsm          file state machine data
  * @return             0 on success
  */
-int cpioInstallArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
-                      /*@out@*/const char ** failedFile)
-       /*@modifies fileSystem, cfd, *failedFile @*/;
+int cpioInstallArchive(FSM_t fsm)
+       /*@modifies fileSystem, fsm @*/;
 
 /** \ingroup payload
  * The RPM internal equivalent of the command line "cpio -o".
index efcf9b1..c069893 100644 (file)
@@ -531,10 +531,12 @@ typedef enum rpmTagType_e {
 /*@unused@*/ static inline /*@null@*/ void * headerFreeData(
                        /*@only@*/ const void * data, rpmTagType type)
 {
-    if (type == RPM_STRING_ARRAY_TYPE ||
-       type == RPM_I18NSTRING_TYPE ||
-       type == RPM_BIN_TYPE) {
-       if (data) free((void *)data);
+    if (data) {
+       if (type < 0 ||
+           type == RPM_STRING_ARRAY_TYPE ||
+           type == RPM_I18NSTRING_TYPE ||
+           type == RPM_BIN_TYPE)
+               free((void *)data);
     }
     return NULL;
 }
index 3fbfaa1..6e1278e 100644 (file)
@@ -416,12 +416,6 @@ static int installArchive(const rpmTransactionSet ts, TFI_t fi, int allFiles)
        return 0;
     }
 
-    {  uint_32 * asp;
-       rc = headerGetEntry(fi->h, RPMTAG_ARCHIVESIZE, NULL,
-                               (void **) &asp, NULL);
-       fi->archiveSize = (rc ? *asp : 0);
-    }
-
     /* Retrieve type of payload compression. */
     {  const char * payload_compressor = NULL;
        char * t;
@@ -437,12 +431,18 @@ static int installArchive(const rpmTransactionSet ts, TFI_t fi, int allFiles)
            t = stpcpy(t, ".bzdio");
     }
 
-    {  FD_t cfd;
+    {
+       FD_t cfd;
        (void) Fflush(alp->fd);
+
        cfd = Fdopen(fdDup(Fileno(alp->fd)), rpmio_flags);
-       rc = cpioInstallArchive(ts, fi, cfd, &failedFile);
+       cfd = fdLink(cfd, "persist (installArchive");
+
+       rc = fsmSetup(fi->fsm, ts, fi, cfd, &failedFile);
+       rc = cpioInstallArchive(fi->fsm);
        saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
        Fclose(cfd);
+       (void) fsmTeardown(fi->fsm);
     }
 
     if (rc) {
@@ -456,6 +456,13 @@ static int installArchive(const rpmTransactionSet ts, TFI_t fi, int allFiles)
                (failedFile != NULL ? failedFile : ""),
                cpioStrerror(rc));
        rc = 1;
+    } else {
+       if (ts && ts->notify) {
+           unsigned int archiveSize = (fi->archiveSize ? fi->archiveSize : 100);
+           (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
+                       archiveSize, archiveSize,
+                       (fi->ap ? fi->ap->key : NULL), ts->notifyData);
+       }
     }
 
     if (failedFile)
@@ -809,7 +816,7 @@ int installBinaryPackage(const rpmTransactionSet ts, TFI_t fi)
 
        setFileOwners(fi);
 
-       rc = pkgActions(ts, fi);
+       rc = pkgActions(ts, fi, FSM_COMMIT);
        if (rc)
            goto exit;
 
index c540e43..146768e 100644 (file)
 
 /*@access h@*/         /* compared with NULL */
 
-#define        SUFFIX_RPMORIG  ".rpmorig"
-#define        SUFFIX_RPMSAVE  ".rpmsave"
-#define        SUFFIX_RPMNEW   ".rpmnew"
-
-static char * ridsub = ".rid/";
-static char * ridsep = ";";
-static mode_t riddmode = 0700;
-static mode_t ridfmode = 0000;
-
-int dirstashPackage(const rpmTransactionSet ts, const TFI_t fi, rollbackDir dir)
-{
-    unsigned int offset = fi->record;
-    char tsid[20], ofn[BUFSIZ], nfn[BUFSIZ];
-    const char * s, * t;
-    char * se, * te;
-    Header h;
-    int i;
-
-    assert(fi->type == TR_REMOVED);
-
-    {  rpmdbMatchIterator mi = NULL;
-
-       mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
-                               &offset, sizeof(offset));
-
-       h = rpmdbNextIterator(mi);
-       if (h == NULL) {
-           rpmdbFreeIterator(mi);
-           return 1;
-       }
-       h = headerLink(h);
-       rpmdbFreeIterator(mi);
-    }
-
-    sprintf(tsid, "%08x", ts->id);
-
-    /* Create rid sub-directories if necessary. */
-    if (strchr(ridsub, '/')) {
-       for (i = 0; i < fi->dc; i++) {
-
-           t = te = nfn;
-           *te = '\0';
-           te = stpcpy(te, fi->dnl[i]);
-           te = stpcpy(te, ridsub);
-           if (te[-1] == '/')
-               *(--te) = '\0';
-fprintf(stderr, "*** mkdir(%s,%o)\n", t, (int)riddmode);
-       }
-    }
-
-    /* Rename files about to be removed. */
-    for (i = 0; i < fi->fc; i++) {
-
-       if (S_ISDIR(fi->fmodes[i]))
-           continue;
-
-       s = se = ofn;
-       *se = '\0';
-       se = stpcpy( stpcpy(se, fi->dnl[fi->dil[i]]), fi->bnl[i]);
-
-       t = te = nfn;
-       *te = '\0';
-       te = stpcpy(te, fi->dnl[fi->dil[i]]);
-       if (ridsub)
-           te = stpcpy(te, ridsub);
-       te = stpcpy( stpcpy( stpcpy(te, fi->bnl[i]), ridsep), tsid);
-
-       s = strrchr(s, '/') + 1;
-       t = strrchr(t, '/') + 1;
-fprintf(stderr, "*** rename(%s,%s%s)\n", s, (ridsub ? ridsub : ""), t);
-fprintf(stderr, "*** chmod(%s%s,%o)\n", (ridsub ? ridsub : ""), t, ridfmode);
-    }
-
-    return 0;
-}
-
 void loadFi(Header h, TFI_t fi)
 {
     HGE_t hge;
-    int len, i;
+    uint_32 * uip;
+    int len;
+    int rc;
+    int i;
     
+    if (fi->fsm == NULL)
+       fi->fsm = newFSM();
+
     /* XXX avoid gcc noise on pointer (4th arg) cast(s) */
     hge = (fi->type == TR_ADDED)
        ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry;
@@ -108,19 +38,16 @@ void loadFi(Header h, TFI_t fi)
     hge(fi->h, RPMTAG_RELEASE, NULL, (void **) &fi->release, NULL);
     fi->release = xstrdup(fi->release);
 
+    /* -1 means not found */
+    rc = hge(fi->h, RPMTAG_EPOCH, NULL, (void **) &uip, NULL);
+    fi->epoch = (rc ? *uip : -1);
+    /* 0 means unknown */
+    rc = hge(fi->h, RPMTAG_ARCHIVESIZE, NULL, (void **) &uip, NULL);
+    fi->archiveSize = (rc ? *uip : 0);
+
     if (!hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc)) {
        fi->dc = 0;
        fi->fc = 0;
-       fi->dnl = NULL;
-       fi->bnl = NULL;
-       fi->dil = NULL;
-       fi->fmodes = NULL;
-       fi->fflags = NULL;
-       fi->fsizes = NULL;
-       fi->fstates = NULL;
-       fi->fmd5s = NULL;
-       fi->flinks = NULL;
-       fi->flangs = NULL;
        return;
     }
 
@@ -184,9 +111,6 @@ void loadFi(Header h, TFI_t fi)
 
 void freeFi(TFI_t fi)
 {
-    if (fi->h) {
-       headerFree(fi->h); fi->h = NULL;
-    }
     if (fi->name) {
        free((void *)fi->name); fi->name = NULL;
     }
@@ -205,33 +129,17 @@ void freeFi(TFI_t fi)
     if (fi->replaced) {
        free(fi->replaced); fi->replaced = NULL;
     }
-    if (fi->bnl) {
-       free(fi->bnl); fi->bnl = NULL;
-    }
-    if (fi->dnl) {
-       free(fi->dnl); fi->dnl = NULL;
-    }
-    if (fi->obnl) {
-       free(fi->obnl); fi->obnl = NULL;
-    }
-    if (fi->odnl) {
-       free(fi->odnl); fi->odnl = NULL;
-    }
-    if (fi->flinks) {
-       free(fi->flinks); fi->flinks = NULL;
-    }
-    if (fi->fmd5s) {
-       free(fi->fmd5s); fi->fmd5s = NULL;
-    }
-    if (fi->fuser) {
-       free(fi->fuser); fi->fuser = NULL;
-    }
-    if (fi->fgroup) {
-       free(fi->fgroup); fi->fgroup = NULL;
-    }
-    if (fi->flangs) {
-       free(fi->flangs); fi->flangs = NULL;
-    }
+
+    fi->bnl = headerFreeData(fi->bnl, -1);
+    fi->dnl = headerFreeData(fi->dnl, -1);
+    fi->obnl = headerFreeData(fi->obnl, -1);
+    fi->odnl = headerFreeData(fi->odnl, -1);
+    fi->flinks = headerFreeData(fi->flinks, -1);
+    fi->fmd5s = headerFreeData(fi->fmd5s, -1);
+    fi->fuser = headerFreeData(fi->fuser, -1);
+    fi->fgroup = headerFreeData(fi->fgroup, -1);
+    fi->flangs = headerFreeData(fi->flangs, -1);
+
     if (fi->apath) {
        free(fi->apath); fi->apath = NULL;
     }
@@ -245,27 +153,22 @@ void freeFi(TFI_t fi)
        free(fi->fmapflags); fi->fmapflags = NULL;
     }
 
+    fi->fsm = freeFSM(fi->fsm);
+
     switch (fi->type) {
     case TR_ADDED:
            break;
     case TR_REMOVED:
-       if (fi->fsizes) {
-           free((void *)fi->fsizes); fi->fsizes = NULL;
-       }
-       if (fi->fflags) {
-           free((void *)fi->fflags); fi->fflags = NULL;
-       }
-       if (fi->fmodes) {
-           free((void *)fi->fmodes); fi->fmodes = NULL;
-       }
-       if (fi->fstates) {
-           free((void *)fi->fstates); fi->fstates = NULL;
-       }
-       if (fi->dil) {
-           free((void *)fi->dil); fi->dil = NULL;
-       }
+       fi->fsizes = headerFreeData(fi->fsizes, -1);
+       fi->fflags = headerFreeData(fi->fflags, -1);
+       fi->fmodes = headerFreeData(fi->fmodes, -1);
+       fi->fstates = headerFreeData(fi->fstates, -1);
+       fi->dil = headerFreeData(fi->dil, -1);
        break;
     }
+    if (fi->h) {
+       headerFree(fi->h); fi->h = NULL;
+    }
 }
 
 /*@observer@*/ const char *const fiTypeString(TFI_t fi) {
@@ -279,31 +182,39 @@ void freeFi(TFI_t fi)
 
 /*@observer@*/ const char *const fileStageString(fileStage a) {
     switch(a) {
-    case FI_CREATE:    return "create";
-    case FI_INIT:      return "init";
-    case FI_MAP:       return "map";
-    case FI_SKIP:      return "skip";
-    case FI_PRE:       return "pre-process";
-    case FI_PROCESS:   return "process";
-    case FI_POST:      return "post-process";
-    case FI_NOTIFY:    return "notify";
-    case FI_UNDO:      return "undo";
-    case FI_COMMIT:    return "commit";
-    case FI_DESTROY:   return "destroy";
-    case FI_VERIFY:    return "verify";
-    case FI_UNLINK:    return "unlink";
-    case FI_RENAME:    return "rename";
-    case FI_MKDIR:     return "mkdir";
-    case FI_RMDIR:     return "rmdir";
-    case FI_CHOWN:     return "chown";
-    case FI_LCHOWN:    return "lchown";
-    case FI_CHMOD:     return "chmod";
-    case FI_UTIME:     return "utime";
-    case FI_SYMLINK:   return "symlink";
-    case FI_LINK:      return "link";
-    case FI_MKFIFO:    return "mkfifo";
-    case FI_MKNOD:     return "mknod";
-    default:           return "???";
+    case FSM_CREATE:   return "create";
+    case FSM_INIT:     return "init";
+    case FSM_MAP:      return "map ";
+    case FSM_MKDIRS:   return "mkdirs";
+    case FSM_RMDIRS:   return "rmdirs";
+    case FSM_PRE:      return "pre ";
+    case FSM_PROCESS:  return "process";
+    case FSM_POST:     return "post";
+    case FSM_MKLINKS:  return "mklinks";
+    case FSM_NOTIFY:   return "notify";
+    case FSM_UNDO:     return "undo";
+    case FSM_COMMIT:   return "commit";
+    case FSM_DESTROY:  return "destroy";
+    case FSM_VERIFY:   return "verify";
+
+    case FSM_UNLINK:   return "unlink";
+    case FSM_RENAME:   return "rename";
+    case FSM_MKDIR:    return "mkdir";
+    case FSM_RMDIR:    return "rmdir";
+    case FSM_CHOWN:    return "chown";
+    case FSM_LCHOWN:   return "lchown";
+    case FSM_CHMOD:    return "chmod";
+    case FSM_UTIME:    return "utime";
+    case FSM_SYMLINK:  return "symlink";
+    case FSM_LINK:     return "link";
+    case FSM_MKFIFO:   return "mkfifo";
+    case FSM_MKNOD:    return "mknod";
+
+    case FSM_NEXT:     return "next";
+    case FSM_EAT:      return "eat ";
+    case FSM_POS:      return "pos ";
+    case FSM_PAD:      return "pad ";
+    default:           return "??? ";
     }
     /*@noteached@*/
 }
@@ -311,65 +222,71 @@ void freeFi(TFI_t fi)
 /*@obserever@*/ const char *const fileActionString(fileAction a)
 {
     switch (a) {
-    case FA_UNKNOWN: return "unknown";
-    case FA_CREATE: return "create";
-    case FA_BACKUP: return "backup";
-    case FA_SAVE: return "save";
-    case FA_SKIP: return "skip";
-    case FA_ALTNAME: return "altname";
-    case FA_REMOVE: return "remove";
+    case FA_UNKNOWN:   return "unknown";
+    case FA_CREATE:    return "create";
+    case FA_BACKUP:    return "backup";
+    case FA_SAVE:      return "save";
+    case FA_SKIP:      return "skip";
+    case FA_ALTNAME:   return "altname";
+    case FA_REMOVE:    return "remove";
     case FA_SKIPNSTATE: return "skipnstate";
     case FA_SKIPNETSHARED: return "skipnetshared";
     case FA_SKIPMULTILIB: return "skipmultilib";
-    default: return "???";
+    default:           return "???";
     }
     /*@notreached@*/
 }
 
+/**
+ */
 struct pkgIterator {
-/*@kept@*/ TFI_t fi;
+/*@dependent@*/ /*@kept@*/ TFI_t fi;
     int i;
 };
 
-static void pkgFreeIterator(void * this) {
+/**
+ */
+static /*@null@*/ void * pkgFreeIterator(/*@only@*/ /*@null@*/ void * this) {
     if (this) free(this);
+    return NULL;
 }
 
-static void * pkgInitIterator(TFI_t fi) {
+/**
+ */
+static /*@only@*/ void * pkgInitIterator(/*@kept@*/ TFI_t fi) {
     struct pkgIterator *pi = xcalloc(sizeof(*pi), 1);
     pi->fi = fi;
     switch (fi->type) {
-    case TR_ADDED:     pi->i = 0;              break;
+    case TR_ADDED:     pi->i = 0;      break;
     case TR_REMOVED:   pi->i = fi->fc; break;
     }
     return pi;
 }
 
-static int pkgNextIterator(void * this) {
+/**
+ */
+static int pkgNextIterator(/*@null@*/ void * this) {
     struct pkgIterator *pi = this;
-    TFI_t fi = pi->fi;
     int i = -1;
-    switch (fi->type) {
-    case TR_ADDED:
-       if (pi->i < fi->fc)
-           i = pi->i++;
-       break;
-    case TR_REMOVED:
-       if (pi->i >= 0)
-           i = --pi->i;
-       break;
+
+    if (pi) {
+       TFI_t fi = pi->fi;
+       switch (fi->type) {
+       case TR_ADDED:
+           if (pi->i < fi->fc)
+               i = pi->i++;
+           break;
+       case TR_REMOVED:
+           if (pi->i >= 0)
+               i = --pi->i;
+           break;
+       }
     }
     return i;
 }
 
-
-int pkgActions(const rpmTransactionSet ts, TFI_t fi)
+int pkgActions(const rpmTransactionSet ts, TFI_t fi, fileStage a)
 {
-    int nb = (!ts->chrootDone ? strlen(ts->rootDir) : 0);
-    char * opath = alloca(nb + fi->dnlmax + fi->bnlmax + 64);
-    char * o = (!ts->chrootDone ? stpcpy(opath, ts->rootDir) : opath);
-    char * npath = alloca(nb + fi->dnlmax + fi->bnlmax + 64);
-    char * n = (!ts->chrootDone ? stpcpy(npath, ts->rootDir) : npath);
     int rc = 0;
     void * pi;
     int i;
@@ -379,121 +296,8 @@ int pkgActions(const rpmTransactionSet ts, TFI_t fi)
 
     pi = pkgInitIterator(fi);
     while ((i = pkgNextIterator(pi)) != -1) {
-       char * ext, * t;
-
-       if (fi->actions[i] & FA_DONE)
-           continue;
-
-       rpmMessage(RPMMESS_DEBUG, _("   file: %s%s action: %s\n"),
-                       fi->dnl[fi->dil[i]], fi->bnl[i],
-               fileActionString((fi->actions ? fi->actions[i] : FA_UNKNOWN)) );
-
-       ext = NULL;
-
-       switch (fi->actions[i] & ~FA_DONE) {
-       case FA_DONE:
-       case FA_SKIP:
-       case FA_SKIPMULTILIB:
-       case FA_UNKNOWN:
-           continue;
-           /*@notreached@*/ break;
-
-       case FA_CREATE:
-           assert(fi->type == TR_ADDED);
-           continue;
-           /*@notreached@*/ break;
-
-       case FA_SKIPNSTATE:
-           if (fi->type == TR_ADDED)
-               fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
-           continue;
-           /*@notreached@*/ break;
-
-       case FA_SKIPNETSHARED:
-           if (fi->type == TR_ADDED)
-               fi->fstates[i] = RPMFILE_STATE_NETSHARED;
-           continue;
-           /*@notreached@*/ break;
-       case FA_BACKUP:
-           ext = (fi->type == TR_ADDED ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE);
-           break;
-
-       case FA_ALTNAME:
-           assert(fi->type == TR_ADDED);
-           ext = SUFFIX_RPMNEW;
-           t = xmalloc(strlen(fi->bnl[i]) + strlen(ext) + 1);
-           (void)stpcpy(stpcpy(t, fi->bnl[i]), ext);
-           rpmMessage(RPMMESS_WARNING, _("%s: %s%s created as %s\n"),
-                       fiTypeString(fi), fi->dnl[fi->dil[i]], fi->bnl[i], t);
-           fi->bnl[i] = t;             /* XXX memory leak iff i = 0 */
-           ext = NULL;
-           continue;
-           /*@notreached@*/ break;
-
-       case FA_SAVE:
-           assert(fi->type == TR_ADDED);
-           ext = SUFFIX_RPMSAVE;
-           break;
-
-       case FA_REMOVE:
-           assert(fi->type == TR_REMOVED);
-           /* Append file name to (possible) root dir. */
-           (void) stpcpy( stpcpy(o, fi->dnl[fi->dil[i]]), fi->bnl[i]);
-           if (S_ISDIR(fi->fmodes[i])) {
-               if (!rmdir(opath))
-                   continue;
-               switch (errno) {
-               case ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
-               case ENOTEMPTY:
-#ifdef NOTYET
-                   if (fi->fflags[i] & RPMFILE_MISSINGOK)
-                       continue;
-#endif
-                   rpmError(RPMERR_RMDIR, 
-                       _("%s: cannot remove %s - directory not empty\n"), 
-                               fiTypeString(fi), o);
-                   break;
-               default:
-                   rpmError(RPMERR_RMDIR,
-                               _("%s rmdir of %s failed: %s\n"),
-                               fiTypeString(fi), o, strerror(errno));
-                   break;
-               }
-               rc++;
-               continue;
-               /*@notreached@*/ break;
-           }
-           if (!unlink(opath))
-               continue;
-           if (errno == ENOENT && (fi->fflags[i] & RPMFILE_MISSINGOK))
-               continue;
-           rpmError(RPMERR_UNLINK, _("%s removal of %s failed: %s\n"),
-                               fiTypeString(fi), o, strerror(errno));
+       if (pkgAction(ts, fi, i, a))
            rc++;
-           continue;
-           /*@notreached@*/ break;
-       }
-
-       if (ext == NULL)
-           continue;
-
-       /* Append file name to (possible) root dir. */
-       (void) stpcpy( stpcpy(o, fi->dnl[fi->dil[i]]), fi->bnl[i]);
-
-       /* XXX TR_REMOVED dinna do this. */
-       if (access(opath, F_OK) != 0)
-           continue;
-
-       (void) stpcpy( stpcpy(n, o), ext);
-       rpmMessage(RPMMESS_WARNING, _("%s: %s saved as %s\n"),
-                       fiTypeString(fi), o, n);
-
-       if (!rename(opath, npath))
-           continue;
-
-       rpmError(RPMERR_RENAME, _("%s rename of %s to %s failed: %s\n"),
-                       fiTypeString(fi), o, n, strerror(errno));
-       rc++;
     }
     pkgFreeIterator(pi);
     return rc;
index b6d8224..8c3dfe9 100644 (file)
@@ -6,38 +6,56 @@
 
 #include "depends.h"
 #include "install.h"
+
+/**
+ */
+typedef /*@abstract@*/ struct cpioHeader * FSM_t;
+
 #include "cpio.h"
 
 /**
  */
-#define        FI_INTERNAL     0x8000
-#define        _fi(_a)         ((_a) | FI_INTERNAL)
+#define        FSM_INTERNAL    0x8000
+#define        FSM_QUIET       0x4000
+#define        _fi(_a)         ((_a) | FSM_INTERNAL)
+#define        _fq(_a)         ((_a) | FSM_INTERNAL)
 typedef enum fileStage_e {
-    FI_CREATE  =  _fi(0),
-    FI_INIT    =   1,
-    FI_MAP     =   2,
-    FI_SKIP    =  _fi(3),
-    FI_PRE     =   4,
-    FI_PROCESS =   5,
-    FI_POST    =   6,
-    FI_NOTIFY  =  _fi(7),
-    FI_UNDO    =   8,
-    FI_COMMIT  =   9,
-    FI_DESTROY =  10,
-    FI_VERIFY  =  _fi(11),
-    FI_UNLINK  =  _fi(12),
-    FI_RENAME  =  _fi(13),
-    FI_MKDIR   =  _fi(14),
-    FI_RMDIR   =  _fi(15),
-    FI_CHOWN   =  _fi(16),
-    FI_LCHOWN  =  _fi(17),
-    FI_CHMOD   =  _fi(18),
-    FI_UTIME   =  _fi(19),
-    FI_SYMLINK =  _fi(20),
-    FI_LINK    =  _fi(21),
-    FI_MKFIFO  =  _fi(22),
-    FI_MKNOD   =  _fi(23),
+    FSM_UNKNOWN =   0,
+    FSM_INIT   =  _fq(1),
+    FSM_PRE    =  _fq(2),
+    FSM_PROCESS        =  _fq(3),
+    FSM_POST   =  _fq(4),
+    FSM_UNDO   =  5,
+    FSM_COMMIT =  6,
+
+    FSM_CREATE =  _fi(17),
+    FSM_MAP    =  _fi(18),
+    FSM_MKDIRS =  _fi(19),
+    FSM_RMDIRS =  _fi(20),
+    FSM_MKLINKS        =  _fi(21),
+    FSM_NOTIFY =  _fi(22),
+    FSM_DESTROY        =  _fi(23),
+    FSM_VERIFY =  _fi(24),
+
+    FSM_UNLINK =  _fi(33),
+    FSM_RENAME =  _fi(34),
+    FSM_MKDIR  =  _fi(35),
+    FSM_RMDIR  =  _fi(36),
+    FSM_CHOWN  =  _fi(37),
+    FSM_LCHOWN =  _fi(38),
+    FSM_CHMOD  =  _fi(39),
+    FSM_UTIME  =  _fi(40),
+    FSM_SYMLINK        =  _fi(41),
+    FSM_LINK   =  _fi(42),
+    FSM_MKFIFO =  _fi(43),
+    FSM_MKNOD  =  _fi(44),
+
+    FSM_NEXT   =  _fi(65),
+    FSM_EAT    =  _fi(66),
+    FSM_POS    =  _fi(67),
+    FSM_PAD    =  _fi(68),
 } fileStage;
+#undef _fi
 
 /**
  * File disposition(s) during package install/erase transaction.
@@ -53,7 +71,6 @@ typedef enum fileAction_e {
     FA_SKIPNSTATE,     /*!< ... untouched, state "not installed". */
     FA_SKIPNETSHARED,  /*!< ... untouched, state "netshared". */
     FA_SKIPMULTILIB,   /*!< ... untouched. @todo state "multilib" ???. */
-    FA_DONE = (1 << 31)
 } fileAction;
 
 
@@ -102,6 +119,7 @@ struct transactionFileInfo_s {
 /*@owned@*/ const char * name;
 /*@owned@*/ const char * version;
 /*@owned@*/ const char * release;
+    int_32 epoch;
     const uint_32 * fflags;    /*!< File flags (from header) */
     const uint_32 * fsizes;    /*!< File sizes (from header) */
 /*@owned@*/ const char ** bnl; /*!< Base names (from header) */
@@ -134,6 +152,8 @@ struct transactionFileInfo_s {
 /*@owned@*/ gid_t * fgids;
     int magic;
 #define        TFIMAGIC        0x09697923
+/*@owned@*/ FSM_t fsm;
+
   /* these are for TR_ADDED packages */
 /*@dependent@*/ struct availablePackage * ap;
 /*@owned@*/ struct sharedFileInfo * replaced;
@@ -147,14 +167,12 @@ extern "C" {
 #endif
 
 /**
- * Save/restore files from transaction element by renaming on file system.
- * @param ts           transaction set
- * @param fi           transaction element file info
- * @param dir          save or restore?
- * @return             0 on success
  */
-int dirstashPackage(const rpmTransactionSet ts, const TFI_t fi,
-               rollbackDir dir);
+/*@only@*/ /*@null@*/ FSM_t newFSM(void);
+
+/**
+ */
+/*@null@*/ FSM_t freeFSM(/*@only@*/ /*@null@*/ FSM_t fsm);
 
 /**
  * Load data from header into transaction file element info.
@@ -193,12 +211,42 @@ void freeFi(TFI_t fi)
 /*@observer@*/ const char *const fileActionString(fileAction a);
 
 /**
+ * Perform package install/remove actions for s single file.
+ * @param ts           transaction set
+ * @param fi           transaction element file info
+ * @param i            file index
+ * @param a            file stage
+ * @return             0 on success, 1 on failure
+ */
+int pkgAction(const rpmTransactionSet ts, TFI_t fi, int i, fileStage a);
+
+/**
  * Perform package install/remove actions.
  * @param ts           transaction set
  * @param fi           transaction element file info
+ * @param a            file stage
  * @return             0 on success, otherwise no. of failures
  */
-int pkgActions(const rpmTransactionSet ts, TFI_t fi);
+int pkgActions(const rpmTransactionSet ts, TFI_t fi, fileStage a);
+
+/**
+ * @return             0 on success
+ */
+int fsmSetup(FSM_t fsm, const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
+                const char ** failedFile);
+
+/**
+ * @return             0 on success
+ */
+int fsmTeardown(FSM_t fsm);
+
+/**
+ * Archive extraction state machine.
+ * @param fsm          file state machine data
+ * @param stage                next stage
+ * @return             0 on success
+ */
+int fsmStage(FSM_t fsm, fileStage stage);
 
 #ifdef __cplusplus
 }
index 84b1802..8f8831f 100644 (file)
@@ -1688,26 +1688,6 @@ int rpmRunTransactions(  rpmTransactionSet ts,
     }
 
     /* ===============================================
-     * Save removed files before upgrading.
-     */
-    if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
-       i = -2;
-       for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++) {
-           switch (ts->order[oc].type) {
-           case TR_ADDED:
-               i = ts->order[oc].u.addedIndex;
-               break;
-           case TR_REMOVED:
-               if (ts->order[oc].u.removed.dependsOnIndex != i)
-                   break;
-               if (ts->transFlags & RPMTRANS_FLAG_DIRSTASH)
-                   dirstashPackage(ts, fi, ROLLBACK_SAVE);
-               break;
-           }
-       }
-    }
-
-    /* ===============================================
      * Install and remove packages.
      */
 
index 225e5e6..4907292 100644 (file)
@@ -73,7 +73,7 @@ int removeBinaryPackage(const rpmTransactionSet ts, TFI_t fi)
            (void)ts->notify(h, RPMCALLBACK_UNINST_START, fi->fc, fi->fc,
                pkgKey, ts->notifyData);
 
-       rc = pkgActions(ts, fi);
+       rc = pkgActions(ts, fi, FSM_COMMIT);
 
        if (ts->notify)
            (void)ts->notify(h, RPMCALLBACK_UNINST_STOP, 0, fi->fc,
index 681d435..d342707 100644 (file)
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2001-01-28 14:10-0500\n"
+"POT-Creation-Date: 2001-01-29 17:39-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -70,1016 +70,1016 @@ msgstr ""
 msgid "Building for target %s\n"
 msgstr ""
 
-#: rpm.c:199 rpmqv.c:357
+#: rpm.c:201 rpmqv.c:357
 #, c-format
 msgid "rpm: %s\n"
 msgstr ""
 
-#: rpm.c:210 rpmqv.c:362
+#: rpm.c:212 rpmqv.c:362
 #, c-format
 msgid "RPM version %s\n"
 msgstr ""
 
-#: rpm.c:214 rpmqv.c:366
+#: rpm.c:216 rpmqv.c:366
 msgid "Copyright (C) 1998-2000 - Red Hat, Inc."
 msgstr ""
 
-#: rpm.c:215 rpmqv.c:367
+#: rpm.c:217 rpmqv.c:367
 msgid "This program may be freely redistributed under the terms of the GNU GPL"
 msgstr ""
 
-#: rpm.c:223
+#: rpm.c:225
 msgid "Usage: rpm {--help}"
 msgstr ""
 
-#: rpm.c:224
+#: rpm.c:226
 msgid "       rpm {--version}"
 msgstr ""
 
-#: rpm.c:225
+#: rpm.c:227
 msgid "       rpm {--initdb}   [--dbpath <dir>]"
 msgstr ""
 
-#: rpm.c:226
+#: rpm.c:228
 msgid ""
 "       rpm {--install -i} [-v] [--hash -h] [--percent] [--force] [--test]"
 msgstr ""
 
-#: rpm.c:227
+#: rpm.c:229
 msgid "                        [--replacepkgs] [--replacefiles] [--root <dir>]"
 msgstr ""
 
-#: rpm.c:228
+#: rpm.c:230
 msgid "                        [--excludedocs] [--includedocs] [--noscripts]"
 msgstr ""
 
-#: rpm.c:229
+#: rpm.c:231
 msgid ""
 "                        [--rcfile <file>] [--ignorearch] [--dbpath <dir>]"
 msgstr ""
 
-#: rpm.c:230
+#: rpm.c:232
 msgid ""
 "                        [--prefix <dir>] [--ignoreos] [--nodeps] [--allfiles]"
 msgstr ""
 
-#: rpm.c:231 rpm.c:240 rpm.c:250
+#: rpm.c:233 rpm.c:242 rpm.c:252
 msgid "                        [--ftpproxy <host>] [--ftpport <port>]"
 msgstr ""
 
-#: rpm.c:232 rpm.c:251
+#: rpm.c:234 rpm.c:253
 msgid "                        [--httpproxy <host>] [--httpport <port>]"
 msgstr ""
 
-#: rpm.c:233
+#: rpm.c:235
 msgid ""
 "                        [--justdb] [--noorder] [--relocate oldpath=newpath]"
 msgstr ""
 
-#: rpm.c:234
+#: rpm.c:236
 msgid ""
 "                        [--badreloc] [--notriggers] [--excludepath <path>]"
 msgstr ""
 
-#: rpm.c:235
+#: rpm.c:237
 msgid "                        [--ignoresize] file1.rpm ... fileN.rpm"
 msgstr ""
 
-#: rpm.c:236
+#: rpm.c:238
 msgid ""
 "       rpm {--upgrade -U} [-v] [--hash -h] [--percent] [--force] [--test]"
 msgstr ""
 
-#: rpm.c:237
+#: rpm.c:239
 msgid "                        [--oldpackage] [--root <dir>] [--noscripts]"
 msgstr ""
 
-#: rpm.c:238
+#: rpm.c:240
 msgid ""
 "                        [--excludedocs] [--includedocs] [--rcfile <file>]"
 msgstr ""
 
-#: rpm.c:239
+#: rpm.c:241
 msgid ""
 "                        [--ignorearch]  [--dbpath <dir>] [--prefix <dir>] "
 msgstr ""
 
-#: rpm.c:241
+#: rpm.c:243
 msgid "                        [--httpproxy <host>] [--httpport <port>] "
 msgstr ""
 
-#: rpm.c:242
+#: rpm.c:244
 msgid "                        [--ignoreos] [--nodeps] [--allfiles] [--justdb]"
 msgstr ""
 
-#: rpm.c:243
+#: rpm.c:245
 msgid "                        [--noorder] [--relocate oldpath=newpath]"
 msgstr ""
 
-#: rpm.c:244
+#: rpm.c:246
 msgid ""
 "                        [--badreloc] [--excludepath <path>] [--ignoresize]"
 msgstr ""
 
-#: rpm.c:245
+#: rpm.c:247
 msgid "                        file1.rpm ... fileN.rpm"
 msgstr ""
 
-#: rpm.c:246
+#: rpm.c:248
 msgid "       rpm {--query -q} [-afpg] [-i] [-l] [-s] [-d] [-c] [-v] [-R]"
 msgstr ""
 
-#: rpm.c:247
+#: rpm.c:249
 msgid "                        [--scripts] [--root <dir>] [--rcfile <file>]"
 msgstr ""
 
-#: rpm.c:248
+#: rpm.c:250
 msgid "                        [--whatprovides] [--whatrequires] [--requires]"
 msgstr ""
 
-#: rpm.c:249
+#: rpm.c:251
 msgid "                        [--triggeredby]"
 msgstr ""
 
-#: rpm.c:252
+#: rpm.c:254
 msgid "                        [--provides] [--triggers] [--dump]"
 msgstr ""
 
-#: rpm.c:253
+#: rpm.c:255
 msgid "                        [--changelog] [--dbpath <dir>] [targets]"
 msgstr ""
 
-#: rpm.c:254
+#: rpm.c:256
 msgid "       rpm {--verify -V -y} [-afpg] [--root <dir>] [--rcfile <file>]"
 msgstr ""
 
-#: rpm.c:255
+#: rpm.c:257
 msgid ""
 "                        [--dbpath <dir>] [--nodeps] [--nofiles] [--noscripts]"
 msgstr ""
 
-#: rpm.c:256
+#: rpm.c:258
 msgid "                        [--nomd5] [targets]"
 msgstr ""
 
-#: rpm.c:257
+#: rpm.c:259
 msgid "       rpm {--setperms} [-afpg] [target]"
 msgstr ""
 
-#: rpm.c:258
+#: rpm.c:260
 msgid "       rpm {--setugids} [-afpg] [target]"
 msgstr ""
 
-#: rpm.c:259
+#: rpm.c:261
 msgid "       rpm {--freshen -F} file1.rpm ... fileN.rpm"
 msgstr ""
 
-#: rpm.c:260
+#: rpm.c:262
 msgid "       rpm {--erase -e} [--root <dir>] [--noscripts] [--rcfile <file>]"
 msgstr ""
 
-#: rpm.c:261
+#: rpm.c:263
 msgid "                        [--dbpath <dir>] [--nodeps] [--allmatches]"
 msgstr ""
 
-#: rpm.c:262
+#: rpm.c:264
 msgid "                        [--justdb] [--notriggers] package1 ... packageN"
 msgstr ""
 
-#: rpm.c:263
+#: rpm.c:265
 msgid "       rpm {--resign} [--rcfile <file>] package1 package2 ... packageN"
 msgstr ""
 
-#: rpm.c:264
+#: rpm.c:266
 msgid "       rpm {--addsign} [--rcfile <file>] package1 package2 ... packageN"
 msgstr ""
 
-#: rpm.c:265
+#: rpm.c:267
 msgid ""
 "       rpm {--checksig -K} [--nopgp] [--nogpg] [--nomd5] [--rcfile <file>]"
 msgstr ""
 
-#: rpm.c:266
+#: rpm.c:268
 msgid "                           package1 ... packageN"
 msgstr ""
 
-#: rpm.c:267
+#: rpm.c:269
 msgid "       rpm {--rebuilddb} [--rcfile <file>] [--dbpath <dir>]"
 msgstr ""
 
-#: rpm.c:268
+#: rpm.c:270
 msgid "       rpm {--querytags}"
 msgstr ""
 
-#: rpm.c:302 rpmqv.c:442
+#: rpm.c:304 rpmqv.c:442
 msgid "Usage:"
 msgstr ""
 
-#: rpm.c:304 rpmqv.c:444
+#: rpm.c:306 rpmqv.c:444
 msgid "print this message"
 msgstr ""
 
-#: rpm.c:306 rpmqv.c:129 rpmqv.c:446
+#: rpm.c:308 rpmqv.c:129 rpmqv.c:446
 msgid "print the version of rpm being used"
 msgstr ""
 
-#: rpm.c:309
+#: rpm.c:311
 msgid "   All modes support the following arguments:"
 msgstr ""
 
-#: rpm.c:310
+#: rpm.c:312
 msgid "    --define '<name> <body>'"
 msgstr ""
 
-#: rpm.c:311 rpmqv.c:136 rpmqv.c:451
+#: rpm.c:313 rpmqv.c:136 rpmqv.c:451
 msgid "define macro <name> with value <body>"
 msgstr ""
 
-#: rpm.c:312
+#: rpm.c:314
 msgid "    --eval '<name>+'      "
 msgstr ""
 
-#: rpm.c:313
+#: rpm.c:315
 msgid "print the expansion of macro <name> to stdout"
 msgstr ""
 
-#: rpm.c:314
+#: rpm.c:316
 msgid "    --pipe <cmd>          "
 msgstr ""
 
-#: rpm.c:315 rpmqv.c:142 rpmqv.c:455
+#: rpm.c:317 rpmqv.c:142 rpmqv.c:455
 msgid "send stdout to <cmd>"
 msgstr ""
 
-#: rpm.c:316
+#: rpm.c:318
 msgid "    --rcfile <file>       "
 msgstr ""
 
-#: rpm.c:317
+#: rpm.c:319
 msgid "use <file> instead of /etc/rpmrc and $HOME/.rpmrc"
 msgstr ""
 
-#: rpm.c:319 rpmqv.c:160 rpmqv.c:459
+#: rpm.c:321 rpmqv.c:160 rpmqv.c:459
 msgid "display final rpmrc and macro configuration"
 msgstr ""
 
-#: rpm.c:321 rpmqv.c:467
+#: rpm.c:323 rpmqv.c:467
 msgid "be a little more verbose"
 msgstr ""
 
-#: rpm.c:323 rpmqv.c:469
+#: rpm.c:325 rpmqv.c:469
 msgid "be incredibly verbose (for debugging)"
 msgstr ""
 
-#: rpm.c:326
+#: rpm.c:328
 msgid "   Install, upgrade and query (with -p) allow URL's to be used in place"
 msgstr ""
 
-#: rpm.c:327
+#: rpm.c:329
 msgid "   of file names as well as the following options:"
 msgstr ""
 
-#: rpm.c:328
+#: rpm.c:330
 msgid "      --ftpproxy <host>   "
 msgstr ""
 
-#: rpm.c:329 rpmqv.c:476
+#: rpm.c:331 rpmqv.c:476
 msgid "hostname or IP of ftp proxy"
 msgstr ""
 
-#: rpm.c:330
+#: rpm.c:332
 msgid "      --ftpport <port>    "
 msgstr ""
 
-#: rpm.c:331 rpmqv.c:478
+#: rpm.c:333 rpmqv.c:478
 msgid "port number of ftp server (or proxy)"
 msgstr ""
 
-#: rpm.c:332
+#: rpm.c:334
 msgid "      --httpproxy <host>  "
 msgstr ""
 
-#: rpm.c:333 rpmqv.c:480
+#: rpm.c:335 rpmqv.c:480
 msgid "hostname or IP of http proxy"
 msgstr ""
 
-#: rpm.c:334
+#: rpm.c:336
 msgid "      --httpport <port>   "
 msgstr ""
 
-#: rpm.c:335 rpmqv.c:482
+#: rpm.c:337 rpmqv.c:482
 msgid "port number of http server (or proxy)"
 msgstr ""
 
-#: rpm.c:339 rpmqv.c:502
+#: rpm.c:341 rpmqv.c:502
 msgid "query mode"
 msgstr ""
 
-#: rpm.c:340 rpm.c:386 rpm.c:411 rpm.c:463 rpm.c:537
+#: rpm.c:342 rpm.c:388 rpm.c:413 rpm.c:465 rpm.c:539
 msgid "      --dbpath <dir>      "
 msgstr ""
 
-#: rpm.c:341 rpm.c:387 rpm.c:412 rpm.c:464 rpm.c:538 rpmqv.c:462
+#: rpm.c:343 rpm.c:389 rpm.c:414 rpm.c:466 rpm.c:540 rpmqv.c:462
 msgid "use <dir> as the directory for the database"
 msgstr ""
 
-#: rpm.c:342
+#: rpm.c:344
 msgid "      --queryformat <qfmt>"
 msgstr ""
 
-#: rpm.c:343 rpmqv.c:504
+#: rpm.c:345 rpmqv.c:504
 msgid "use <qfmt> as the header format (implies --info)"
 msgstr ""
 
-#: rpm.c:344 rpm.c:388 rpm.c:446 rpm.c:475
+#: rpm.c:346 rpm.c:390 rpm.c:448 rpm.c:477
 msgid "      --root <dir>        "
 msgstr ""
 
-#: rpm.c:345 rpm.c:389 rpm.c:447 rpm.c:476 rpm.c:540 rpmqv.c:145 rpmqv.c:464
+#: rpm.c:347 rpm.c:391 rpm.c:449 rpm.c:478 rpm.c:542 rpmqv.c:145 rpmqv.c:464
 msgid "use <dir> as the top level directory"
 msgstr ""
 
-#: rpm.c:346
+#: rpm.c:348
 msgid "      Package specification options:"
 msgstr ""
 
-#: rpm.c:348
+#: rpm.c:350
 msgid "query all packages"
 msgstr ""
 
-#: rpm.c:349
+#: rpm.c:351
 msgid "        -f <file>+        "
 msgstr ""
 
-#: rpm.c:350
+#: rpm.c:352
 msgid "query package owning <file>"
 msgstr ""
 
-#: rpm.c:351
+#: rpm.c:353
 msgid "        -p <packagefile>+ "
 msgstr ""
 
-#: rpm.c:352
+#: rpm.c:354
 msgid "query (uninstalled) package <packagefile>"
 msgstr ""
 
-#: rpm.c:353
+#: rpm.c:355
 msgid "        --triggeredby <pkg>"
 msgstr ""
 
-#: rpm.c:354
+#: rpm.c:356
 msgid "query packages triggered by <pkg>"
 msgstr ""
 
-#: rpm.c:355
+#: rpm.c:357
 msgid "        --whatprovides <cap>"
 msgstr ""
 
-#: rpm.c:356
+#: rpm.c:358
 msgid "query packages which provide <cap> capability"
 msgstr ""
 
-#: rpm.c:357
+#: rpm.c:359
 msgid "        --whatrequires <cap>"
 msgstr ""
 
-#: rpm.c:358
+#: rpm.c:360
 msgid "query packages which require <cap> capability"
 msgstr ""
 
-#: rpm.c:359
+#: rpm.c:361
 msgid "      Information selection options:"
 msgstr ""
 
-#: rpm.c:361 rpmqv.c:508
+#: rpm.c:363 rpmqv.c:508
 msgid "display package information"
 msgstr ""
 
-#: rpm.c:363 rpmqv.c:510
+#: rpm.c:365 rpmqv.c:510
 msgid "display the package's change log"
 msgstr ""
 
-#: rpm.c:365 rpmqv.c:512
+#: rpm.c:367 rpmqv.c:512
 msgid "display package file list"
 msgstr ""
 
-#: rpm.c:367 rpmqv.c:514
+#: rpm.c:369 rpmqv.c:514
 msgid "show file states (implies -l)"
 msgstr ""
 
-#: rpm.c:369 rpmqv.c:516
+#: rpm.c:371 rpmqv.c:516
 msgid "list only documentation files (implies -l)"
 msgstr ""
 
-#: rpm.c:371 rpmqv.c:518
+#: rpm.c:373 rpmqv.c:518
 msgid "list only configuration files (implies -l)"
 msgstr ""
 
-#: rpm.c:373 rpmqv.c:520
+#: rpm.c:375 rpmqv.c:520
 msgid ""
 "show all verifiable information for each file (must be used with -l, -c, or "
 "-d)"
 msgstr ""
 
-#: rpm.c:375
+#: rpm.c:377
 msgid "list capabilities package provides"
 msgstr ""
 
-#: rpm.c:377
+#: rpm.c:379
 msgid "list package dependencies"
 msgstr ""
 
-#: rpm.c:379
+#: rpm.c:381
 msgid "print the various [un]install scripts"
 msgstr ""
 
-#: rpm.c:381
+#: rpm.c:383
 msgid "show the trigger scripts contained in the package"
 msgstr ""
 
-#: rpm.c:385 rpmqv.c:531
+#: rpm.c:387 rpmqv.c:531
 msgid ""
 "verify a package installation using the same same package specification "
 "options as -q"
 msgstr ""
 
-#: lib/poptBT.c:180 lib/verify.c:56 rpm.c:391 rpm.c:433 rpm.c:468 rpmqv.c:263
+#: lib/poptBT.c:180 lib/verify.c:56 rpm.c:393 rpm.c:435 rpm.c:470 rpmqv.c:263
 #: rpmqv.c:533 rpmqv.c:581 rpmqv.c:615
 msgid "do not verify package dependencies"
 msgstr ""
 
-#: lib/verify.c:62 rpm.c:393 rpmqv.c:209 rpmqv.c:537
+#: lib/verify.c:62 rpm.c:395 rpmqv.c:209 rpmqv.c:537
 msgid "do not verify file md5 checksums"
 msgstr ""
 
-#: rpm.c:395 rpmqv.c:535
+#: rpm.c:397 rpmqv.c:535
 msgid "do not verify file attributes"
 msgstr ""
 
-#: rpm.c:397 rpmqv.c:542
+#: rpm.c:399 rpmqv.c:542
 msgid "list the tags that can be used in a query format"
 msgstr ""
 
-#: rpm.c:400
+#: rpm.c:402
 msgid "    --install <packagefile>"
 msgstr ""
 
-#: rpm.c:401
+#: rpm.c:403
 msgid "    -i <packagefile>      "
 msgstr ""
 
-#: rpm.c:402 rpmqv.c:259 rpmqv.c:556
+#: rpm.c:404 rpmqv.c:259 rpmqv.c:556
 msgid "install package"
 msgstr ""
 
-#: rpm.c:403
+#: rpm.c:405
 msgid "      --excludepath <path>"
 msgstr ""
 
-#: rpm.c:404
+#: rpm.c:406
 msgid "skip files in path <path>"
 msgstr ""
 
-#: rpm.c:405
+#: rpm.c:407
 msgid "      --relocate <oldpath>=<newpath>"
 msgstr ""
 
-#: rpm.c:406 rpmqv.c:593
+#: rpm.c:408 rpmqv.c:593
 msgid "relocate files from <oldpath> to <newpath>"
 msgstr ""
 
-#: rpm.c:408 rpmqv.c:231 rpmqv.c:561
+#: rpm.c:410 rpmqv.c:231 rpmqv.c:561
 msgid "relocate files in non-relocateable package"
 msgstr ""
 
-#: rpm.c:409
+#: rpm.c:411
 msgid "      --prefix <dir>      "
 msgstr ""
 
-#: rpm.c:410 rpmqv.c:277 rpmqv.c:591
+#: rpm.c:412 rpmqv.c:277 rpmqv.c:591
 msgid "relocate the package to <dir>, if relocatable"
 msgstr ""
 
-#: rpm.c:414 rpmqv.c:237 rpmqv.c:563
+#: rpm.c:416 rpmqv.c:237 rpmqv.c:563
 msgid "do not install documentation"
 msgstr ""
 
-#: rpm.c:416 rpmqv.c:242 rpmqv.c:567
+#: rpm.c:418 rpmqv.c:242 rpmqv.c:567
 msgid "short hand for --replacepkgs --replacefiles"
 msgstr ""
 
-#: rpm.c:418 rpmqv.c:248 rpmqv.c:569
+#: rpm.c:420 rpmqv.c:248 rpmqv.c:569
 msgid "print hash marks as package installs (good with -v)"
 msgstr ""
 
-#: rpm.c:420 rpmqv.c:225 rpmqv.c:558
+#: rpm.c:422 rpmqv.c:225 rpmqv.c:558
 msgid "install all files, even configurations which might otherwise be skipped"
 msgstr ""
 
-#: rpm.c:423 rpmqv.c:250 rpmqv.c:571
+#: rpm.c:425 rpmqv.c:250 rpmqv.c:571
 msgid "don't verify package architecture"
 msgstr ""
 
-#: rpm.c:425 rpmqv.c:255 rpmqv.c:573
+#: rpm.c:427 rpmqv.c:255 rpmqv.c:573
 msgid "don't check disk space before installing"
 msgstr ""
 
-#: rpm.c:427 rpmqv.c:252 rpmqv.c:575
+#: rpm.c:429 rpmqv.c:252 rpmqv.c:575
 msgid "don't verify package operating system"
 msgstr ""
 
-#: rpm.c:429 rpmqv.c:257 rpmqv.c:577
+#: rpm.c:431 rpmqv.c:257 rpmqv.c:577
 msgid "install documentation"
 msgstr ""
 
-#: rpm.c:431 rpm.c:466 rpmqv.c:261 rpmqv.c:579 rpmqv.c:613
+#: rpm.c:433 rpm.c:468 rpmqv.c:261 rpmqv.c:579 rpmqv.c:613
 msgid "update the database, but do not modify the filesystem"
 msgstr ""
 
-#: rpm.c:435 rpm.c:470 rpmqv.c:265 rpmqv.c:583 rpmqv.c:617
+#: rpm.c:437 rpm.c:472 rpmqv.c:265 rpmqv.c:583 rpmqv.c:617
 msgid "do not reorder package installation to satisfy dependencies"
 msgstr ""
 
-#: rpm.c:437
+#: rpm.c:439
 msgid "don't execute any installation scripts"
 msgstr ""
 
-#: rpm.c:439 rpm.c:474 rpmqv.c:621
+#: rpm.c:441 rpm.c:476 rpmqv.c:621
 msgid "don't execute any scripts triggered by this package"
 msgstr ""
 
-#: rpm.c:441 rpmqv.c:275 rpmqv.c:589
+#: rpm.c:443 rpmqv.c:275 rpmqv.c:589
 msgid "print percentages as package installs"
 msgstr ""
 
-#: rpm.c:443 rpmqv.c:286 rpmqv.c:595
+#: rpm.c:445 rpmqv.c:286 rpmqv.c:595
 msgid "install even if the package replaces installed files"
 msgstr ""
 
-#: rpm.c:445 rpmqv.c:288 rpmqv.c:597
+#: rpm.c:447 rpmqv.c:288 rpmqv.c:597
 msgid "reinstall if the package is already present"
 msgstr ""
 
-#: rpm.c:449 rpmqv.c:290 rpmqv.c:599
+#: rpm.c:451 rpmqv.c:290 rpmqv.c:599
 msgid "don't install, but tell if it would work or not"
 msgstr ""
 
-#: rpm.c:452
+#: rpm.c:454
 msgid "    --upgrade <packagefile>"
 msgstr ""
 
-#: rpm.c:453
+#: rpm.c:455
 msgid "    -U <packagefile>      "
 msgstr ""
 
-#: rpm.c:454 rpmqv.c:603
+#: rpm.c:456 rpmqv.c:603
 msgid "upgrade package (same options as --install, plus)"
 msgstr ""
 
-#: rpm.c:456 rpmqv.c:272 rpmqv.c:605
+#: rpm.c:458 rpmqv.c:272 rpmqv.c:605
 msgid ""
 "upgrade to an old version of the package (--force on upgrades does this "
 "automatically)"
 msgstr ""
 
-#: rpm.c:458
+#: rpm.c:460
 msgid "    --erase <package>"
 msgstr ""
 
-#: rpm.c:460 rpmqv.c:235 rpmqv.c:609
+#: rpm.c:462 rpmqv.c:235 rpmqv.c:609
 msgid "erase (uninstall) package"
 msgstr ""
 
-#: rpm.c:462 rpmqv.c:228 rpmqv.c:611
+#: rpm.c:464 rpmqv.c:228 rpmqv.c:611
 msgid ""
 "remove all packages which match <package> (normally an error is generated if "
 "<package> specified multiple packages)"
 msgstr ""
 
-#: rpm.c:472 rpmqv.c:619
+#: rpm.c:474 rpmqv.c:619
 msgid "do not execute any package specific scripts"
 msgstr ""
 
-#: rpm.c:478
+#: rpm.c:480
 msgid "    -b<stage> <spec>      "
 msgstr ""
 
-#: rpm.c:479
+#: rpm.c:481
 msgid "    -t<stage> <tarball>   "
 msgstr ""
 
-#: rpm.c:480
+#: rpm.c:482
 msgid "build package, where <stage> is one of:"
 msgstr ""
 
-#: rpm.c:482
+#: rpm.c:484
 msgid "prep (unpack sources and apply patches)"
 msgstr ""
 
-#: rpm.c:484
+#: rpm.c:486
 #, c-format
 msgid "list check (do some cursory checks on %files)"
 msgstr ""
 
-#: rpm.c:486
+#: rpm.c:488
 msgid "compile (prep and compile)"
 msgstr ""
 
-#: rpm.c:488
+#: rpm.c:490
 msgid "install (prep, compile, install)"
 msgstr ""
 
-#: rpm.c:490
+#: rpm.c:492
 msgid "binary package (prep, compile, install, package)"
 msgstr ""
 
-#: rpm.c:492
+#: rpm.c:494
 msgid "bin/src package (prep, compile, install, package)"
 msgstr ""
 
-#: lib/poptBT.c:191 rpm.c:494
+#: lib/poptBT.c:191 rpm.c:496
 msgid "skip straight to specified stage (only for c,i)"
 msgstr ""
 
-#: lib/poptBT.c:172 rpm.c:496
+#: lib/poptBT.c:172 rpm.c:498
 msgid "remove build tree when done"
 msgstr ""
 
-#: lib/poptBT.c:187 rpm.c:498
+#: lib/poptBT.c:187 rpm.c:500
 msgid "remove sources when done"
 msgstr ""
 
-#: rpm.c:500
+#: rpm.c:502
 msgid "remove spec file when done"
 msgstr ""
 
-#: lib/poptBT.c:193 rpm.c:502 rpmqv.c:201
+#: lib/poptBT.c:193 rpm.c:504 rpmqv.c:201
 msgid "generate PGP/GPG signature"
 msgstr ""
 
-#: rpm.c:503
+#: rpm.c:505
 msgid "      --buildroot <dir>   "
 msgstr ""
 
-#: rpm.c:504
+#: rpm.c:506
 msgid "use <dir> as the build root"
 msgstr ""
 
-#: rpm.c:505
+#: rpm.c:507
 msgid "      --target=<platform>+"
 msgstr ""
 
-#: rpm.c:506
+#: rpm.c:508
 msgid "build the packages for the build targets platform1...platformN."
 msgstr ""
 
-#: rpm.c:508
+#: rpm.c:510
 msgid "do not execute any stages"
 msgstr ""
 
-#: rpm.c:509
+#: rpm.c:511
 msgid "      --timecheck <secs>  "
 msgstr ""
 
-#: rpm.c:510
+#: rpm.c:512
 msgid "set the time check to <secs> seconds (0 disables)"
 msgstr ""
 
-#: rpm.c:512
+#: rpm.c:514
 msgid "    --rebuild <src_pkg>   "
 msgstr ""
 
-#: rpm.c:513
+#: rpm.c:515
 msgid ""
 "install source package, build binary package and remove spec file, sources, "
 "patches, and icons."
 msgstr ""
 
-#: rpm.c:514
+#: rpm.c:516
 msgid "    --recompile <src_pkg> "
 msgstr ""
 
-#: rpm.c:515
+#: rpm.c:517
 msgid "like --rebuild, but don't build any package"
 msgstr ""
 
-#: rpm.c:518
+#: rpm.c:520
 msgid "    --resign <pkg>+       "
 msgstr ""
 
-#: rpm.c:519 rpmqv.c:199 rpmqv.c:627
+#: rpm.c:521 rpmqv.c:199 rpmqv.c:627
 msgid "sign a package (discard current signature)"
 msgstr ""
 
-#: rpm.c:520
+#: rpm.c:522
 msgid "    --addsign <pkg>+      "
 msgstr ""
 
-#: rpm.c:521 rpmqv.c:197 rpmqv.c:629
+#: rpm.c:523 rpmqv.c:197 rpmqv.c:629
 msgid "add a signature to a package"
 msgstr ""
 
-#: rpm.c:522
+#: rpm.c:524
 msgid "    --checksig <pkg>+"
 msgstr ""
 
-#: rpm.c:523
+#: rpm.c:525
 msgid "    -K <pkg>+             "
 msgstr ""
 
-#: rpm.c:524 rpmqv.c:203 rpmqv.c:633
+#: rpm.c:526 rpmqv.c:203 rpmqv.c:633
 msgid "verify package signature"
 msgstr ""
 
-#: rpm.c:526 rpmqv.c:205 rpmqv.c:635
+#: rpm.c:528 rpmqv.c:205 rpmqv.c:635
 msgid "skip any PGP signatures"
 msgstr ""
 
-#: rpm.c:528 rpmqv.c:207 rpmqv.c:637
+#: rpm.c:530 rpmqv.c:207 rpmqv.c:637
 msgid "skip any GPG signatures"
 msgstr ""
 
-#: rpm.c:530 rpmqv.c:639
+#: rpm.c:532 rpmqv.c:639
 msgid "skip any MD5 signatures"
 msgstr ""
 
-#: rpm.c:534
+#: rpm.c:536
 msgid "make sure a valid database exists"
 msgstr ""
 
-#: rpm.c:536
+#: rpm.c:538
 msgid "rebuild database from existing database"
 msgstr ""
 
-#: rpm.c:544 rpmqv.c:544
+#: rpm.c:546 rpmqv.c:544
 msgid ""
 "set the file permissions to those in the package database using the same "
 "package specification options as -q"
 msgstr ""
 
-#: rpm.c:547 rpmqv.c:547
+#: rpm.c:549 rpmqv.c:547
 msgid ""
 "set the file owner and group to those in the package database using the same "
 "package specification options as -q"
 msgstr ""
 
-#: rpm.c:687 rpm.c:693 rpm.c:702 rpm.c:724 rpm.c:730 rpm.c:737 rpm.c:745
-#: rpm.c:753 rpm.c:774 rpm.c:837 rpmqv.c:832 rpmqv.c:838 rpmqv.c:845
+#: rpm.c:689 rpm.c:695 rpm.c:704 rpm.c:726 rpm.c:732 rpm.c:739 rpm.c:747
+#: rpm.c:755 rpm.c:776 rpm.c:839 rpmqv.c:832 rpmqv.c:838 rpmqv.c:845
 #: rpmqv.c:851 rpmqv.c:885 rpmqv.c:893 rpmqv.c:899 rpmqv.c:907 rpmqv.c:974
 msgid "only one major mode may be specified"
 msgstr ""
 
-#: rpm.c:695
+#: rpm.c:697
 msgid "-u and --uninstall are deprecated and no longer work.\n"
 msgstr ""
 
-#: rpm.c:697
+#: rpm.c:699
 msgid "Use -e or --erase instead.\n"
 msgstr ""
 
-#: rpm.c:780 rpmqv.c:869
+#: rpm.c:782 rpmqv.c:869
 msgid "relocations must begin with a /"
 msgstr ""
 
-#: rpm.c:782 rpmqv.c:871
+#: rpm.c:784 rpmqv.c:871
 msgid "relocations must contain a ="
 msgstr ""
 
-#: rpm.c:785 rpmqv.c:874
+#: rpm.c:787 rpmqv.c:874
 msgid "relocations must have a / following the ="
 msgstr ""
 
-#: rpm.c:794 rpmqv.c:858
+#: rpm.c:796 rpmqv.c:858
 msgid "exclude paths must begin with a /"
 msgstr ""
 
-#: rpm.c:803 rpmqv.c:928
+#: rpm.c:805 rpmqv.c:928
 msgid "The --rcfile option has been eliminated.\n"
 msgstr ""
 
-#: rpm.c:804
+#: rpm.c:806
 msgid "Use --macros with a colon separated list of macro files to read.\n"
 msgstr ""
 
-#: rpm.c:809 rpmqv.c:934
+#: rpm.c:811 rpmqv.c:934
 #, c-format
 msgid "Internal error in argument processing (%d) :-(\n"
 msgstr ""
 
-#: rpm.c:844 rpmqv.c:989
+#: rpm.c:846 rpmqv.c:989
 msgid "one type of query/verify may be performed at a time"
 msgstr ""
 
-#: rpm.c:849 rpmqv.c:993
+#: rpm.c:851 rpmqv.c:993
 msgid "unexpected query flags"
 msgstr ""
 
-#: rpm.c:852 rpmqv.c:996
+#: rpm.c:854 rpmqv.c:996
 msgid "unexpected query format"
 msgstr ""
 
-#: rpm.c:855 rpmqv.c:999
+#: rpm.c:857 rpmqv.c:999
 msgid "unexpected query source"
 msgstr ""
 
-#: rpm.c:858 rpmqv.c:1009
+#: rpm.c:860 rpmqv.c:1009
 msgid "only installation, upgrading, rmsource and rmspec may be forced"
 msgstr ""
 
-#: rpm.c:861 rpmqv.c:1014
+#: rpm.c:863 rpmqv.c:1014
 msgid "files may only be relocated during package installation"
 msgstr ""
 
-#: rpm.c:864 rpmqv.c:1017
+#: rpm.c:866 rpmqv.c:1017
 msgid "only one of --prefix or --relocate may be used"
 msgstr ""
 
-#: rpm.c:867 rpmqv.c:1020
+#: rpm.c:869 rpmqv.c:1020
 msgid ""
 "--relocate and --excludepath may only be used when installing new packages"
 msgstr ""
 
-#: rpm.c:870 rpmqv.c:1023
+#: rpm.c:872 rpmqv.c:1023
 msgid "--prefix may only be used when installing new packages"
 msgstr ""
 
-#: rpm.c:873 rpmqv.c:1026
+#: rpm.c:875 rpmqv.c:1026
 msgid "arguments to --prefix must begin with a /"
 msgstr ""
 
-#: rpm.c:876 rpmqv.c:1029
+#: rpm.c:878 rpmqv.c:1029
 msgid "--hash (-h) may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:880 rpmqv.c:1033
+#: rpm.c:882 rpmqv.c:1033
 msgid "--percent may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:884 rpmqv.c:1038
+#: rpm.c:886 rpmqv.c:1038
 msgid "--replacefiles may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:888 rpmqv.c:1042
+#: rpm.c:890 rpmqv.c:1042
 msgid "--replacepkgs may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:892 rpmqv.c:1046
+#: rpm.c:894 rpmqv.c:1046
 msgid "--excludedocs may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:896 rpmqv.c:1050
+#: rpm.c:898 rpmqv.c:1050
 msgid "--includedocs may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:900 rpmqv.c:1054
+#: rpm.c:902 rpmqv.c:1054
 msgid "only one of --excludedocs and --includedocs may be specified"
 msgstr ""
 
-#: rpm.c:904 rpmqv.c:1058
+#: rpm.c:906 rpmqv.c:1058
 msgid "--ignorearch may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:908 rpmqv.c:1062
+#: rpm.c:910 rpmqv.c:1062
 msgid "--ignoreos may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:912 rpmqv.c:1067
+#: rpm.c:914 rpmqv.c:1067
 msgid "--ignoresize may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:916 rpmqv.c:1071
+#: rpm.c:918 rpmqv.c:1071
 msgid "--allmatches may only be specified during package erasure"
 msgstr ""
 
-#: rpm.c:920 rpmqv.c:1075
+#: rpm.c:922 rpmqv.c:1075
 msgid "--allfiles may only be specified during package installation"
 msgstr ""
 
-#: rpm.c:924 rpmqv.c:1080
+#: rpm.c:926 rpmqv.c:1080
 msgid "--justdb may only be specified during package installation and erasure"
 msgstr ""
 
-#: rpm.c:929
+#: rpm.c:931
 msgid ""
 "--noscripts may only be specified during package installation, erasure, and "
 "verification"
 msgstr ""
 
-#: rpm.c:933
+#: rpm.c:935
 msgid ""
 "--notriggers may only be specified during package installation, erasure, and "
 "verification"
 msgstr ""
 
-#: rpm.c:937 rpmqv.c:1091
+#: rpm.c:939 rpmqv.c:1091
 msgid ""
 "--nodeps may only be specified during package building, rebuilding, "
 "recompilation, installation,erasure, and verification"
 msgstr ""
 
-#: rpm.c:942 rpmqv.c:1096
+#: rpm.c:944 rpmqv.c:1096
 msgid ""
 "--test may only be specified during package installation, erasure, and "
 "building"
 msgstr ""
 
-#: rpm.c:946 rpmqv.c:1101
+#: rpm.c:948 rpmqv.c:1101
 msgid ""
 "--root (-r) may only be specified during installation, erasure, querying, "
 "and database rebuilds"
 msgstr ""
 
-#: rpm.c:958 rpmqv.c:1113
+#: rpm.c:960 rpmqv.c:1113
 msgid "arguments to --root (-r) must begin with a /"
 msgstr ""
 
-#: rpm.c:964
+#: rpm.c:966
 msgid "--oldpackage may only be used during upgrades"
 msgstr ""
 
-#: rpm.c:967 rpmqv.c:1120
+#: rpm.c:969 rpmqv.c:1120
 msgid "--nopgp may only be used during signature checking"
 msgstr ""
 
-#: rpm.c:970 rpmqv.c:1123
+#: rpm.c:972 rpmqv.c:1123
 msgid "--nogpg may only be used during signature checking"
 msgstr ""
 
-#: rpm.c:973 rpmqv.c:1128
+#: rpm.c:975 rpmqv.c:1128
 msgid ""
 "--nomd5 may only be used during signature checking and package verification"
 msgstr ""
 
-#: rpm.c:984 rpmqv.c:1144
+#: rpm.c:986 rpmqv.c:1144
 msgid "no files to sign\n"
 msgstr ""
 
-#: rpm.c:989 rpmqv.c:1149
+#: rpm.c:991 rpmqv.c:1149
 #, c-format
 msgid "cannot access file %s\n"
 msgstr ""
 
-#: rpm.c:1004 rpmqv.c:1165
+#: rpm.c:1006 rpmqv.c:1165
 msgid "pgp not found: "
 msgstr ""
 
-#: rpm.c:1008 rpmqv.c:1169
+#: rpm.c:1010 rpmqv.c:1169
 msgid "Enter pass phrase: "
 msgstr ""
 
-#: rpm.c:1010 rpmqv.c:1171
+#: rpm.c:1012 rpmqv.c:1171
 msgid "Pass phrase check failed\n"
 msgstr ""
 
-#: rpm.c:1013 rpmqv.c:1174
+#: rpm.c:1015 rpmqv.c:1174
 msgid "Pass phrase is good.\n"
 msgstr ""
 
-#: rpm.c:1018 rpmqv.c:1179
+#: rpm.c:1020 rpmqv.c:1179
 msgid "Invalid %%_signature spec in macro file.\n"
 msgstr ""
 
-#: rpm.c:1024 rpmqv.c:1185
+#: rpm.c:1026 rpmqv.c:1185
 msgid "--sign may only be used during package building"
 msgstr ""
 
-#: rpm.c:1039 rpmqv.c:1201
+#: rpm.c:1041 rpmqv.c:1201
 msgid "exec failed\n"
 msgstr ""
 
-#: rpm.c:1058 rpmqv.c:1445
+#: rpm.c:1060 rpmqv.c:1445
 msgid "unexpected arguments to --querytags "
 msgstr ""
 
-#: rpm.c:1069 rpmqv.c:1467
+#: rpm.c:1071 rpmqv.c:1467
 msgid "no packages given for signature check"
 msgstr ""
 
-#: rpm.c:1080 rpmqv.c:1478
+#: rpm.c:1082 rpmqv.c:1478
 msgid "no packages given for signing"
 msgstr ""
 
-#: rpm.c:1096 rpmqv.c:1341
+#: rpm.c:1098 rpmqv.c:1341
 msgid "no packages given for uninstall"
 msgstr ""
 
-#: rpm.c:1160 rpmqv.c:1370
+#: rpm.c:1162 rpmqv.c:1370
 msgid "no packages given for install"
 msgstr ""
 
-#: rpm.c:1184 rpmqv.c:1411
+#: rpm.c:1186 rpmqv.c:1411
 msgid "extra arguments given for query of all packages"
 msgstr ""
 
-#: rpm.c:1189 rpmqv.c:1416
+#: rpm.c:1191 rpmqv.c:1416
 msgid "no arguments given for query"
 msgstr ""
 
-#: rpm.c:1206 rpmqv.c:1433
+#: rpm.c:1208 rpmqv.c:1433
 msgid "extra arguments given for verify of all packages"
 msgstr ""
 
-#: rpm.c:1210 rpmqv.c:1437
+#: rpm.c:1212 rpmqv.c:1437
 msgid "no arguments given for verify"
 msgstr ""
 
@@ -2185,50 +2185,85 @@ msgstr ""
 msgid "line %d: Bad %s number: %s\n"
 msgstr ""
 
-#: lib/cpio.c:835
+#: lib/cpio.c:353
 #, c-format
-msgid "%8x %s -> %s path %s\n"
+msgid "   file: %s%s action: %s\n"
 msgstr ""
 
-#: lib/cpio.c:1222
+#: lib/cpio.c:389
 #, c-format
-msgid "getNextHeader: %s\n"
+msgid "%s: %s%s created as %s\n"
 msgstr ""
 
-#: lib/cpio.c:1626
+#: lib/cpio.c:415
+#, c-format
+msgid "%s: cannot remove %s - directory not empty\n"
+msgstr ""
+
+#: lib/cpio.c:420
+#, c-format
+msgid "%s rmdir of %s failed: %s\n"
+msgstr ""
+
+#: lib/cpio.c:431
+#, c-format
+msgid "%s removal of %s failed: %s\n"
+msgstr ""
+
+#: lib/cpio.c:446
+#, c-format
+msgid "%s: %s saved as %s\n"
+msgstr ""
+
+#: lib/cpio.c:452
+#, c-format
+msgid "%s rename of %s to %s failed: %s\n"
+msgstr ""
+
+#: lib/cpio.c:860
+#, c-format
+msgid "%8x %s:%s\t%06o%s\n"
+msgstr ""
+
+#: lib/cpio.c:865
+#, c-format
+msgid "%8x %s\t%06o %s\n"
+msgstr ""
+
+#: lib/cpio.c:1811
 #, c-format
 msgid "(error 0x%x)"
 msgstr ""
 
-#: lib/cpio.c:1629
+#: lib/cpio.c:1814
 msgid "Bad magic"
 msgstr ""
 
-#: lib/cpio.c:1630
+#: lib/cpio.c:1815
 msgid "Bad/unreadable  header"
 msgstr ""
 
-#: lib/cpio.c:1651
+#: lib/cpio.c:1836
 msgid "Header size too big"
 msgstr ""
 
-#: lib/cpio.c:1652
+#: lib/cpio.c:1837
 msgid "Unknown file type"
 msgstr ""
 
-#: lib/cpio.c:1653
+#: lib/cpio.c:1838
 msgid "Missing hard link"
 msgstr ""
 
-#: lib/cpio.c:1654
+#: lib/cpio.c:1839
 msgid "MD5 sum mismatch"
 msgstr ""
 
-#: lib/cpio.c:1655
+#: lib/cpio.c:1840
 msgid "Internal error"
 msgstr ""
 
-#: lib/cpio.c:1664
+#: lib/cpio.c:1849
 msgid " failed - "
 msgstr ""
 
@@ -2616,39 +2651,39 @@ msgstr ""
 msgid " on file "
 msgstr ""
 
-#: lib/install.c:489
+#: lib/install.c:496
 #, c-format
 msgid "cannot create %s %s\n"
 msgstr ""
 
-#: lib/install.c:495
+#: lib/install.c:502
 #, c-format
 msgid "cannot write to %s\n"
 msgstr ""
 
-#: lib/install.c:516
+#: lib/install.c:523
 msgid "installing a source package\n"
 msgstr ""
 
-#: lib/install.c:568
+#: lib/install.c:575
 msgid "source package contains no .spec file\n"
 msgstr ""
 
-#: lib/install.c:648
+#: lib/install.c:655
 msgid "source package expected, binary found\n"
 msgstr ""
 
-#: lib/install.c:711 lib/uninstall.c:24
+#: lib/install.c:718 lib/uninstall.c:24
 #, c-format
 msgid "%s: %s-%s-%s has %d files, test = %d\n"
 msgstr ""
 
-#: lib/install.c:778 lib/install.c:866 lib/uninstall.c:62 lib/uninstall.c:83
+#: lib/install.c:785 lib/install.c:873 lib/uninstall.c:62 lib/uninstall.c:83
 #, c-format
 msgid "%s: running %s script(s) (if any)\n"
 msgstr ""
 
-#: lib/install.c:785
+#: lib/install.c:792
 msgid "skipping %s-%s-%s install, %%pre scriptlet failed rc %d\n"
 msgstr ""
 
@@ -3053,41 +3088,6 @@ msgstr ""
 msgid "package %s is not installed\n"
 msgstr ""
 
-#: lib/rollback.c:387
-#, c-format
-msgid "   file: %s%s action: %s\n"
-msgstr ""
-
-#: lib/rollback.c:426
-#, c-format
-msgid "%s: %s%s created as %s\n"
-msgstr ""
-
-#: lib/rollback.c:453
-#, c-format
-msgid "%s: cannot remove %s - directory not empty\n"
-msgstr ""
-
-#: lib/rollback.c:458
-#, c-format
-msgid "%s rmdir of %s failed: %s\n"
-msgstr ""
-
-#: lib/rollback.c:470
-#, c-format
-msgid "%s removal of %s failed: %s\n"
-msgstr ""
-
-#: lib/rollback.c:488
-#, c-format
-msgid "%s: %s saved as %s\n"
-msgstr ""
-
-#: lib/rollback.c:494
-#, c-format
-msgid "%s rename of %s to %s failed: %s\n"
-msgstr ""
-
 #: lib/rpmchecksig.c:38
 #, c-format
 msgid "%s: open failed: %s\n"
diff --git a/rpm.c b/rpm.c
index afc0597..c8dc031 100755 (executable)
--- a/rpm.c
+++ b/rpm.c
@@ -55,6 +55,7 @@ static int badReloc;
 static int dirStash;
 static int excldocs;
 static int force;
+extern int _fsm_debug;
 extern int _ftp_debug;
 static int showHash;
 static int help;
@@ -122,6 +123,7 @@ static struct poptOption optionsTable[] = {
  { "excludepath", '\0', POPT_ARG_STRING, 0, GETOPT_EXCLUDEPATH,        NULL, NULL},
  { "force", '\0', 0, &force, 0,                        NULL, NULL},
  { "freshen", 'F', 0, 0, 'F',                  NULL, NULL},
+ { "fsmdebug", '\0', POPT_ARG_VAL, &_fsm_debug, -1,            NULL, NULL},
  { "ftpdebug", '\0', POPT_ARG_VAL, &_ftp_debug, -1,            NULL, NULL},
  { "hash", 'h', 0, &showHash, 0,               NULL, NULL},
  { "help", '\0', 0, &help, 0,                  NULL, NULL},