diff options
Diffstat (limited to 'lib/fsm.c')
-rw-r--r-- | lib/fsm.c | 1751 |
1 files changed, 454 insertions, 1297 deletions
@@ -13,129 +13,23 @@ #include <rpm/rpmte.h> #include <rpm/rpmts.h> -#include <rpm/rpmsq.h> #include <rpm/rpmlog.h> +#include <rpm/rpmmacro.h> #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ -#include "lib/cpio.h" #include "lib/fsm.h" -#define fsmUNSAFE fsmStage -#include "lib/rpmfi_internal.h" /* XXX fi->apath, ... */ #include "lib/rpmte_internal.h" /* XXX rpmfs */ -#include "lib/rpmts_internal.h" /* rpmtsSELabelFoo() only */ -#include "lib/rpmplugins.h" /* rpm plugins hooks */ +#include "lib/rpmplugins.h" /* rpm plugins hooks */ #include "lib/rpmug.h" -#include "lib/cpio.h" #include "debug.h" #define _FSM_DEBUG 0 int _fsm_debug = _FSM_DEBUG; -extern int _fsm_debug; - -/** \ingroup payload - */ -enum cpioMapFlags_e { - CPIO_MAP_PATH = (1 << 0), - CPIO_MAP_MODE = (1 << 1), - CPIO_MAP_UID = (1 << 2), - CPIO_MAP_GID = (1 << 3), - CPIO_FOLLOW_SYMLINKS= (1 << 4), /*!< only for building. */ - CPIO_MAP_ABSOLUTE = (1 << 5), - CPIO_MAP_ADDDOT = (1 << 6), - CPIO_MAP_TYPE = (1 << 8), /*!< only for building. */ - CPIO_SBIT_CHECK = (1 << 9) -}; -typedef rpmFlags cpioMapFlags; - -typedef struct fsmIterator_s * FSMI_t; -typedef struct fsm_s * FSM_t; - -typedef struct hardLink_s * hardLink_t; - -typedef enum fileStage_e { - FSM_PKGINSTALL, - FSM_PKGERASE, - FSM_PKGBUILD, -} fileStage; - /* XXX Failure to remove is not (yet) cause for failure. */ static int strict_erasures = 0; -/** \ingroup payload - * Keeps track of the set of all hard links to a file in an archive. - */ -struct hardLink_s { - hardLink_t next; - const char ** nsuffix; - int * filex; - struct stat sb; - nlink_t nlink; - nlink_t linksLeft; - int linkIndex; - int createdPath; -}; - -/** \ingroup payload - * Iterator across package file info, forward on install, backward on erase. - */ -struct fsmIterator_s { - rpmfs fs; /*!< file state info. */ - rpmfi fi; /*!< transaction element file info. */ - int reverse; /*!< reversed traversal? */ - int isave; /*!< last returned iterator index. */ - int i; /*!< iterator index. */ -}; - -/** \ingroup payload - * File name and stat information. - */ -struct fsm_s { - char * path; /*!< Current file name. */ - char * buf; /*!< read: Buffer. */ - size_t bufsize; /*!< read: Buffer allocated size. */ - FSMI_t iter; /*!< File iterator. */ - int ix; /*!< Current file iterator index. */ - hardLink_t links; /*!< Pending hard linked file(s). */ - char ** failedFile; /*!< First file name that failed. */ - const char * osuffix; /*!< Old, preserved, file suffix. */ - const char * nsuffix; /*!< New, created, file suffix. */ - char * suffix; /*!< Current file suffix. */ - int postpone; /*!< Skip remaining stages? */ - int diskchecked; /*!< Has stat(2) been performed? */ - int exists; /*!< Does current file exist on disk? */ - cpioMapFlags mapFlags; /*!< Bit(s) to control mapping. */ - const char * dirName; /*!< File directory name. */ - const char * baseName; /*!< File base name. */ - struct selabel_handle *sehandle; /*!< SELinux label handle (if any). */ - rpmPlugins plugins; /*!< Rpm plugins handle */ - - unsigned fflags; /*!< File flags. */ - rpmFileAction action; /*!< File disposition. */ - fileStage goal; /*!< Package state machine goal. */ - struct stat sb; /*!< Current file stat(2) info. */ - struct stat osb; /*!< Original file stat(2) info. */ -}; - - -/** - * Retrieve transaction element file info from file state machine iterator. - * @param fsm file state machine - * @return transaction element file info - */ -static rpmfi fsmGetFi(const FSM_t fsm) -{ - const FSMI_t iter = fsm->iter; - return (iter ? iter->fi : NULL); -} - -static rpmfs fsmGetFs(const FSM_t fsm) -{ - const FSMI_t iter = fsm->iter; - return (iter ? iter->fs : NULL); -} - #define SUFFIX_RPMORIG ".rpmorig" #define SUFFIX_RPMSAVE ".rpmsave" #define SUFFIX_RPMNEW ".rpmnew" @@ -152,126 +46,20 @@ static const char * fileActionString(rpmFileAction a); /** \ingroup payload * Build path to file from file info, optionally ornamented with suffix. - * @param fsm file state machine data - * @param isDir directory or regular path? + * @param fi file info iterator * @param suffix suffix to use (NULL disables) * @retval path to file (malloced) */ -static char * fsmFsPath(const FSM_t fsm, int isDir, - const char * suffix) -{ - return rstrscat(NULL, - fsm->dirName, fsm->baseName, - (!isDir && suffix) ? suffix : "", - NULL); -} - -/** \ingroup payload - * Destroy file info iterator. - * @param p file info iterator - * @retval NULL always - */ -static FSMI_t mapFreeIterator(FSMI_t iter) +static char * fsmFsPath(rpmfi fi, const char * suffix) { - if (iter) { - iter->fs = NULL; /* rpmfs is not refcounted */ - iter->fi = rpmfiFree(iter->fi); - free(iter); - } - return NULL; -} - -/** \ingroup payload - * Create file info iterator. - * @param fi transaction element file info - * @return file info iterator - */ -static FSMI_t -mapInitIterator(rpmfs fs, rpmfi fi, int reverse) -{ - FSMI_t iter = NULL; - - iter = xcalloc(1, sizeof(*iter)); - iter->fs = fs; /* rpmfs is not refcounted */ - iter->fi = rpmfiLink(fi); - iter->reverse = reverse; - iter->i = (iter->reverse ? (rpmfiFC(fi) - 1) : 0); - iter->isave = iter->i; - return iter; -} - -/** \ingroup payload - * Return next index into file info. - * @param a file info iterator - * @return next index, -1 on termination - */ -static int mapNextIterator(FSMI_t iter) -{ - int i = -1; - - if (iter) { - const rpmfi fi = iter->fi; - if (iter->reverse) { - if (iter->i >= 0) i = iter->i--; - } else { - if (iter->i < rpmfiFC(fi)) i = iter->i++; - } - iter->isave = i; - } - return i; -} - -/** \ingroup payload - */ -static int cpioStrCmp(const void * a, const void * b) -{ - const char * afn = *(const char **)a; - const char * bfn = *(const char **)b; - - /* Match rpm-4.0 payloads with ./ prefixes. */ - if (afn[0] == '.' && afn[1] == '/') afn += 2; - if (bfn[0] == '.' && bfn[1] == '/') bfn += 2; - - /* If either path is absolute, make it relative. */ - if (afn[0] == '/') afn += 1; - if (bfn[0] == '/') bfn += 1; - - return strcmp(afn, bfn); -} - -/** \ingroup payload - * Locate archive path in file info. - * @param iter file info iterator - * @param fsmPath archive path - * @return index into file info, -1 if archive path was not found - */ -static int mapFind(FSMI_t iter, const char * fsmPath) -{ - int ix = -1; - - if (iter) { - const rpmfi fi = iter->fi; - int fc = rpmfiFC(fi); - if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) { - char ** p = NULL; - - if (fi->apath != NULL) - p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath), - cpioStrCmp); - if (p) { - iter->i = p - fi->apath; - ix = mapNextIterator(iter); - } - } - } - return ix; + return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL); } /** \ingroup payload * Directory name iterator. */ typedef struct dnli_s { - rpmfi fi; + rpmfiles fi; char * active; int reverse; int isave; @@ -280,7 +68,7 @@ typedef struct dnli_s { /** \ingroup payload * Destroy directory name iterator. - * @param a directory name iterator + * @param dnli directory name iterator * @retval NULL always */ static DNLI_t dnlFreeIterator(DNLI_t dnli) @@ -299,7 +87,7 @@ static DNLI_t dnlFreeIterator(DNLI_t dnli) * @param reverse traverse directory names in reverse order? * @return directory name iterator */ -static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse) +static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse) { DNLI_t dnli; int i, j; @@ -307,7 +95,7 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse) if (fi == NULL) return NULL; - dc = rpmfiDC(fi); + dc = rpmfilesDC(fi); dnli = xcalloc(1, sizeof(*dnli)); dnli->fi = fi; dnli->reverse = reverse; @@ -315,24 +103,24 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse) if (dc) { dnli->active = xcalloc(dc, sizeof(*dnli->active)); - int fc = rpmfiFC(fi); + int fc = rpmfilesFC(fi); /* Identify parent directories not skipped. */ for (i = 0; i < fc; i++) if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) - dnli->active[rpmfiDIIndex(fi, i)] = 1; + dnli->active[rpmfilesDI(fi, i)] = 1; /* Exclude parent directories that are explicitly included. */ for (i = 0; i < fc; i++) { int dil; size_t dnlen, bnlen; - if (!S_ISDIR(rpmfiFModeIndex(fi, i))) + if (!S_ISDIR(rpmfilesFMode(fi, i))) continue; - dil = rpmfiDIIndex(fi, i); - dnlen = strlen(rpmfiDNIndex(fi, dil)); - bnlen = strlen(rpmfiBNIndex(fi, i)); + dil = rpmfilesDI(fi, i); + dnlen = strlen(rpmfilesDN(fi, dil)); + bnlen = strlen(rpmfilesBN(fi, i)); for (j = 0; j < dc; j++) { const char * dnl; @@ -340,13 +128,13 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse) if (!dnli->active[j] || j == dil) continue; - dnl = rpmfiDNIndex(fi, j); + dnl = rpmfilesDN(fi, j); jlen = strlen(dnl); if (jlen != (dnlen+bnlen+1)) continue; - if (!rstreqn(dnl, rpmfiDNIndex(fi, dil), dnlen)) + if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen)) continue; - if (!rstreqn(dnl+dnlen, rpmfiBNIndex(fi, i), bnlen)) + if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen)) continue; if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') continue; @@ -366,7 +154,7 @@ static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse) rpmlog(RPMLOG_DEBUG, "========== Directories not explicitly included in package:\n"); } - rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfiDNIndex(fi, i)); + rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i)); } if (j) rpmlog(RPMLOG_DEBUG, "==========\n"); @@ -386,8 +174,8 @@ const char * dnlNextIterator(DNLI_t dnli) const char * dn = NULL; if (dnli) { - rpmfi fi = dnli->fi; - int dc = rpmfiDC(fi); + rpmfiles fi = dnli->fi; + int dc = rpmfilesDC(fi); int i = -1; if (dnli->active) @@ -396,7 +184,7 @@ const char * dnlNextIterator(DNLI_t dnli) } while (i >= 0 && i < dc && !dnli->active[i]); if (i >= 0 && i < dc) - dn = rpmfiDNIndex(fi, i); + dn = rpmfilesDN(fi, i); else i = -1; dnli->isave = i; @@ -404,251 +192,6 @@ const char * dnlNextIterator(DNLI_t dnli) return dn; } -/** - * Map next file path and action. - * @param fsm file state machine - * @param i file index - */ -static int fsmMapPath(FSM_t fsm, int i) -{ - rpmfi fi = fsmGetFi(fsm); /* XXX const except for fstates */ - int rc = 0; - - fsm->osuffix = NULL; - fsm->nsuffix = NULL; - fsm->action = FA_UNKNOWN; - - if (fi && i >= 0 && i < rpmfiFC(fi)) { - rpmfs fs = fsmGetFs(fsm); - /* XXX these should use rpmfiFFlags() etc */ - fsm->action = rpmfsGetAction(fs, i); - fsm->fflags = rpmfiFFlagsIndex(fi, i); - - /* src rpms have simple base name in payload. */ - fsm->dirName = rpmfiDNIndex(fi, rpmfiDIIndex(fi, i)); - fsm->baseName = rpmfiBNIndex(fi, i); - - /* Never create backup for %ghost files. */ - if (fsm->goal != FSM_PKGBUILD && !(fsm->fflags & RPMFILE_GHOST)) { - switch (fsm->action) { - case FA_ALTNAME: - fsm->nsuffix = SUFFIX_RPMNEW; - break; - case FA_SAVE: - fsm->osuffix = SUFFIX_RPMSAVE; - break; - case FA_BACKUP: - fsm->osuffix = (fsm->goal == FSM_PKGINSTALL) ? - SUFFIX_RPMORIG : SUFFIX_RPMSAVE; - break; - default: - break; - } - } - - if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) { - fsm->path = _free(fsm->path); - fsm->path = fsmFsPath(fsm, S_ISDIR(fsm->sb.st_mode), - (fsm->suffix ? fsm->suffix : fsm->nsuffix)); - } - } - return rc; -} - -/** \ingroup payload - * Save hard link in chain. - * @param fsm file state machine data - * @retval linkSet hard link set when complete - * @return Is chain only partially filled? - */ -static int saveHardLink(FSM_t fsm, hardLink_t * linkSet) -{ - struct stat * st = &fsm->sb; - int rc = 0; - int ix = -1; - int j; - hardLink_t *tailp, li; - - /* Find hard link set. */ - for (tailp = &fsm->links; (li = *tailp) != NULL; tailp = &li->next) { - if (li->sb.st_ino == st->st_ino && li->sb.st_dev == st->st_dev) - break; - } - - /* New hard link encountered, add new link to set. */ - if (li == NULL) { - li = xcalloc(1, sizeof(*li)); - li->next = NULL; - li->sb = *st; /* structure assignment */ - li->nlink = st->st_nlink; - li->linkIndex = fsm->ix; - li->createdPath = -1; - - li->filex = xcalloc(st->st_nlink, sizeof(li->filex[0])); - memset(li->filex, -1, (st->st_nlink * sizeof(li->filex[0]))); - li->nsuffix = xcalloc(st->st_nlink, sizeof(*li->nsuffix)); - - if (fsm->goal == FSM_PKGBUILD) - li->linksLeft = st->st_nlink; - if (fsm->goal == FSM_PKGINSTALL) - li->linksLeft = 0; - - *tailp = li; /* append to tail of linked list */ - } - - if (fsm->goal == FSM_PKGBUILD) --li->linksLeft; - li->filex[li->linksLeft] = fsm->ix; - li->nsuffix[li->linksLeft] = fsm->nsuffix; - if (fsm->goal == FSM_PKGINSTALL) li->linksLeft++; - - if (fsm->goal == FSM_PKGBUILD) - return (li->linksLeft > 0); - - if (fsm->goal != FSM_PKGINSTALL) - return 0; - - if (!(st->st_size || li->linksLeft == st->st_nlink)) - return 1; - - /* Here come the bits, time to choose a non-skipped file name. */ - { rpmfs fs = fsmGetFs(fsm); - - for (j = li->linksLeft - 1; j >= 0; j--) { - ix = li->filex[j]; - if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix))) - continue; - break; - } - } - - /* Are all links skipped or not encountered yet? */ - if (ix < 0 || j < 0) - return 1; /* XXX W2DO? */ - - /* Save the non-skipped file name and map index. */ - li->linkIndex = j; - if (linkSet) - *linkSet = li; - fsm->path = _free(fsm->path); - fsm->ix = ix; - rc = fsmMapPath(fsm, fsm->ix); - return rc; -} - -/** \ingroup payload - * Destroy set of hard links. - * @param li set of hard links - * @return NULL always - */ -static hardLink_t freeHardLink(hardLink_t li) -{ - if (li) { - li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */ - li->filex = _free(li->filex); - _free(li); - } - return NULL; -} - -/* Check for hard links missing from payload */ -static int checkHardLinks(FSM_t fsm) -{ - int rc = 0; - rpmfs fs = fsmGetFs(fsm); - - for (hardLink_t li = fsm->links; li != NULL; li = li->next) { - if (li->linksLeft) { - for (nlink_t i = 0 ; i < li->linksLeft; i++) { - int ix = li->filex[i]; - if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix))) - continue; - rc = CPIOERR_MISSING_HARDLINK; - if (fsm->failedFile && *fsm->failedFile == NULL) { - if (!fsmMapPath(fsm, ix)) { - /* Out-of-sync hardlinks handled as sub-state */ - *fsm->failedFile = fsm->path; - fsm->path = NULL; - } - } - break; - } - } - } - return rc; -} - -static FSM_t fsmNew(fileStage goal, rpmfs fs, rpmfi fi, char ** failedFile) -{ - FSM_t fsm = xcalloc(1, sizeof(*fsm)); - - fsm->ix = -1; - fsm->goal = goal; - fsm->iter = mapInitIterator(fs, fi, (goal == FSM_PKGERASE)); - - /* common flags for all modes */ - fsm->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID; - - if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) { - fsm->bufsize = 8 * BUFSIZ; - fsm->buf = xmalloc(fsm->bufsize); - } - - fsm->failedFile = failedFile; - if (fsm->failedFile) - *fsm->failedFile = NULL; - - return fsm; -} - -static FSM_t fsmFree(FSM_t fsm) -{ - hardLink_t li; - fsm->buf = _free(fsm->buf); - fsm->bufsize = 0; - - fsm->iter = mapFreeIterator(fsm->iter); - fsm->failedFile = NULL; - - fsm->path = _free(fsm->path); - fsm->suffix = _free(fsm->suffix); - - while ((li = fsm->links) != NULL) { - fsm->links = li->next; - li->next = NULL; - freeHardLink(li); - } - free(fsm); - return NULL; -} - -/* Find and set file security context */ -static int fsmSetSELabel(struct selabel_handle *sehandle, - const char *path, mode_t mode) -{ - int rc = 0; -#if WITH_SELINUX - if (sehandle) { - security_context_t scon = NULL; - - if (selabel_lookup_raw(sehandle, &scon, path, mode) == 0) { - rc = lsetfilecon(path, scon); - - if (_fsm_debug) { - rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", - __func__, path, scon, - (rc < 0 ? strerror(errno) : "")); - } - - if (rc < 0 && errno == EOPNOTSUPP) - rc = 0; - } - - freecon(scon); - } -#endif - return rc ? CPIOERR_LSETFCON_FAILED : 0; -} - static int fsmSetFCaps(const char *path, const char *captxt) { int rc = 0; @@ -656,7 +199,7 @@ static int fsmSetFCaps(const char *path, const char *captxt) if (captxt && *captxt != '\0') { cap_t fcaps = cap_from_text(captxt); if (fcaps == NULL || cap_set_file(path, fcaps) != 0) { - rc = CPIOERR_SETCAP_FAILED; + rc = RPMERR_SETCAP_FAILED; } cap_free(fcaps); } @@ -664,132 +207,102 @@ static int fsmSetFCaps(const char *path, const char *captxt) return rc; } -/** - * Map file stat(2) info. - * @param fsm file state machine - */ -static int fsmMapAttrs(FSM_t fsm) +static void wfd_close(FD_t *wfdp) { - struct stat * st = &fsm->sb; - rpmfi fi = fsmGetFi(fsm); - int i = fsm->ix; - - /* this check is pretty moot, rpmfi accessors check array bounds etc */ - if (fi && i >= 0 && i < rpmfiFC(fi)) { - ino_t finalInode = rpmfiFInodeIndex(fi, i); - mode_t finalMode = rpmfiFModeIndex(fi, i); - dev_t finalRdev = rpmfiFRdevIndex(fi, i); - time_t finalMtime = rpmfiFMtimeIndex(fi, i); - const char *user = rpmfiFUserIndex(fi, i); - const char *group = rpmfiFGroupIndex(fi, i); - uid_t uid = 0; - gid_t gid = 0; - - if (user && rpmugUid(user, &uid)) { - if (fsm->goal == FSM_PKGINSTALL) - rpmlog(RPMLOG_WARNING, - _("user %s does not exist - using root\n"), user); - finalMode &= ~S_ISUID; /* turn off suid bit */ + if (wfdp && *wfdp) { + int myerrno = errno; + static int oneshot = 0; + static int flush_io = 0; + if (!oneshot) { + flush_io = rpmExpandNumeric("%{?_flush_io}"); + oneshot = 1; } - - if (group && rpmugGid(group, &gid)) { - if (fsm->goal == FSM_PKGINSTALL) - rpmlog(RPMLOG_WARNING, - _("group %s does not exist - using root\n"), group); - finalMode &= ~S_ISGID; /* turn off sgid bit */ + if (flush_io) { + int fdno = Fileno(*wfdp); + fsync(fdno); } + Fclose(*wfdp); + *wfdp = NULL; + errno = myerrno; + } +} - if (fsm->mapFlags & CPIO_MAP_MODE) - st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT); - if (fsm->mapFlags & CPIO_MAP_TYPE) { - st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT); - if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - && st->st_nlink == 0) - st->st_nlink = 1; - st->st_ino = finalInode; - st->st_rdev = finalRdev; - st->st_mtime = finalMtime; - } - if (fsm->mapFlags & CPIO_MAP_UID) - st->st_uid = uid; - if (fsm->mapFlags & CPIO_MAP_GID) - st->st_gid = gid; +static int wfd_open(FD_t *wfdp, const char *dest) +{ + int rc = 0; + /* Create the file with 0200 permissions (write by owner). */ + { + mode_t old_umask = umask(0577); + *wfdp = Fopen(dest, "wx.ufdio"); + umask(old_umask); } + if (Ferror(*wfdp)) { + rc = RPMERR_OPEN_FAILED; + goto exit; + } + return 0; + +exit: + wfd_close(wfdp); + return rc; } /** \ingroup payload * Create file from payload stream. - * @param fsm file state machine data - * @param archive payload archive * @return 0 on success */ -static int expandRegular(FSM_t fsm, rpmpsm psm, rpmcpio_t archive, int nodigest) +static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest) { FD_t wfd = NULL; - const struct stat * st = &fsm->sb; - rpm_loff_t left = st->st_size; - const unsigned char * fidigest = NULL; - pgpHashAlgo digestalgo = 0; - int rc = 0; - - wfd = Fopen(fsm->path, "w.ufdio"); - if (Ferror(wfd)) { - rc = CPIOERR_OPEN_FAILED; - goto exit; - } - - if (!nodigest) { - rpmfi fi = fsmGetFi(fsm); - digestalgo = rpmfiDigestAlgo(fi); - fidigest = rpmfiFDigestIndex(fi, fsm->ix, NULL, NULL); - } - - if (st->st_size > 0 && fidigest) - fdInitDigest(wfd, digestalgo, 0); - - while (left) { - size_t len; - len = (left > fsm->bufsize ? fsm->bufsize : left); - if (rpmcpioRead(archive, fsm->buf, len) != len) { - rc = CPIOERR_READ_FAILED; - goto exit; - } - if ((Fwrite(fsm->buf, sizeof(*fsm->buf), len, wfd) != len) || Ferror(wfd)) { - rc = CPIOERR_WRITE_FAILED; - goto exit; - } + int rc; - left -= len; + rc = wfd_open(&wfd, dest); + if (rc != 0) + goto exit; - /* don't call this with fileSize == fileComplete */ - if (!rc && left) - rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(archive)); - } - - if (st->st_size > 0 && fidigest) { - void * digest = NULL; + rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm); + wfd_close(&wfd); +exit: + return rc; +} - (void) Fflush(wfd); - fdFiniDigest(wfd, digestalgo, &digest, NULL, 0); +static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, + rpmpsm psm, int nodigest, int *setmeta, + int * firsthardlink, FD_t *firstlinkfile) +{ + int rc = 0; + int numHardlinks = rpmfiFNlink(fi); - if (digest != NULL && fidigest != NULL) { - size_t diglen = rpmDigestLength(digestalgo); - if (memcmp(digest, fidigest, diglen)) { - rc = CPIOERR_DIGEST_MISMATCH; - } + if (numHardlinks > 1) { + /* Create first hardlinked file empty */ + if (*firsthardlink < 0) { + *firsthardlink = rpmfiFX(fi); + rc = wfd_open(firstlinkfile, dest); } else { - rc = CPIOERR_DIGEST_MISMATCH; + /* Create hard links for others */ + char *fn = rpmfilesFN(files, *firsthardlink); + rc = link(fn, dest); + if (rc < 0) { + rc = RPMERR_LINK_FAILED; + } + free(fn); } - free(digest); } - -exit: - if (wfd) { - int myerrno = errno; - Fclose(wfd); - errno = myerrno; + /* Write normal files or fill the last hardlinked (already + existing) file with content */ + if (numHardlinks<=1) { + if (!rc) + rc = expandRegular(fi, dest, psm, nodigest); + } else if (rpmfiArchiveHasContent(fi)) { + if (!rc) + rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); + wfd_close(firstlinkfile); + *firsthardlink = -1; + } else { + *setmeta = 0; } + return rc; } @@ -797,7 +310,7 @@ static int fsmReadLink(const char *path, char *buf, size_t bufsize, size_t *linklen) { ssize_t llen = readlink(path, buf, bufsize - 1); - int rc = CPIOERR_READLINK_FAILED; + int rc = RPMERR_READLINK_FAILED; if (_fsm_debug) { rpmlog(RPMLOG_DEBUG, " %8s (%s, buf, %d) %s\n", @@ -813,168 +326,6 @@ static int fsmReadLink(const char *path, return rc; } -/** \ingroup payload - * Write next item to payload stream. - * @param fsm file state machine data - * @param writeData should data be written? - * @param archive payload archive - * @param ix file index - * @return 0 on success - */ -static int writeFile(FSM_t fsm, int writeData, rpmcpio_t archive, int ix) -{ - FD_t rfd = NULL; - char * path = fsm->path; - struct stat * st = &fsm->sb; - struct stat * ost = &fsm->osb; - char * symbuf = NULL; - rpm_loff_t left; - int rc = 0; - - st->st_size = (writeData ? ost->st_size : 0); - - if (S_ISDIR(st->st_mode)) { - st->st_size = 0; - } else if (S_ISLNK(st->st_mode)) { - /* - * While linux puts the size of a symlink in the st_size field, - * I don't think that's a specified standard. - */ - size_t linklen; - rc = fsmReadLink(fsm->path, fsm->buf, fsm->bufsize, &linklen); - if (rc) goto exit; - st->st_size = linklen; - rstrcat(&symbuf, fsm->buf); /* XXX save readlink return. */ - } - - if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) { - fsm->path = rstrscat(NULL, (fsm->mapFlags & CPIO_MAP_ADDDOT) ? "." : "", - fsm->dirName, fsm->baseName, NULL); - } else if (fsm->mapFlags & CPIO_MAP_PATH) { - rpmfi fi = fsmGetFi(fsm); - fsm->path = xstrdup((fi->apath ? fi->apath[ix] : - rpmfiBNIndex(fi, ix))); - } - - rc = rpmcpioHeaderWrite(archive, fsm->path, st); - _free(fsm->path); - fsm->path = path; - - if (rc) goto exit; - - - if (writeData && S_ISREG(st->st_mode)) { - size_t len; - - rfd = Fopen(fsm->path, "r.ufdio"); - if (Ferror(rfd)) { - rc = CPIOERR_OPEN_FAILED; - goto exit; - } - - left = st->st_size; - - while (left) { - len = (left > fsm->bufsize ? fsm->bufsize : left); - if (Fread(fsm->buf, sizeof(*fsm->buf), len, rfd) != len || Ferror(rfd)) { - rc = CPIOERR_READ_FAILED; - goto exit; - } - - if (rpmcpioWrite(archive, fsm->buf, len) != len) { - rc = CPIOERR_WRITE_FAILED; - goto exit; - } - left -= len; - } - } else if (writeData && S_ISLNK(st->st_mode)) { - size_t len = strlen(symbuf); - if (rpmcpioWrite(archive, symbuf, len) != len) { - rc = CPIOERR_WRITE_FAILED; - goto exit; - } - } - -exit: - if (rfd) { - /* preserve any prior errno across close */ - int myerrno = errno; - Fclose(rfd); - errno = myerrno; - } - fsm->path = path; - free(symbuf); - return rc; -} - -/** \ingroup payload - * Write set of linked files to payload stream. - * @param fsm file state machine data - * @param archive payload archive - * @param li link to write - * @return 0 on success - */ -static int writeLinkedFile(FSM_t fsm, rpmcpio_t archive, hardLink_t li) -{ - char * path = fsm->path; - const char * nsuffix = fsm->nsuffix; - int ec = 0; - int rc; - int i; - - fsm->path = NULL; - fsm->nsuffix = NULL; - - for (i = li->nlink - 1; i >= 0; i--) { - - if (li->filex[i] < 0) continue; - - rc = fsmMapPath(fsm, li->filex[i]); - - /* Write data after last link. */ - rc = writeFile(fsm, (i == 0), archive, li->filex[i]); - if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { - ec = rc; - *fsm->failedFile = xstrdup(fsm->path); - } - - fsm->path = _free(fsm->path); - li->filex[i] = -1; - } - - fsm->nsuffix = nsuffix; - fsm->path = path; - return ec; -} - -static int writeLinks(FSM_t fsm, rpmcpio_t archive) -{ - int j, rc = 0; - nlink_t i, nlink; - - for (hardLink_t li = fsm->links; li; li = li->next) { - /* Re-calculate link count for archive header. */ - for (j = -1, nlink = 0, i = 0; i < li->nlink; i++) { - if (li->filex[i] < 0) - continue; - nlink++; - if (j == -1) j = i; - } - /* XXX force the contents out as well. */ - if (j != 0) { - li->filex[0] = li->filex[j]; - li->filex[j] = -1; - } - li->sb.st_nlink = nlink; - - fsm->sb = li->sb; /* structure assignment */ - fsm->osb = fsm->sb; /* structure assignment */ - - if (!rc) rc = writeLinkedFile(fsm, archive, li); - } - return rc; -} - static int fsmStat(const char *path, int dolstat, struct stat *sb) { int rc; @@ -988,105 +339,10 @@ static int fsmStat(const char *path, int dolstat, struct stat *sb) __func__, path, (rc < 0 ? strerror(errno) : "")); if (rc < 0) { - rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_LSTAT_FAILED); - /* WTH is this, and is it really needed, still? */ - memset(sb, 0, sizeof(*sb)); /* XXX s390x hackery */ - } - return rc; -} - -static int fsmVerify(FSM_t fsm); - -/** \ingroup payload - * Create pending hard links to existing file. - * @param fsm file state machine data - * @param li hard link - * @return 0 on success - */ -static int fsmMakeLinks(FSM_t fsm, hardLink_t li) -{ - char * path = fsm->path; - char * opath = NULL; - const char * nsuffix = fsm->nsuffix; - int ec = 0; - int rc; - int i; - - fsm->path = NULL; - fsm->nsuffix = NULL; - - rc = fsmMapPath(fsm, li->filex[li->createdPath]); - opath = fsm->path; - fsm->path = NULL; - for (i = 0; i < li->nlink; i++) { - if (li->filex[i] < 0) continue; - if (li->createdPath == i) continue; - - fsm->path = _free(fsm->path); - rc = fsmMapPath(fsm, li->filex[i]); - if (XFA_SKIPPING(fsm->action)) continue; - - rc = fsmVerify(fsm); - if (!rc) continue; - if (!(rc == CPIOERR_ENOENT)) break; - - /* XXX link(opath, fsm->path) */ - rc = link(opath, fsm->path); - if (_fsm_debug) - rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, - opath, fsm->path, (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_LINK_FAILED; - - if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { - ec = rc; - *fsm->failedFile = xstrdup(fsm->path); - } - - li->linksLeft--; + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED); + /* Ensure consistent struct content on failure */ + memset(sb, 0, sizeof(*sb)); } - fsm->path = _free(fsm->path); - free(opath); - - fsm->nsuffix = nsuffix; - fsm->path = path; - return ec; -} - -static int fsmCommit(FSM_t fsm, int ix); - -/** \ingroup payload - * Commit hard linked file set atomically. - * @param fsm file state machine data - * @return 0 on success - */ -static int fsmCommitLinks(FSM_t fsm) -{ - char * path = fsm->path; - const char * nsuffix = fsm->nsuffix; - struct stat * st = &fsm->sb; - int rc = 0; - nlink_t i; - hardLink_t li; - - fsm->path = NULL; - fsm->nsuffix = NULL; - - for (li = fsm->links; li != NULL; li = li->next) { - if (li->sb.st_ino == st->st_ino && li->sb.st_dev == st->st_dev) - break; - } - - for (i = 0; i < li->nlink; i++) { - if (li->filex[i] < 0) continue; - rc = fsmMapPath(fsm, li->filex[i]); - if (!XFA_SKIPPING(fsm->action)) - rc = fsmCommit(fsm, li->filex[i]); - fsm->path = _free(fsm->path); - li->filex[i] = -1; - } - - fsm->nsuffix = nsuffix; - fsm->path = path; return rc; } @@ -1098,9 +354,9 @@ static int fsmRmdir(const char *path) path, (rc < 0 ? strerror(errno) : "")); if (rc < 0) switch (errno) { - case ENOENT: rc = CPIOERR_ENOENT; break; - case ENOTEMPTY: rc = CPIOERR_ENOTEMPTY; break; - default: rc = CPIOERR_RMDIR_FAILED; break; + case ENOENT: rc = RPMERR_ENOENT; break; + case ENOTEMPTY: rc = RPMERR_ENOTEMPTY; break; + default: rc = RPMERR_RMDIR_FAILED; break; } return rc; } @@ -1112,7 +368,7 @@ static int fsmMkdir(const char *path, mode_t mode) rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, path, (unsigned)(mode & 07777), (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_MKDIR_FAILED; + if (rc < 0) rc = RPMERR_MKDIR_FAILED; return rc; } @@ -1127,7 +383,7 @@ static int fsmMkfifo(const char *path, mode_t mode) } if (rc < 0) - rc = CPIOERR_MKFIFO_FAILED; + rc = RPMERR_MKFIFO_FAILED; return rc; } @@ -1144,24 +400,24 @@ static int fsmMknod(const char *path, mode_t mode, dev_t dev) } if (rc < 0) - rc = CPIOERR_MKNOD_FAILED; + rc = RPMERR_MKNOD_FAILED; return rc; } /** * Create (if necessary) directories not explicitly included in package. - * @param dnli file state machine data - * @param sehandle selinux label handle (bah) + * @param files file data + * @param fs file states * @param plugins rpm plugins handle * @return 0 on success */ -static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle, rpmPlugins plugins) +static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins) { - DNLI_t dnli = dnlInitIterator(fi, fs, 0); + DNLI_t dnli = dnlInitIterator(files, fs, 0); struct stat sb; const char *dpath; - int dc = rpmfiDC(fi); + int dc = rpmfilesDC(files); int rc = 0; int i; int ldnlen = 0; @@ -1213,21 +469,35 @@ static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle, rpmPlu if (rc == 0 && S_ISDIR(sb.st_mode)) { /* Move pre-existing path marker forward. */ dnlx[dc] = (te - dn); - } else if (rc == CPIOERR_ENOENT) { + } else if (rc == RPMERR_ENOENT) { *te = '\0'; mode_t mode = S_IFDIR | (_dirPerms & 07777); - rc = fsmMkdir(dn, mode); + rpmFsmOp op = (FA_CREATE|FAF_UNOWNED); + + /* Run fsm file pre hook for all plugins */ + rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op); + + if (!rc) + rc = fsmMkdir(dn, mode); + if (!rc) { - rc = fsmSetSELabel(sehandle, dn, mode); + rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn, + mode, op); + } + /* Run fsm file post hook for all plugins */ + rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc); + + if (!rc) { rpmlog(RPMLOG_DEBUG, "%s directory created with perms %04o\n", dn, (unsigned)(mode & 07777)); } + if (!rc) { - /* Run file closed hook for all plugins */ - rc = rpmpluginsCallFsmCommit(plugins, dn, mode, DIR_TYPE_UNOWNED); - } + /* Run file closed hook for all plugins */ + rc = rpmpluginsCallFsmCommit(plugins, dn, mode, DIR_TYPE_UNOWNED); + } *te = '/'; } if (rc) @@ -1267,72 +537,14 @@ static void removeSBITS(const char *path) } } -/********************************************************************/ - -static void fsmReset(FSM_t fsm) -{ - fsm->path = _free(fsm->path); - fsm->postpone = 0; - fsm->diskchecked = fsm->exists = 0; - fsm->action = FA_UNKNOWN; - fsm->osuffix = NULL; - fsm->nsuffix = NULL; - memset(&(fsm->sb), 0, sizeof(fsm->sb)); - memset(&(fsm->osb), 0, sizeof(fsm->sb)); -} - -static int fsmInit(FSM_t fsm) +static void fsmDebug(const char *fpath, rpmFileAction action, + const struct stat *st) { - int rc = 0; - - /* On non-install, mode must be known so that dirs don't get suffix. */ - if (fsm->goal != FSM_PKGINSTALL) { - rpmfi fi = fsmGetFi(fsm); - fsm->sb.st_mode = rpmfiFModeIndex(fi, fsm->ix); - } - - /* Generate file path. */ - rc = fsmMapPath(fsm, fsm->ix); - if (rc) return rc; - - /* Perform lstat/stat for disk file. */ - if (fsm->path != NULL && - !(fsm->goal == FSM_PKGINSTALL && S_ISREG(fsm->sb.st_mode))) - { - int dolstat = !(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS); - rc = fsmStat(fsm->path, dolstat, &fsm->osb); - if (rc == CPIOERR_ENOENT) { - // errno = saveerrno; XXX temporary commented out - rc = 0; - fsm->exists = 0; - } else if (rc == 0) { - fsm->exists = 1; - } - } else { - /* Skip %ghost files on build. */ - fsm->exists = 0; - } - fsm->diskchecked = 1; - if (rc) return rc; - - /* On non-install, the disk file stat is what's remapped. */ - if (fsm->goal != FSM_PKGINSTALL) - fsm->sb = fsm->osb; /* structure assignment */ - - /* Remap file perms, owner, and group. */ - rc = fsmMapAttrs(fsm); - if (rc) return rc; - - fsm->postpone = XFA_SKIPPING(fsm->action); - rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n", - fileActionString(fsm->action), (int)fsm->sb.st_mode, - (int)fsm->sb.st_nlink, (int)fsm->sb.st_uid, - (int)fsm->sb.st_gid, (int)fsm->sb.st_size, - (fsm->path ? fsm->path : "")); - - return rc; - + fileActionString(action), (int)st->st_mode, + (int)st->st_nlink, (int)st->st_uid, + (int)st->st_gid, (int)st->st_size, + (fpath ? fpath : "")); } static int fsmSymlink(const char *opath, const char *path) @@ -1345,29 +557,26 @@ static int fsmSymlink(const char *opath, const char *path) } if (rc < 0) - rc = CPIOERR_SYMLINK_FAILED; + rc = RPMERR_SYMLINK_FAILED; return rc; } -static int fsmUnlink(const char *path, cpioMapFlags mapFlags) +static int fsmUnlink(const char *path) { int rc = 0; - if (mapFlags & CPIO_SBIT_CHECK) - removeSBITS(path); + removeSBITS(path); rc = unlink(path); if (_fsm_debug) rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, path, (rc < 0 ? strerror(errno) : "")); if (rc < 0) - rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_UNLINK_FAILED); + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED); return rc; } -static int fsmRename(const char *opath, const char *path, - cpioMapFlags mapFlags) +static int fsmRename(const char *opath, const char *path) { - if (mapFlags & CPIO_SBIT_CHECK) - removeSBITS(path); + removeSBITS(path); int rc = rename(opath, path); #if defined(ETXTBSY) && defined(__HPUX__) /* XXX HP-UX (and other os'es) don't permit rename to busy files. */ @@ -1382,30 +591,19 @@ static int fsmRename(const char *opath, const char *path, if (_fsm_debug) rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, opath, path, (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_RENAME_FAILED; + if (rc < 0) + rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED); return rc; } - -static int fsmChown(const char *path, uid_t uid, gid_t gid) +static int fsmRemove(const char *path, mode_t mode) { - int rc = chown(path, uid, gid); - if (rc < 0) { - struct stat st; - if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid) - rc = 0; - } - if (_fsm_debug) - rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__, - path, (int)uid, (int)gid, - (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_CHOWN_FAILED; - return rc; + return S_ISDIR(mode) ? fsmRmdir(path) : fsmUnlink(path); } -static int fsmLChown(const char *path, uid_t uid, gid_t gid) +static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - int rc = lchown(path, uid, gid); + int rc = S_ISLNK(mode) ? lchown(path, uid, gid) : chown(path, uid, gid); if (rc < 0) { struct stat st; if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid) @@ -1415,7 +613,7 @@ static int fsmLChown(const char *path, uid_t uid, gid_t gid) rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__, path, (int)uid, (int)gid, (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_CHOWN_FAILED; + if (rc < 0) rc = RPMERR_CHOWN_FAILED; return rc; } @@ -1431,76 +629,90 @@ static int fsmChmod(const char *path, mode_t mode) rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, path, (unsigned)(mode & 07777), (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_CHMOD_FAILED; + if (rc < 0) rc = RPMERR_CHMOD_FAILED; return rc; } -static int fsmUtime(const char *path, time_t mtime) +static int fsmUtime(const char *path, mode_t mode, time_t mtime) { int rc = 0; - struct utimbuf stamp; - stamp.actime = mtime; - stamp.modtime = mtime; - rc = utime(path, &stamp); + struct timeval stamps[2] = { + { .tv_sec = mtime, .tv_usec = 0 }, + { .tv_sec = mtime, .tv_usec = 0 }, + }; + +#if HAVE_LUTIMES + rc = lutimes(path, stamps); +#else + if (!S_ISLNK(mode)) + rc = utimes(path, stamps); +#endif + if (_fsm_debug) rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__, path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); - if (rc < 0) rc = CPIOERR_UTIME_FAILED; + if (rc < 0) rc = RPMERR_UTIME_FAILED; + /* ...but utime error is not critical for directories */ + if (rc && S_ISDIR(mode)) + rc = 0; return rc; } -static int fsmVerify(FSM_t fsm) +static int fsmVerify(const char *path, rpmfi fi, const struct stat *fsb) { int rc; - struct stat * st = &fsm->sb; - struct stat * ost = &fsm->osb; int saveerrno = errno; + struct stat dsb; + mode_t mode = rpmfiFMode(fi); - if (fsm->diskchecked && !fsm->exists) { - return CPIOERR_ENOENT; - } - if (S_ISREG(st->st_mode)) { + rc = fsmStat(path, 1, &dsb); + if (rc) + return rc; + + if (S_ISREG(mode)) { /* HP-UX (and other os'es) don't permit unlink on busy files. */ - char *rmpath = rstrscat(NULL, fsm->path, "-RPMDELETE", NULL); - rc = fsmRename(fsm->path, rmpath, fsm->mapFlags); + char *rmpath = rstrscat(NULL, path, "-RPMDELETE", NULL); + rc = fsmRename(path, rmpath); /* XXX shouldn't we take unlink return code here? */ if (!rc) - (void) fsmUnlink(rmpath, fsm->mapFlags); + (void) fsmUnlink(rmpath); else - rc = CPIOERR_UNLINK_FAILED; + rc = RPMERR_UNLINK_FAILED; free(rmpath); - return (rc ? rc : CPIOERR_ENOENT); /* XXX HACK */ - } else if (S_ISDIR(st->st_mode)) { - if (S_ISDIR(ost->st_mode)) return 0; - if (S_ISLNK(ost->st_mode)) { - rc = fsmStat(fsm->path, 0, &fsm->osb); - if (rc == CPIOERR_ENOENT) rc = 0; + return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */ + } else if (S_ISDIR(mode)) { + if (S_ISDIR(dsb.st_mode)) return 0; + if (S_ISLNK(dsb.st_mode)) { + uid_t luid = dsb.st_uid; + rc = fsmStat(path, 0, &dsb); + if (rc == RPMERR_ENOENT) rc = 0; if (rc) return rc; errno = saveerrno; - if (S_ISDIR(ost->st_mode)) return 0; + /* Only permit directory symlinks by target owner and root */ + if (S_ISDIR(dsb.st_mode) && (luid == 0 || luid == fsb->st_uid)) + return 0; } - } else if (S_ISLNK(st->st_mode)) { - if (S_ISLNK(ost->st_mode)) { + } else if (S_ISLNK(mode)) { + if (S_ISLNK(dsb.st_mode)) { char buf[8 * BUFSIZ]; size_t len; - rc = fsmReadLink(fsm->path, buf, 8 * BUFSIZ, &len); + rc = fsmReadLink(path, buf, 8 * BUFSIZ, &len); errno = saveerrno; if (rc) return rc; - /* FSM_PROCESS puts link target to fsm->buf. */ - if (rstreq(fsm->buf, buf)) return 0; + if (rstreq(rpmfiFLink(fi), buf)) return 0; } - } else if (S_ISFIFO(st->st_mode)) { - if (S_ISFIFO(ost->st_mode)) return 0; - } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { - if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) && - (ost->st_rdev == st->st_rdev)) return 0; - } else if (S_ISSOCK(st->st_mode)) { - if (S_ISSOCK(ost->st_mode)) return 0; + } else if (S_ISFIFO(mode)) { + if (S_ISFIFO(dsb.st_mode)) return 0; + } else if (S_ISCHR(mode) || S_ISBLK(mode)) { + if ((S_ISCHR(dsb.st_mode) || S_ISBLK(dsb.st_mode)) && + (dsb.st_rdev == rpmfiFRdev(fi))) return 0; + } else if (S_ISSOCK(mode)) { + if (S_ISSOCK(dsb.st_mode)) return 0; } /* XXX shouldn't do this with commit/undo. */ - rc = fsmUnlink(fsm->path, fsm->mapFlags); - if (rc == 0) rc = CPIOERR_ENOENT; - return (rc ? rc : CPIOERR_ENOENT); /* XXX HACK */ + rc = fsmUnlink(path); + if (rc == 0) rc = RPMERR_ENOENT; + return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */ } #define IS_DEV_LOG(_x) \ @@ -1512,88 +724,101 @@ static int fsmVerify(FSM_t fsm) /* Rename pre-existing modified or unmanaged file. */ -static int fsmBackup(FSM_t fsm) +static int fsmBackup(rpmfi fi, rpmFileAction action) { int rc = 0; + const char *suffix = NULL; - /* FIXME: %ghost can have backup action but no suffix */ - if ((fsm->action == FA_SAVE || fsm->action == FA_BACKUP) && fsm->osuffix) { - char * opath = fsmFsPath(fsm, S_ISDIR(fsm->sb.st_mode), NULL); - char * path = fsmFsPath(fsm, 0, fsm->osuffix); - rc = fsmRename(opath, path, fsm->mapFlags); - if (!rc) { - rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path); - fsm->exists = 0; /* it doesn't exist anymore... */ - } - free(path); - free(opath); + if (!(rpmfiFFlags(fi) & RPMFILE_GHOST)) { + switch (action) { + case FA_SAVE: + suffix = SUFFIX_RPMSAVE; + break; + case FA_BACKUP: + suffix = SUFFIX_RPMORIG; + break; + default: + break; + } + } + + if (suffix) { + char * opath = fsmFsPath(fi, NULL); + char * path = fsmFsPath(fi, suffix); + rc = fsmRename(opath, path); + if (!rc) { + rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path); + } + free(path); + free(opath); } return rc; } -static int fsmCommit(FSM_t fsm, int ix) +static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins, + rpmFileAction action, const struct stat * st, + int nofcaps) +{ + int rc = 0; + const char *dest = rpmfiFN(fi); + + if (!rc && !getuid()) { + rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid); + } + if (!rc && !S_ISLNK(st->st_mode)) { + rc = fsmChmod(path, st->st_mode); + } + /* Set file capabilities (if enabled) */ + if (!rc && !nofcaps && S_ISREG(st->st_mode) && !getuid()) { + rc = fsmSetFCaps(path, rpmfiFCaps(fi)); + } + if (!rc) { + rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi)); + } + if (!rc) { + rc = rpmpluginsCallFsmFilePrepare(plugins, fi, + path, dest, st->st_mode, action); + } + + return rc; +} + +static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix, rpmPlugins plugins) { int rc = 0; - struct stat * st = &fsm->sb; /* XXX Special case /dev/log, which shouldn't be packaged anyways */ - if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) { - /* Backup on-disk file if needed. Directories are handled earlier */ - if (!S_ISDIR(st->st_mode)) - rc = fsmBackup(fsm); - /* Rename temporary to final file name. */ - if (!S_ISDIR(st->st_mode) && (fsm->suffix || fsm->nsuffix)) { - char *npath = fsmFsPath(fsm, 0, fsm->nsuffix); - rc = fsmRename(fsm->path, npath, fsm->mapFlags); - if (!rc && fsm->nsuffix) { - char * opath = fsmFsPath(fsm, 0, NULL); - rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), - opath, npath); - free(opath); - } - free(fsm->path); - fsm->path = npath; - } - /* Set file security context (if enabled) */ - if (!rc && !getuid()) { - rc = fsmSetSELabel(fsm->sehandle, fsm->path, fsm->sb.st_mode); - } + if (!(S_ISSOCK(rpmfiFMode(fi)) && IS_DEV_LOG(*path))) { + const char *nsuffix = (action == FA_ALTNAME) ? SUFFIX_RPMNEW : NULL; + char *dest = *path; + /* Construct final destination path (nsuffix is usually NULL) */ + if (suffix) + dest = fsmFsPath(fi, nsuffix); + + /* Rename temporary to final file name if needed. */ + if (dest != *path) { + rc = fsmRename(*path, dest); + if (!rc && nsuffix) { + char * opath = fsmFsPath(fi, NULL); + rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), + opath, dest); + free(opath); + } + free(*path); + *path = dest; + } /* Call fsm commit hook for all plugins */ if (!rc) { - rc = rpmpluginsCallFsmCommit(fsm->plugins, fsm->path, fsm->sb.st_mode, DIR_TYPE_NORMAL); - } - if (S_ISLNK(st->st_mode)) { - if (!rc && !getuid()) - rc = fsmLChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid); - } else { - rpmfi fi = fsmGetFi(fsm); - if (!rc && !getuid()) - rc = fsmChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid); - if (!rc) - rc = fsmChmod(fsm->path, fsm->sb.st_mode); - if (!rc) { - rc = fsmUtime(fsm->path, rpmfiFMtimeIndex(fi, ix)); - /* utime error is not critical for directories */ - if (rc && S_ISDIR(st->st_mode)) - rc = 0; - } - /* Set file capabilities (if enabled) */ - if (!rc && !S_ISDIR(st->st_mode) && !getuid()) { - rc = fsmSetFCaps(fsm->path, rpmfiFCapsIndex(fi, ix)); - } + rc = rpmpluginsCallFsmCommit(plugins, *path, rpmfiFMode(fi), DIR_TYPE_NORMAL); } } - if (rc && fsm->failedFile && *fsm->failedFile == NULL) { - *fsm->failedFile = fsm->path; - fsm->path = NULL; - } return rc; } /** * Return formatted string representation of file disposition. - * @param a file dispostion + * @param a file disposition * @return formatted string */ static const char * fileActionString(rpmFileAction a) @@ -1601,8 +826,6 @@ static const char * fileActionString(rpmFileAction a) switch (a) { case FA_UNKNOWN: return "unknown"; case FA_CREATE: return "create"; - case FA_COPYOUT: return "copyout"; - case FA_COPYIN: return "copyin"; case FA_BACKUP: return "backup"; case FA_SAVE: return "save"; case FA_SKIP: return "skip"; @@ -1611,14 +834,15 @@ static const char * fileActionString(rpmFileAction a) case FA_SKIPNSTATE: return "skipnstate"; case FA_SKIPNETSHARED: return "skipnetshared"; case FA_SKIPCOLOR: return "skipcolor"; + case FA_TOUCH: return "touch"; default: return "???"; } } /* Remember any non-regular file state for recording in the rpmdb */ -static void setFileState(rpmfs fs, int i, rpmFileAction action) +static void setFileState(rpmfs fs, int i) { - switch (action) { + switch (rpmfsGetAction(fs, i)) { case FA_SKIPNSTATE: rpmfsSetState(fs, i, RPMFILE_STATE_NOTINSTALLED); break; @@ -1628,219 +852,223 @@ static void setFileState(rpmfs fs, int i, rpmFileAction action) case FA_SKIPCOLOR: rpmfsSetState(fs, i, RPMFILE_STATE_WRONGCOLOR); break; + case FA_TOUCH: + rpmfsSetState(fs, i, RPMFILE_STATE_NORMAL); + break; default: break; } } -int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi fi, FD_t cfd, +int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, rpmpsm psm, char ** failedFile) { + FD_t payload = rpmtePayload(te); + rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); rpmfs fs = rpmteGetFileStates(te); - FSM_t fsm = fsmNew(FSM_PKGINSTALL, fs, fi, failedFile); - rpmcpio_t archive = rpmcpioOpen(cfd, O_RDONLY); - struct stat * st = &fsm->sb; + rpmPlugins plugins = rpmtsPlugins(ts); + struct stat sb; int saveerrno = errno; int rc = 0; - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST); - - if (!rpmteIsSource(te)) - fsm->mapFlags |= CPIO_SBIT_CHECK; - - if (archive == NULL) - rc = CPIOERR_INTERNAL; + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; + int firsthardlink = -1; + FD_t firstlinkfile = NULL; + int skip; + rpmFileAction action; + char *tid = NULL; + const char *suffix; + char *fpath = NULL; + + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; + goto exit; + } - fsm->sehandle = rpmtsSELabelHandle(ts); - fsm->plugins = rpmtsPlugins(ts); - /* transaction id used for temporary path suffix while installing */ - rasprintf(&fsm->suffix, ";%08x", (unsigned)rpmtsGetTid(ts)); + rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); /* Detect and create directories not explicitly in package. */ - if (!rc) { - rc = fsmMkdirs(fi, rpmteGetFileStates(te), fsm->sehandle, fsm->plugins); - } + rc = fsmMkdirs(files, fs, plugins); while (!rc) { - hardLink_t li = NULL; - - /* Clean fsm, free'ing memory. */ - fsmReset(fsm); - /* Read next payload header. */ - rc = rpmcpioHeaderRead(archive, &(fsm->path), &(fsm->sb)); + rc = rpmfiNext(fi); - /* Detect and exit on end-of-payload. */ - if (rc == CPIOERR_HDR_TRAILER) { - rc = 0; + if (rc < 0) { + if (rc == RPMERR_ITER_END) + rc = 0; break; } - if (rc) break; - - /* Identify mapping index. */ - fsm->ix = mapFind(fsm->iter, fsm->path); - - /* Mapping error */ - if (fsm->ix < 0) { - if (fsm->failedFile && *fsm->failedFile == NULL) - *fsm->failedFile = xstrdup(fsm->path); - rc = CPIOERR_UNMAPPED_FILE; - break; + action = rpmfsGetAction(fs, rpmfiFX(fi)); + skip = XFA_SKIPPING(action); + suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; + if (action != FA_TOUCH) { + fpath = fsmFsPath(fi, suffix); + } else { + fpath = fsmFsPath(fi, ""); } - rc = fsmInit(fsm); + /* Remap file perms, owner, and group. */ + rc = rpmfiStat(fi, 1, &sb); - /* Exit on error. */ - if (rc) { - fsm->postpone = 1; - break; - } + fsmDebug(fpath, action, &sb); - /* Run fsm init hook for all plugins */ - rc = rpmpluginsCallFsmInit(fsm->plugins, fsm->path, fsm->sb.st_mode); - /* Exit on error. */ - if (rc) { - fsm->postpone = 1; + if (rc) break; - } - - if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1) - fsm->postpone = saveHardLink(fsm, &li); - - setFileState(rpmteGetFileStates(te), fsm->ix, fsm->action); - - if (!fsm->postpone) { - if (S_ISREG(st->st_mode)) { - rc = fsmVerify(fsm); - if (!(rc == CPIOERR_ENOENT)) return rc; - rc = expandRegular(fsm, psm, archive, nodigest); - } else if (S_ISDIR(st->st_mode)) { - /* Directories replacing something need early backup */ - rc = fsmBackup(fsm); - rc = fsmVerify(fsm); - if (rc == CPIOERR_ENOENT) { - mode_t mode = st->st_mode; + + /* Run fsm init hook for all plugins */ + //FIXME. functions related with msm. + rc = rpmpluginsCallFsmInit(plugins, fpath, sb.st_mode); + + /* Run fsm file pre hook for all plugins */ + rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, + sb.st_mode, action); + if (rc) { + skip = 1; + } else { + setFileState(fs, rpmfiFX(fi)); + } + + if (!skip) { + int setmeta = 1; + + /* Directories replacing something need early backup */ + if (!suffix) { + rc = fsmBackup(fi, action); + } + /* Assume file does't exist when tmp suffix is in use */ + if (!suffix) { + rc = fsmVerify(fpath, fi, &sb); + } else { + rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT; + } + + if (S_ISREG(sb.st_mode)) { + if (rc == RPMERR_ENOENT) { + rc = fsmMkfile(fi, fpath, files, psm, nodigest, + &setmeta, &firsthardlink, &firstlinkfile); + } + } else if (S_ISDIR(sb.st_mode)) { + if (rc == RPMERR_ENOENT) { + mode_t mode = sb.st_mode; mode &= ~07777; mode |= 00700; - rc = fsmMkdir(fsm->path, mode); + rc = fsmMkdir(fpath, mode); } - } else if (S_ISLNK(st->st_mode)) { - if ((st->st_size + 1) > fsm->bufsize) { - rc = CPIOERR_HDR_SIZE; - } else if (rpmcpioRead(archive, fsm->buf, st->st_size) != st->st_size) { - rc = CPIOERR_READ_FAILED; - } else { - - fsm->buf[st->st_size] = '\0'; - /* fsmVerify() assumes link target in fsm->buf */ - rc = fsmVerify(fsm); - if (rc == CPIOERR_ENOENT) { - rc = fsmSymlink(fsm->buf, fsm->path); - } - } - } else if (S_ISFIFO(st->st_mode)) { - /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */ - rc = fsmVerify(fsm); - if (rc == CPIOERR_ENOENT) { - rc = fsmMkfifo(fsm->path, 0000); + } else if (S_ISLNK(sb.st_mode)) { + if (rc == RPMERR_ENOENT) { + rc = fsmSymlink(rpmfiFLink(fi), fpath); + } + } else if (S_ISFIFO(sb.st_mode)) { + /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ + if (rc == RPMERR_ENOENT) { + rc = fsmMkfifo(fpath, 0000); } - } else if (S_ISCHR(st->st_mode) || - S_ISBLK(st->st_mode) || - S_ISSOCK(st->st_mode)) + } else if (S_ISCHR(sb.st_mode) || + S_ISBLK(sb.st_mode) || + S_ISSOCK(sb.st_mode)) { - rc = fsmVerify(fsm); - if (rc == CPIOERR_ENOENT) { - rc = fsmMknod(fsm->path, fsm->sb.st_mode, fsm->sb.st_rdev); + if (rc == RPMERR_ENOENT) { + rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); } } else { /* XXX Special case /dev/log, which shouldn't be packaged anyways */ - if (!IS_DEV_LOG(fsm->path)) - rc = CPIOERR_UNKNOWN_FILETYPE; + if (!IS_DEV_LOG(fpath)) + rc = RPMERR_UNKNOWN_FILETYPE; } - if (li != NULL) { - li->createdPath = li->linkIndex; - rc = fsmMakeLinks(fsm, li); - } - } + /* Set permissions, timestamps etc for non-hardlink entries */ + if (!rc && setmeta) { + rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); + } + } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { + /* we skip the hard linked file containing the content */ + /* write the content to the first used instead */ + char *fn = rpmfilesFN(files, firsthardlink); + rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); + wfd_close(&firstlinkfile); + firsthardlink = -1; + free(fn); + } if (rc) { - if (!fsm->postpone) { + if (!skip) { /* XXX only erase if temp fn w suffix is in use */ - if (fsm->suffix) { - if (S_ISDIR(st->st_mode)) { - (void) fsmRmdir(fsm->path); - } else { - (void) fsmUnlink(fsm->path, fsm->mapFlags); - } + if (suffix && (action != FA_TOUCH)) { + (void) fsmRemove(fpath, sb.st_mode); } errno = saveerrno; - if (fsm->failedFile && *fsm->failedFile == NULL) - *fsm->failedFile = xstrdup(fsm->path); } + } else { + /* Notify on success. */ + rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); - break; - } + if (!skip) { + /* Backup file if needed. Directories are handled earlier */ + if (suffix) + rc = fsmBackup(fi, action); - /* Notify on success. */ - rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(archive)); + if (!rc) + rc = fsmCommit(&fpath, fi, action, suffix, plugins); + } + } - if (!fsm->postpone) { - rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1) - ? fsmCommitLinks(fsm) : fsmCommit(fsm, fsm->ix)); - } - if (rc) { - break; - } + if (rc) + *failedFile = xstrdup(fpath); + + /* Run fsm file post hook for all plugins */ + rpmpluginsCallFsmFilePost(plugins, fi, fpath, + sb.st_mode, action, rc); + fpath = _free(fpath); } - if (!rc) - rc = checkHardLinks(fsm); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); + +exit: /* No need to bother with close errors on read */ - rpmcpioFree(archive); - fsmFree(fsm); + rpmfiArchiveClose(fi); + rpmfiFree(fi); + Fclose(payload); + free(tid); + free(fpath); return rc; } -int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi, +int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, rpmpsm psm, char ** failedFile) { + rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); rpmfs fs = rpmteGetFileStates(te); - FSM_t fsm = fsmNew(FSM_PKGERASE, fs, fi, failedFile); + rpmPlugins plugins = rpmtsPlugins(ts); + struct stat sb; int rc = 0; + char *fpath = NULL; - if (!rpmteIsSource(te)) - fsm->mapFlags |= CPIO_SBIT_CHECK; + while (!rc && rpmfiNext(fi) >= 0) { + rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); + fpath = fsmFsPath(fi, NULL); + rc = fsmStat(fpath, 1, &sb); - while (!rc) { - /* Clean fsm, free'ing memory. */ - fsmReset(fsm); - - /* Identify mapping index. */ - fsm->ix = mapNextIterator(fsm->iter); + fsmDebug(fpath, action, &sb); - /* Exit on end-of-payload. */ - if (fsm->ix < 0) - break; + /* Run fsm file pre hook for all plugins */ + rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, + sb.st_mode, action); - rc = fsmInit(fsm); - - if (!fsm->postpone) - rc = fsmBackup(fsm); + if (!XFA_SKIPPING(action)) + rc = fsmBackup(fi, action); /* Remove erased files. */ - if (!fsm->postpone && fsm->action == FA_ERASE) { - int missingok = (fsm->fflags & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); + if (action == FA_ERASE) { + int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); - if (S_ISDIR(fsm->sb.st_mode)) { - rc = fsmRmdir(fsm->path); - } else { - rc = fsmUnlink(fsm->path, fsm->mapFlags); - } + rc = fsmRemove(fpath, sb.st_mode); /* * Missing %ghost or %missingok entries are not errors. @@ -1849,7 +1077,7 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi, * and complaining about job already done seems like kinderkarten * level "But it was MY turn!" whining... */ - if (rc == CPIOERR_ENOENT && missingok) { + if (rc == RPMERR_ENOENT && missingok) { rc = 0; } @@ -1858,112 +1086,41 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi, * to track at least some of the expected failures though, * such as when we knowingly left config file backups etc behind. */ - if (rc == CPIOERR_ENOTEMPTY) { + if (rc == RPMERR_ENOTEMPTY) { rc = 0; } if (rc) { int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING; rpmlog(lvl, _("%s %s: remove failed: %s\n"), - S_ISDIR(fsm->sb.st_mode) ? _("directory") : _("file"), - fsm->path, strerror(errno)); + S_ISDIR(sb.st_mode) ? _("directory") : _("file"), + fpath, strerror(errno)); } } + + /* Run fsm file post hook for all plugins */ + rpmpluginsCallFsmFilePost(plugins, fi, fpath, + sb.st_mode, action, rc); + /* XXX Failure to remove is not (yet) cause for failure. */ if (!strict_erasures) rc = 0; - if (rc) break; + if (rc) + *failedFile = xstrdup(fpath); - /* Notify on success. */ - /* On erase we're iterating backwards, fixup for progress */ - rpm_loff_t amount = (fsm->ix >= 0) ? - rpmfiFC(fsmGetFi(fsm)) - fsm->ix : 0; - rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); + if (rc == 0) { + /* Notify on success. */ + /* On erase we're iterating backwards, fixup for progress */ + rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); + rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); + } + fpath = _free(fpath); } - fsmFree(fsm); + free(fpath); + rpmfiFree(fi); return rc; } -int rpmPackageFilesArchive(rpmfi fi, int isSrc, FD_t cfd, - rpm_loff_t * archiveSize, char ** failedFile) -{ - rpmfs fs = rpmfsNew(rpmfiFC(fi), 0);; - FSM_t fsm = fsmNew(FSM_PKGBUILD, fs, fi, failedFile);; - rpmcpio_t archive = rpmcpioOpen(cfd, O_WRONLY); - int rc = 0; - - fsm->mapFlags |= CPIO_MAP_TYPE; - if (isSrc) - fsm->mapFlags |= CPIO_FOLLOW_SYMLINKS; - - if (archive == NULL) { - rc = CPIOERR_INTERNAL; - } else { - int ghost, i, fc = rpmfiFC(fi); - - /* XXX Is this actually still needed? */ - for (i = 0; i < fc; i++) { - ghost = (rpmfiFFlagsIndex(fi, i) & RPMFILE_GHOST); - rpmfsSetAction(fs, i, ghost ? FA_SKIP : FA_COPYOUT); - } - } - - while (!rc) { - fsmReset(fsm); - - /* Identify mapping index. */ - fsm->ix = mapNextIterator(fsm->iter); - - /* Exit on end-of-payload. */ - if (fsm->ix < 0) - break; - - rc = fsmInit(fsm); - - /* Exit on error. */ - if (rc) { - fsm->postpone = 1; - break; - } - - if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1) - fsm->postpone = saveHardLink(fsm, NULL); - - if (fsm->postpone || fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */ - continue; - /* Hardlinks are handled later */ - if (!(S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)) { - /* Copy file into archive. */ - rc = writeFile(fsm, 1, archive, fsm->ix); - } - - if (rc) { - if (!fsm->postpone) { - if (fsm->failedFile && *fsm->failedFile == NULL) - *fsm->failedFile = xstrdup(fsm->path); - } - - break; - } - } - - /* Flush partial sets of hard linked files. */ - if (!rc) - rc = writeLinks(fsm, archive); - - /* Finish the payload stream */ - if (!rc) - rc = rpmcpioClose(archive); - - if (archiveSize) - *archiveSize = (rc == 0) ? rpmcpioTell(archive) : 0; - - rpmcpioFree(archive); - rpmfsFree(fs); - fsmFree(fsm); - - return rc; -} |