3 * File state machine to handle a payload from a package.
11 #include <sys/capability.h>
14 #include <rpm/rpmte.h>
15 #include <rpm/rpmts.h>
16 #include <rpm/rpmsq.h>
17 #include <rpm/rpmlog.h>
19 #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
22 #define fsmUNSAFE fsmStage
23 #include "lib/rpmfi_internal.h" /* XXX fi->apath, ... */
24 #include "lib/rpmte_internal.h" /* XXX rpmfs */
25 #include "lib/rpmts_internal.h" /* rpmtsSELabelFoo() only */
26 #include "lib/rpmplugins.h" /* rpm plugins hooks */
27 #include "lib/rpmug.h"
33 int _fsm_debug = _FSM_DEBUG;
35 extern int _fsm_debug;
40 CPIO_MAP_PATH = (1 << 0),
41 CPIO_MAP_MODE = (1 << 1),
42 CPIO_MAP_UID = (1 << 2),
43 CPIO_MAP_GID = (1 << 3),
44 CPIO_FOLLOW_SYMLINKS= (1 << 4), /*!< only for building. */
45 CPIO_MAP_ABSOLUTE = (1 << 5),
46 CPIO_MAP_ADDDOT = (1 << 6),
47 CPIO_MAP_TYPE = (1 << 8), /*!< only for building. */
48 CPIO_SBIT_CHECK = (1 << 9)
50 typedef rpmFlags cpioMapFlags;
52 typedef struct fsmIterator_s * FSMI_t;
53 typedef struct fsm_s * FSM_t;
55 typedef struct hardLink_s * hardLink_t;
57 typedef enum fileStage_e {
63 /* XXX Failure to remove is not (yet) cause for failure. */
64 static int strict_erasures = 0;
67 * Keeps track of the set of all hard links to a file in an archive.
71 const char ** nsuffix;
81 * Iterator across package file info, forward on install, backward on erase.
83 struct fsmIterator_s {
84 rpmfs fs; /*!< file state info. */
85 rpmfi fi; /*!< transaction element file info. */
86 int reverse; /*!< reversed traversal? */
87 int isave; /*!< last returned iterator index. */
88 int i; /*!< iterator index. */
92 * File name and stat information.
95 char * path; /*!< Current file name. */
96 char * buf; /*!< read: Buffer. */
97 size_t bufsize; /*!< read: Buffer allocated size. */
98 FSMI_t iter; /*!< File iterator. */
99 int ix; /*!< Current file iterator index. */
100 hardLink_t links; /*!< Pending hard linked file(s). */
101 char ** failedFile; /*!< First file name that failed. */
102 const char * osuffix; /*!< Old, preserved, file suffix. */
103 const char * nsuffix; /*!< New, created, file suffix. */
104 char * suffix; /*!< Current file suffix. */
105 int postpone; /*!< Skip remaining stages? */
106 int diskchecked; /*!< Has stat(2) been performed? */
107 int exists; /*!< Does current file exist on disk? */
108 cpioMapFlags mapFlags; /*!< Bit(s) to control mapping. */
109 const char * dirName; /*!< File directory name. */
110 const char * baseName; /*!< File base name. */
111 struct selabel_handle *sehandle; /*!< SELinux label handle (if any). */
112 rpmPlugins plugins; /*!< Rpm plugins handle */
114 unsigned fflags; /*!< File flags. */
115 rpmFileAction action; /*!< File disposition. */
116 fileStage goal; /*!< Package state machine goal. */
117 struct stat sb; /*!< Current file stat(2) info. */
118 struct stat osb; /*!< Original file stat(2) info. */
123 * Retrieve transaction element file info from file state machine iterator.
124 * @param fsm file state machine
125 * @return transaction element file info
127 static rpmfi fsmGetFi(const FSM_t fsm)
129 const FSMI_t iter = fsm->iter;
130 return (iter ? iter->fi : NULL);
133 static rpmfs fsmGetFs(const FSM_t fsm)
135 const FSMI_t iter = fsm->iter;
136 return (iter ? iter->fs : NULL);
139 #define SUFFIX_RPMORIG ".rpmorig"
140 #define SUFFIX_RPMSAVE ".rpmsave"
141 #define SUFFIX_RPMNEW ".rpmnew"
143 /* Default directory and file permissions if not mapped */
144 #define _dirPerms 0755
145 #define _filePerms 0644
148 * XXX Forward declarations for previously exported functions to avoid moving
149 * things around needlessly
151 static const char * fileActionString(rpmFileAction a);
154 * Build path to file from file info, optionally ornamented with suffix.
155 * @param fsm file state machine data
156 * @param isDir directory or regular path?
157 * @param suffix suffix to use (NULL disables)
158 * @retval path to file (malloced)
160 static char * fsmFsPath(const FSM_t fsm, int isDir,
163 return rstrscat(NULL,
164 fsm->dirName, fsm->baseName,
165 (!isDir && suffix) ? suffix : "",
170 * Destroy file info iterator.
171 * @param p file info iterator
172 * @retval NULL always
174 static FSMI_t mapFreeIterator(FSMI_t iter)
177 iter->fs = NULL; /* rpmfs is not refcounted */
178 iter->fi = rpmfiFree(iter->fi);
185 * Create file info iterator.
186 * @param fi transaction element file info
187 * @return file info iterator
190 mapInitIterator(rpmfs fs, rpmfi fi, int reverse)
194 iter = xcalloc(1, sizeof(*iter));
195 iter->fs = fs; /* rpmfs is not refcounted */
196 iter->fi = rpmfiLink(fi);
197 iter->reverse = reverse;
198 iter->i = (iter->reverse ? (rpmfiFC(fi) - 1) : 0);
199 iter->isave = iter->i;
204 * Return next index into file info.
205 * @param a file info iterator
206 * @return next index, -1 on termination
208 static int mapNextIterator(FSMI_t iter)
213 const rpmfi fi = iter->fi;
215 if (iter->i >= 0) i = iter->i--;
217 if (iter->i < rpmfiFC(fi)) i = iter->i++;
226 static int cpioStrCmp(const void * a, const void * b)
228 const char * afn = *(const char **)a;
229 const char * bfn = *(const char **)b;
231 /* Match rpm-4.0 payloads with ./ prefixes. */
232 if (afn[0] == '.' && afn[1] == '/') afn += 2;
233 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
235 /* If either path is absolute, make it relative. */
236 if (afn[0] == '/') afn += 1;
237 if (bfn[0] == '/') bfn += 1;
239 return strcmp(afn, bfn);
243 * Locate archive path in file info.
244 * @param iter file info iterator
245 * @param fsmPath archive path
246 * @return index into file info, -1 if archive path was not found
248 static int mapFind(FSMI_t iter, const char * fsmPath)
253 const rpmfi fi = iter->fi;
254 int fc = rpmfiFC(fi);
255 if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) {
258 if (fi->apath != NULL)
259 p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath),
262 iter->i = p - fi->apath;
263 ix = mapNextIterator(iter);
271 * Directory name iterator.
273 typedef struct dnli_s {
282 * Destroy directory name iterator.
283 * @param a directory name iterator
284 * @retval NULL always
286 static DNLI_t dnlFreeIterator(DNLI_t dnli)
289 if (dnli->active) free(dnli->active);
296 * Create directory name iterator.
297 * @param fi file info set
298 * @param fs file state set
299 * @param reverse traverse directory names in reverse order?
300 * @return directory name iterator
302 static DNLI_t dnlInitIterator(rpmfi fi, rpmfs fs, int reverse)
311 dnli = xcalloc(1, sizeof(*dnli));
313 dnli->reverse = reverse;
314 dnli->i = (reverse ? dc : 0);
317 dnli->active = xcalloc(dc, sizeof(*dnli->active));
318 int fc = rpmfiFC(fi);
320 /* Identify parent directories not skipped. */
321 for (i = 0; i < fc; i++)
322 if (!XFA_SKIPPING(rpmfsGetAction(fs, i)))
323 dnli->active[rpmfiDIIndex(fi, i)] = 1;
325 /* Exclude parent directories that are explicitly included. */
326 for (i = 0; i < fc; i++) {
330 if (!S_ISDIR(rpmfiFModeIndex(fi, i)))
333 dil = rpmfiDIIndex(fi, i);
334 dnlen = strlen(rpmfiDNIndex(fi, dil));
335 bnlen = strlen(rpmfiBNIndex(fi, i));
337 for (j = 0; j < dc; j++) {
341 if (!dnli->active[j] || j == dil)
343 dnl = rpmfiDNIndex(fi, j);
345 if (jlen != (dnlen+bnlen+1))
347 if (!rstreqn(dnl, rpmfiDNIndex(fi, dil), dnlen))
349 if (!rstreqn(dnl+dnlen, rpmfiBNIndex(fi, i), bnlen))
351 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
353 /* This directory is included in the package. */
359 /* Print only once per package. */
362 for (i = 0; i < dc; i++) {
363 if (!dnli->active[i]) continue;
367 "========== Directories not explicitly included in package:\n");
369 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfiDNIndex(fi, i));
372 rpmlog(RPMLOG_DEBUG, "==========\n");
379 * Return next directory name (from file info).
380 * @param dnli directory name iterator
381 * @return next directory name
384 const char * dnlNextIterator(DNLI_t dnli)
386 const char * dn = NULL;
390 int dc = rpmfiDC(fi);
395 i = (!dnli->reverse ? dnli->i++ : --dnli->i);
396 } while (i >= 0 && i < dc && !dnli->active[i]);
398 if (i >= 0 && i < dc)
399 dn = rpmfiDNIndex(fi, i);
408 * Map next file path and action.
409 * @param fsm file state machine
410 * @param i file index
412 static int fsmMapPath(FSM_t fsm, int i)
414 rpmfi fi = fsmGetFi(fsm); /* XXX const except for fstates */
419 fsm->action = FA_UNKNOWN;
421 if (fi && i >= 0 && i < rpmfiFC(fi)) {
422 rpmfs fs = fsmGetFs(fsm);
423 /* XXX these should use rpmfiFFlags() etc */
424 fsm->action = rpmfsGetAction(fs, i);
425 fsm->fflags = rpmfiFFlagsIndex(fi, i);
427 /* src rpms have simple base name in payload. */
428 fsm->dirName = rpmfiDNIndex(fi, rpmfiDIIndex(fi, i));
429 fsm->baseName = rpmfiBNIndex(fi, i);
431 /* Never create backup for %ghost files. */
432 if (fsm->goal != FSM_PKGBUILD && !(fsm->fflags & RPMFILE_GHOST)) {
433 switch (fsm->action) {
435 fsm->nsuffix = SUFFIX_RPMNEW;
438 fsm->osuffix = SUFFIX_RPMSAVE;
441 fsm->osuffix = (fsm->goal == FSM_PKGINSTALL) ?
442 SUFFIX_RPMORIG : SUFFIX_RPMSAVE;
449 if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
450 fsm->path = _free(fsm->path);
451 fsm->path = fsmFsPath(fsm, S_ISDIR(fsm->sb.st_mode),
452 (fsm->suffix ? fsm->suffix : fsm->nsuffix));
459 * Save hard link in chain.
460 * @param fsm file state machine data
461 * @retval linkSet hard link set when complete
462 * @return Is chain only partially filled?
464 static int saveHardLink(FSM_t fsm, hardLink_t * linkSet)
466 struct stat * st = &fsm->sb;
470 hardLink_t *tailp, li;
472 /* Find hard link set. */
473 for (tailp = &fsm->links; (li = *tailp) != NULL; tailp = &li->next) {
474 if (li->sb.st_ino == st->st_ino && li->sb.st_dev == st->st_dev)
478 /* New hard link encountered, add new link to set. */
480 li = xcalloc(1, sizeof(*li));
482 li->sb = *st; /* structure assignment */
483 li->nlink = st->st_nlink;
484 li->linkIndex = fsm->ix;
485 li->createdPath = -1;
487 li->filex = xcalloc(st->st_nlink, sizeof(li->filex[0]));
488 memset(li->filex, -1, (st->st_nlink * sizeof(li->filex[0])));
489 li->nsuffix = xcalloc(st->st_nlink, sizeof(*li->nsuffix));
491 if (fsm->goal == FSM_PKGBUILD)
492 li->linksLeft = st->st_nlink;
493 if (fsm->goal == FSM_PKGINSTALL)
496 *tailp = li; /* append to tail of linked list */
499 if (fsm->goal == FSM_PKGBUILD) --li->linksLeft;
500 li->filex[li->linksLeft] = fsm->ix;
501 li->nsuffix[li->linksLeft] = fsm->nsuffix;
502 if (fsm->goal == FSM_PKGINSTALL) li->linksLeft++;
504 if (fsm->goal == FSM_PKGBUILD)
505 return (li->linksLeft > 0);
507 if (fsm->goal != FSM_PKGINSTALL)
510 if (!(st->st_size || li->linksLeft == st->st_nlink))
513 /* Here come the bits, time to choose a non-skipped file name. */
514 { rpmfs fs = fsmGetFs(fsm);
516 for (j = li->linksLeft - 1; j >= 0; j--) {
518 if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix)))
524 /* Are all links skipped or not encountered yet? */
526 return 1; /* XXX W2DO? */
528 /* Save the non-skipped file name and map index. */
532 fsm->path = _free(fsm->path);
534 rc = fsmMapPath(fsm, fsm->ix);
539 * Destroy set of hard links.
540 * @param li set of hard links
541 * @return NULL always
543 static hardLink_t freeHardLink(hardLink_t li)
546 li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
547 li->filex = _free(li->filex);
553 /* Check for hard links missing from payload */
554 static int checkHardLinks(FSM_t fsm)
557 rpmfs fs = fsmGetFs(fsm);
559 for (hardLink_t li = fsm->links; li != NULL; li = li->next) {
561 for (nlink_t i = 0 ; i < li->linksLeft; i++) {
562 int ix = li->filex[i];
563 if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix)))
565 rc = CPIOERR_MISSING_HARDLINK;
566 if (fsm->failedFile && *fsm->failedFile == NULL) {
567 if (!fsmMapPath(fsm, ix)) {
568 /* Out-of-sync hardlinks handled as sub-state */
569 *fsm->failedFile = fsm->path;
580 static FSM_t fsmNew(fileStage goal, rpmfs fs, rpmfi fi, char ** failedFile)
582 FSM_t fsm = xcalloc(1, sizeof(*fsm));
586 fsm->iter = mapInitIterator(fs, fi, (goal == FSM_PKGERASE));
588 /* common flags for all modes */
589 fsm->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
591 if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
592 fsm->bufsize = 8 * BUFSIZ;
593 fsm->buf = xmalloc(fsm->bufsize);
596 fsm->failedFile = failedFile;
598 *fsm->failedFile = NULL;
603 static FSM_t fsmFree(FSM_t fsm)
606 fsm->buf = _free(fsm->buf);
609 fsm->iter = mapFreeIterator(fsm->iter);
610 fsm->failedFile = NULL;
612 fsm->path = _free(fsm->path);
613 fsm->suffix = _free(fsm->suffix);
615 while ((li = fsm->links) != NULL) {
616 fsm->links = li->next;
624 /* Find and set file security context */
625 static int fsmSetSELabel(struct selabel_handle *sehandle,
626 const char *path, mode_t mode)
631 security_context_t scon = NULL;
633 if (selabel_lookup_raw(sehandle, &scon, path, mode) == 0) {
634 rc = lsetfilecon(path, scon);
637 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n",
638 __func__, path, scon,
639 (rc < 0 ? strerror(errno) : ""));
642 if (rc < 0 && errno == EOPNOTSUPP)
649 return rc ? CPIOERR_LSETFCON_FAILED : 0;
652 static int fsmSetFCaps(const char *path, const char *captxt)
656 if (captxt && *captxt != '\0') {
657 cap_t fcaps = cap_from_text(captxt);
658 if (fcaps == NULL || cap_set_file(path, fcaps) != 0) {
659 rc = CPIOERR_SETCAP_FAILED;
668 * Map file stat(2) info.
669 * @param fsm file state machine
671 static int fsmMapAttrs(FSM_t fsm)
673 struct stat * st = &fsm->sb;
674 rpmfi fi = fsmGetFi(fsm);
677 /* this check is pretty moot, rpmfi accessors check array bounds etc */
678 if (fi && i >= 0 && i < rpmfiFC(fi)) {
679 ino_t finalInode = rpmfiFInodeIndex(fi, i);
680 mode_t finalMode = rpmfiFModeIndex(fi, i);
681 dev_t finalRdev = rpmfiFRdevIndex(fi, i);
682 time_t finalMtime = rpmfiFMtimeIndex(fi, i);
683 const char *user = rpmfiFUserIndex(fi, i);
684 const char *group = rpmfiFGroupIndex(fi, i);
688 if (user && rpmugUid(user, &uid)) {
689 if (fsm->goal == FSM_PKGINSTALL)
690 rpmlog(RPMLOG_WARNING,
691 _("user %s does not exist - using root\n"), user);
692 finalMode &= ~S_ISUID; /* turn off suid bit */
695 if (group && rpmugGid(group, &gid)) {
696 if (fsm->goal == FSM_PKGINSTALL)
697 rpmlog(RPMLOG_WARNING,
698 _("group %s does not exist - using root\n"), group);
699 finalMode &= ~S_ISGID; /* turn off sgid bit */
702 if (fsm->mapFlags & CPIO_MAP_MODE)
703 st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
704 if (fsm->mapFlags & CPIO_MAP_TYPE) {
705 st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
706 if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
707 && st->st_nlink == 0)
709 st->st_ino = finalInode;
710 st->st_rdev = finalRdev;
711 st->st_mtime = finalMtime;
713 if (fsm->mapFlags & CPIO_MAP_UID)
715 if (fsm->mapFlags & CPIO_MAP_GID)
722 * Create file from payload stream.
723 * @param fsm file state machine data
724 * @param archive payload archive
725 * @return 0 on success
727 static int expandRegular(FSM_t fsm, rpmpsm psm, rpmcpio_t archive, int nodigest)
730 const struct stat * st = &fsm->sb;
731 rpm_loff_t left = st->st_size;
732 const unsigned char * fidigest = NULL;
733 pgpHashAlgo digestalgo = 0;
736 wfd = Fopen(fsm->path, "w.ufdio");
738 rc = CPIOERR_OPEN_FAILED;
743 rpmfi fi = fsmGetFi(fsm);
744 digestalgo = rpmfiDigestAlgo(fi);
745 fidigest = rpmfiFDigestIndex(fi, fsm->ix, NULL, NULL);
748 if (st->st_size > 0 && fidigest)
749 fdInitDigest(wfd, digestalgo, 0);
753 len = (left > fsm->bufsize ? fsm->bufsize : left);
754 if (rpmcpioRead(archive, fsm->buf, len) != len) {
755 rc = CPIOERR_READ_FAILED;
758 if ((Fwrite(fsm->buf, sizeof(*fsm->buf), len, wfd) != len) || Ferror(wfd)) {
759 rc = CPIOERR_WRITE_FAILED;
765 /* don't call this with fileSize == fileComplete */
767 rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(archive));
770 if (st->st_size > 0 && fidigest) {
771 void * digest = NULL;
774 fdFiniDigest(wfd, digestalgo, &digest, NULL, 0);
776 if (digest != NULL && fidigest != NULL) {
777 size_t diglen = rpmDigestLength(digestalgo);
778 if (memcmp(digest, fidigest, diglen)) {
779 rc = CPIOERR_DIGEST_MISMATCH;
782 rc = CPIOERR_DIGEST_MISMATCH;
796 static int fsmReadLink(const char *path,
797 char *buf, size_t bufsize, size_t *linklen)
799 ssize_t llen = readlink(path, buf, bufsize - 1);
800 int rc = CPIOERR_READLINK_FAILED;
803 rpmlog(RPMLOG_DEBUG, " %8s (%s, buf, %d) %s\n",
805 path, (int)(bufsize -1), (llen < 0 ? strerror(errno) : ""));
817 * Write next item to payload stream.
818 * @param fsm file state machine data
819 * @param writeData should data be written?
820 * @param archive payload archive
821 * @param ix file index
822 * @return 0 on success
824 static int writeFile(FSM_t fsm, int writeData, rpmcpio_t archive, int ix)
827 char * path = fsm->path;
828 struct stat * st = &fsm->sb;
829 struct stat * ost = &fsm->osb;
830 char * symbuf = NULL;
834 st->st_size = (writeData ? ost->st_size : 0);
836 if (S_ISDIR(st->st_mode)) {
838 } else if (S_ISLNK(st->st_mode)) {
840 * While linux puts the size of a symlink in the st_size field,
841 * I don't think that's a specified standard.
844 rc = fsmReadLink(fsm->path, fsm->buf, fsm->bufsize, &linklen);
846 st->st_size = linklen;
847 rstrcat(&symbuf, fsm->buf); /* XXX save readlink return. */
850 if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) {
851 fsm->path = rstrscat(NULL, (fsm->mapFlags & CPIO_MAP_ADDDOT) ? "." : "",
852 fsm->dirName, fsm->baseName, NULL);
853 } else if (fsm->mapFlags & CPIO_MAP_PATH) {
854 rpmfi fi = fsmGetFi(fsm);
855 fsm->path = xstrdup((fi->apath ? fi->apath[ix] :
856 rpmfiBNIndex(fi, ix)));
859 rc = rpmcpioHeaderWrite(archive, fsm->path, st);
866 if (writeData && S_ISREG(st->st_mode)) {
869 rfd = Fopen(fsm->path, "r.ufdio");
871 rc = CPIOERR_OPEN_FAILED;
878 len = (left > fsm->bufsize ? fsm->bufsize : left);
879 if (Fread(fsm->buf, sizeof(*fsm->buf), len, rfd) != len || Ferror(rfd)) {
880 rc = CPIOERR_READ_FAILED;
884 if (rpmcpioWrite(archive, fsm->buf, len) != len) {
885 rc = CPIOERR_WRITE_FAILED;
890 } else if (writeData && S_ISLNK(st->st_mode)) {
891 size_t len = strlen(symbuf);
892 if (rpmcpioWrite(archive, symbuf, len) != len) {
893 rc = CPIOERR_WRITE_FAILED;
900 /* preserve any prior errno across close */
911 * Write set of linked files to payload stream.
912 * @param fsm file state machine data
913 * @param archive payload archive
914 * @param li link to write
915 * @return 0 on success
917 static int writeLinkedFile(FSM_t fsm, rpmcpio_t archive, hardLink_t li)
919 char * path = fsm->path;
920 const char * nsuffix = fsm->nsuffix;
928 for (i = li->nlink - 1; i >= 0; i--) {
930 if (li->filex[i] < 0) continue;
932 rc = fsmMapPath(fsm, li->filex[i]);
934 /* Write data after last link. */
935 rc = writeFile(fsm, (i == 0), archive, li->filex[i]);
936 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
938 *fsm->failedFile = xstrdup(fsm->path);
941 fsm->path = _free(fsm->path);
945 fsm->nsuffix = nsuffix;
950 static int writeLinks(FSM_t fsm, rpmcpio_t archive)
955 for (hardLink_t li = fsm->links; li; li = li->next) {
956 /* Re-calculate link count for archive header. */
957 for (j = -1, nlink = 0, i = 0; i < li->nlink; i++) {
958 if (li->filex[i] < 0)
963 /* XXX force the contents out as well. */
965 li->filex[0] = li->filex[j];
968 li->sb.st_nlink = nlink;
970 fsm->sb = li->sb; /* structure assignment */
971 fsm->osb = fsm->sb; /* structure assignment */
973 if (!rc) rc = writeLinkedFile(fsm, archive, li);
978 static int fsmStat(const char *path, int dolstat, struct stat *sb)
982 rc = lstat(path, sb);
986 if (_fsm_debug && rc && errno != ENOENT)
987 rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n",
989 path, (rc < 0 ? strerror(errno) : ""));
991 rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_LSTAT_FAILED);
992 /* WTH is this, and is it really needed, still? */
993 memset(sb, 0, sizeof(*sb)); /* XXX s390x hackery */
998 static int fsmVerify(FSM_t fsm);
1000 /** \ingroup payload
1001 * Create pending hard links to existing file.
1002 * @param fsm file state machine data
1003 * @param li hard link
1004 * @return 0 on success
1006 static int fsmMakeLinks(FSM_t fsm, hardLink_t li)
1008 char * path = fsm->path;
1009 char * opath = NULL;
1010 const char * nsuffix = fsm->nsuffix;
1016 fsm->nsuffix = NULL;
1018 rc = fsmMapPath(fsm, li->filex[li->createdPath]);
1021 for (i = 0; i < li->nlink; i++) {
1022 if (li->filex[i] < 0) continue;
1023 if (li->createdPath == i) continue;
1025 fsm->path = _free(fsm->path);
1026 rc = fsmMapPath(fsm, li->filex[i]);
1027 if (XFA_SKIPPING(fsm->action)) continue;
1029 rc = fsmVerify(fsm);
1031 if (!(rc == CPIOERR_ENOENT)) break;
1033 /* XXX link(opath, fsm->path) */
1034 rc = link(opath, fsm->path);
1036 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
1037 opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
1038 if (rc < 0) rc = CPIOERR_LINK_FAILED;
1040 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
1042 *fsm->failedFile = xstrdup(fsm->path);
1047 fsm->path = _free(fsm->path);
1050 fsm->nsuffix = nsuffix;
1055 static int fsmCommit(FSM_t fsm, int ix);
1057 /** \ingroup payload
1058 * Commit hard linked file set atomically.
1059 * @param fsm file state machine data
1060 * @return 0 on success
1062 static int fsmCommitLinks(FSM_t fsm)
1064 char * path = fsm->path;
1065 const char * nsuffix = fsm->nsuffix;
1066 struct stat * st = &fsm->sb;
1072 fsm->nsuffix = NULL;
1074 for (li = fsm->links; li != NULL; li = li->next) {
1075 if (li->sb.st_ino == st->st_ino && li->sb.st_dev == st->st_dev)
1079 for (i = 0; i < li->nlink; i++) {
1080 if (li->filex[i] < 0) continue;
1081 rc = fsmMapPath(fsm, li->filex[i]);
1082 if (!XFA_SKIPPING(fsm->action))
1083 rc = fsmCommit(fsm, li->filex[i]);
1084 fsm->path = _free(fsm->path);
1088 fsm->nsuffix = nsuffix;
1093 static int fsmRmdir(const char *path)
1095 int rc = rmdir(path);
1097 rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
1098 path, (rc < 0 ? strerror(errno) : ""));
1101 case ENOENT: rc = CPIOERR_ENOENT; break;
1102 case ENOTEMPTY: rc = CPIOERR_ENOTEMPTY; break;
1103 default: rc = CPIOERR_RMDIR_FAILED; break;
1108 static int fsmMkdir(const char *path, mode_t mode)
1110 int rc = mkdir(path, (mode & 07777));
1112 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
1113 path, (unsigned)(mode & 07777),
1114 (rc < 0 ? strerror(errno) : ""));
1115 if (rc < 0) rc = CPIOERR_MKDIR_FAILED;
1119 static int fsmMkfifo(const char *path, mode_t mode)
1121 int rc = mkfifo(path, (mode & 07777));
1124 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n",
1125 __func__, path, (unsigned)(mode & 07777),
1126 (rc < 0 ? strerror(errno) : ""));
1130 rc = CPIOERR_MKFIFO_FAILED;
1135 static int fsmMknod(const char *path, mode_t mode, dev_t dev)
1137 /* FIX: check S_IFIFO or dev != 0 */
1138 int rc = mknod(path, (mode & ~07777), dev);
1141 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n",
1142 __func__, path, (unsigned)(mode & ~07777),
1143 (unsigned)dev, (rc < 0 ? strerror(errno) : ""));
1147 rc = CPIOERR_MKNOD_FAILED;
1153 * Create (if necessary) directories not explicitly included in package.
1154 * @param dnli file state machine data
1155 * @param sehandle selinux label handle (bah)
1156 * @param plugins rpm plugins handle
1157 * @return 0 on success
1159 static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle, rpmPlugins plugins)
1161 DNLI_t dnli = dnlInitIterator(fi, fs, 0);
1164 int dc = rpmfiDC(fi);
1170 short * dnlx = NULL;
1172 dnlx = (dc ? xcalloc(dc, sizeof(*dnlx)) : NULL);
1175 while ((dpath = dnlNextIterator(dnli)) != NULL) {
1176 size_t dnlen = strlen(dpath);
1177 char * te, dn[dnlen+1];
1180 if (dc < 0) continue;
1185 if (dnlen <= ldnlen && rstreq(dpath, ldn))
1188 /* Copy as we need to modify the string */
1189 (void) stpcpy(dn, dpath);
1191 /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
1192 for (i = 1, te = dn + 1; *te != '\0'; te++, i++) {
1198 /* Already validated? */
1200 (ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i))
1203 /* Move pre-existing path marker forward. */
1204 dnlx[dc] = (te - dn);
1208 /* Validate next component of path. */
1209 rc = fsmStat(dn, 1, &sb); /* lstat */
1212 /* Directory already exists? */
1213 if (rc == 0 && S_ISDIR(sb.st_mode)) {
1214 /* Move pre-existing path marker forward. */
1215 dnlx[dc] = (te - dn);
1216 } else if (rc == CPIOERR_ENOENT) {
1218 mode_t mode = S_IFDIR | (_dirPerms & 07777);
1219 rc = fsmMkdir(dn, mode);
1221 rc = fsmSetSELabel(sehandle, dn, mode);
1223 rpmlog(RPMLOG_DEBUG,
1224 "%s directory created with perms %04o\n",
1225 dn, (unsigned)(mode & 07777));
1228 /* Run file closed hook for all plugins */
1229 rc = rpmpluginsCallFsmCommit(plugins, dn, mode, DIR_TYPE_UNOWNED);
1238 /* Save last validated path. */
1239 if (ldnalloc < (dnlen + 1)) {
1240 ldnalloc = dnlen + 100;
1241 ldn = xrealloc(ldn, ldnalloc);
1243 if (ldn != NULL) { /* XXX can't happen */
1250 dnlFreeIterator(dnli);
1255 static void removeSBITS(const char *path)
1258 if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) {
1259 if ((stb.st_mode & 06000) != 0) {
1260 (void) chmod(path, stb.st_mode & 0777);
1263 if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
1264 (void) cap_set_file(path, NULL);
1270 /********************************************************************/
1272 static void fsmReset(FSM_t fsm)
1274 fsm->path = _free(fsm->path);
1276 fsm->diskchecked = fsm->exists = 0;
1277 fsm->action = FA_UNKNOWN;
1278 fsm->osuffix = NULL;
1279 fsm->nsuffix = NULL;
1280 memset(&(fsm->sb), 0, sizeof(fsm->sb));
1281 memset(&(fsm->osb), 0, sizeof(fsm->sb));
1284 static int fsmInit(FSM_t fsm)
1288 /* On non-install, mode must be known so that dirs don't get suffix. */
1289 if (fsm->goal != FSM_PKGINSTALL) {
1290 rpmfi fi = fsmGetFi(fsm);
1291 fsm->sb.st_mode = rpmfiFModeIndex(fi, fsm->ix);
1294 /* Generate file path. */
1295 rc = fsmMapPath(fsm, fsm->ix);
1298 /* Perform lstat/stat for disk file. */
1299 if (fsm->path != NULL &&
1300 !(fsm->goal == FSM_PKGINSTALL && S_ISREG(fsm->sb.st_mode)))
1302 int dolstat = !(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS);
1303 rc = fsmStat(fsm->path, dolstat, &fsm->osb);
1304 if (rc == CPIOERR_ENOENT) {
1305 // errno = saveerrno; XXX temporary commented out
1308 } else if (rc == 0) {
1312 /* Skip %ghost files on build. */
1315 fsm->diskchecked = 1;
1318 /* On non-install, the disk file stat is what's remapped. */
1319 if (fsm->goal != FSM_PKGINSTALL)
1320 fsm->sb = fsm->osb; /* structure assignment */
1322 /* Remap file perms, owner, and group. */
1323 rc = fsmMapAttrs(fsm);
1326 fsm->postpone = XFA_SKIPPING(fsm->action);
1328 rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n",
1329 fileActionString(fsm->action), (int)fsm->sb.st_mode,
1330 (int)fsm->sb.st_nlink, (int)fsm->sb.st_uid,
1331 (int)fsm->sb.st_gid, (int)fsm->sb.st_size,
1332 (fsm->path ? fsm->path : ""));
1338 static int fsmSymlink(const char *opath, const char *path)
1340 int rc = symlink(opath, path);
1343 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
1344 opath, path, (rc < 0 ? strerror(errno) : ""));
1348 rc = CPIOERR_SYMLINK_FAILED;
1352 static int fsmUnlink(const char *path, cpioMapFlags mapFlags)
1355 if (mapFlags & CPIO_SBIT_CHECK)
1359 rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
1360 path, (rc < 0 ? strerror(errno) : ""));
1362 rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_UNLINK_FAILED);
1366 static int fsmRename(const char *opath, const char *path,
1367 cpioMapFlags mapFlags)
1369 if (mapFlags & CPIO_SBIT_CHECK)
1371 int rc = rename(opath, path);
1372 #if defined(ETXTBSY) && defined(__HPUX__)
1373 /* XXX HP-UX (and other os'es) don't permit rename to busy files. */
1374 if (rc && errno == ETXTBSY) {
1375 char *rmpath = NULL;
1376 rstrscat(&rmpath, path, "-RPMDELETE", NULL);
1377 rc = rename(path, rmpath);
1378 if (!rc) rc = rename(opath, path);
1383 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
1384 opath, path, (rc < 0 ? strerror(errno) : ""));
1385 if (rc < 0) rc = CPIOERR_RENAME_FAILED;
1390 static int fsmChown(const char *path, uid_t uid, gid_t gid)
1392 int rc = chown(path, uid, gid);
1395 if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
1399 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__,
1400 path, (int)uid, (int)gid,
1401 (rc < 0 ? strerror(errno) : ""));
1402 if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
1406 static int fsmLChown(const char *path, uid_t uid, gid_t gid)
1408 int rc = lchown(path, uid, gid);
1411 if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
1415 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__,
1416 path, (int)uid, (int)gid,
1417 (rc < 0 ? strerror(errno) : ""));
1418 if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
1422 static int fsmChmod(const char *path, mode_t mode)
1424 int rc = chmod(path, (mode & 07777));
1427 if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777))
1431 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
1432 path, (unsigned)(mode & 07777),
1433 (rc < 0 ? strerror(errno) : ""));
1434 if (rc < 0) rc = CPIOERR_CHMOD_FAILED;
1438 static int fsmUtime(const char *path, time_t mtime)
1441 struct utimbuf stamp;
1442 stamp.actime = mtime;
1443 stamp.modtime = mtime;
1444 rc = utime(path, &stamp);
1446 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__,
1447 path, (unsigned)mtime, (rc < 0 ? strerror(errno) : ""));
1448 if (rc < 0) rc = CPIOERR_UTIME_FAILED;
1452 static int fsmVerify(FSM_t fsm)
1455 struct stat * st = &fsm->sb;
1456 struct stat * ost = &fsm->osb;
1457 int saveerrno = errno;
1459 if (fsm->diskchecked && !fsm->exists) {
1460 return CPIOERR_ENOENT;
1462 if (S_ISREG(st->st_mode)) {
1463 /* HP-UX (and other os'es) don't permit unlink on busy files. */
1464 char *rmpath = rstrscat(NULL, fsm->path, "-RPMDELETE", NULL);
1465 rc = fsmRename(fsm->path, rmpath, fsm->mapFlags);
1466 /* XXX shouldn't we take unlink return code here? */
1468 (void) fsmUnlink(rmpath, fsm->mapFlags);
1470 rc = CPIOERR_UNLINK_FAILED;
1472 return (rc ? rc : CPIOERR_ENOENT); /* XXX HACK */
1473 } else if (S_ISDIR(st->st_mode)) {
1474 if (S_ISDIR(ost->st_mode)) return 0;
1475 if (S_ISLNK(ost->st_mode)) {
1476 rc = fsmStat(fsm->path, 0, &fsm->osb);
1477 if (rc == CPIOERR_ENOENT) rc = 0;
1480 if (S_ISDIR(ost->st_mode)) return 0;
1482 } else if (S_ISLNK(st->st_mode)) {
1483 if (S_ISLNK(ost->st_mode)) {
1484 char buf[8 * BUFSIZ];
1486 rc = fsmReadLink(fsm->path, buf, 8 * BUFSIZ, &len);
1489 /* FSM_PROCESS puts link target to fsm->buf. */
1490 if (rstreq(fsm->buf, buf)) return 0;
1492 } else if (S_ISFIFO(st->st_mode)) {
1493 if (S_ISFIFO(ost->st_mode)) return 0;
1494 } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
1495 if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
1496 (ost->st_rdev == st->st_rdev)) return 0;
1497 } else if (S_ISSOCK(st->st_mode)) {
1498 if (S_ISSOCK(ost->st_mode)) return 0;
1500 /* XXX shouldn't do this with commit/undo. */
1501 rc = fsmUnlink(fsm->path, fsm->mapFlags);
1502 if (rc == 0) rc = CPIOERR_ENOENT;
1503 return (rc ? rc : CPIOERR_ENOENT); /* XXX HACK */
1506 #define IS_DEV_LOG(_x) \
1507 ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
1508 rstreqn((_x), "/dev/log", sizeof("/dev/log")-1) && \
1509 ((_x)[sizeof("/dev/log")-1] == '\0' || \
1510 (_x)[sizeof("/dev/log")-1] == ';'))
1514 /* Rename pre-existing modified or unmanaged file. */
1515 static int fsmBackup(FSM_t fsm)
1519 /* FIXME: %ghost can have backup action but no suffix */
1520 if ((fsm->action == FA_SAVE || fsm->action == FA_BACKUP) && fsm->osuffix) {
1521 char * opath = fsmFsPath(fsm, S_ISDIR(fsm->sb.st_mode), NULL);
1522 char * path = fsmFsPath(fsm, 0, fsm->osuffix);
1523 rc = fsmRename(opath, path, fsm->mapFlags);
1525 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path);
1526 fsm->exists = 0; /* it doesn't exist anymore... */
1534 static int fsmCommit(FSM_t fsm, int ix)
1537 struct stat * st = &fsm->sb;
1539 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
1540 if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
1541 /* Backup on-disk file if needed. Directories are handled earlier */
1542 if (!S_ISDIR(st->st_mode))
1543 rc = fsmBackup(fsm);
1544 /* Rename temporary to final file name. */
1545 if (!S_ISDIR(st->st_mode) && (fsm->suffix || fsm->nsuffix)) {
1546 char *npath = fsmFsPath(fsm, 0, fsm->nsuffix);
1547 rc = fsmRename(fsm->path, npath, fsm->mapFlags);
1548 if (!rc && fsm->nsuffix) {
1549 char * opath = fsmFsPath(fsm, 0, NULL);
1550 rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
1557 /* Set file security context (if enabled) */
1558 if (!rc && !getuid()) {
1559 rc = fsmSetSELabel(fsm->sehandle, fsm->path, fsm->sb.st_mode);
1561 /* Call fsm commit hook for all plugins */
1563 rc = rpmpluginsCallFsmCommit(fsm->plugins, fsm->path, fsm->sb.st_mode, DIR_TYPE_NORMAL);
1565 if (S_ISLNK(st->st_mode)) {
1566 if (!rc && !getuid())
1567 rc = fsmLChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
1569 rpmfi fi = fsmGetFi(fsm);
1570 if (!rc && !getuid())
1571 rc = fsmChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
1573 rc = fsmChmod(fsm->path, fsm->sb.st_mode);
1575 rc = fsmUtime(fsm->path, rpmfiFMtimeIndex(fi, ix));
1576 /* utime error is not critical for directories */
1577 if (rc && S_ISDIR(st->st_mode))
1580 /* Set file capabilities (if enabled) */
1581 if (!rc && !S_ISDIR(st->st_mode) && !getuid()) {
1582 rc = fsmSetFCaps(fsm->path, rpmfiFCapsIndex(fi, ix));
1587 if (rc && fsm->failedFile && *fsm->failedFile == NULL) {
1588 *fsm->failedFile = fsm->path;
1595 * Return formatted string representation of file disposition.
1596 * @param a file dispostion
1597 * @return formatted string
1599 static const char * fileActionString(rpmFileAction a)
1602 case FA_UNKNOWN: return "unknown";
1603 case FA_CREATE: return "create";
1604 case FA_COPYOUT: return "copyout";
1605 case FA_COPYIN: return "copyin";
1606 case FA_BACKUP: return "backup";
1607 case FA_SAVE: return "save";
1608 case FA_SKIP: return "skip";
1609 case FA_ALTNAME: return "altname";
1610 case FA_ERASE: return "erase";
1611 case FA_SKIPNSTATE: return "skipnstate";
1612 case FA_SKIPNETSHARED: return "skipnetshared";
1613 case FA_SKIPCOLOR: return "skipcolor";
1614 default: return "???";
1618 /* Remember any non-regular file state for recording in the rpmdb */
1619 static void setFileState(rpmfs fs, int i, rpmFileAction action)
1623 rpmfsSetState(fs, i, RPMFILE_STATE_NOTINSTALLED);
1625 case FA_SKIPNETSHARED:
1626 rpmfsSetState(fs, i, RPMFILE_STATE_NETSHARED);
1629 rpmfsSetState(fs, i, RPMFILE_STATE_WRONGCOLOR);
1636 int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi fi, FD_t cfd,
1637 rpmpsm psm, char ** failedFile)
1639 rpmfs fs = rpmteGetFileStates(te);
1640 FSM_t fsm = fsmNew(FSM_PKGINSTALL, fs, fi, failedFile);
1641 rpmcpio_t archive = rpmcpioOpen(cfd, O_RDONLY);
1642 struct stat * st = &fsm->sb;
1643 int saveerrno = errno;
1645 int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST);
1647 if (!rpmteIsSource(te))
1648 fsm->mapFlags |= CPIO_SBIT_CHECK;
1650 if (archive == NULL)
1651 rc = CPIOERR_INTERNAL;
1653 fsm->sehandle = rpmtsSELabelHandle(ts);
1654 fsm->plugins = rpmtsPlugins(ts);
1656 /* transaction id used for temporary path suffix while installing */
1657 rasprintf(&fsm->suffix, ";%08x", (unsigned)rpmtsGetTid(ts));
1659 /* Detect and create directories not explicitly in package. */
1661 rc = fsmMkdirs(fi, rpmteGetFileStates(te), fsm->sehandle, fsm->plugins);
1665 hardLink_t li = NULL;
1667 /* Clean fsm, free'ing memory. */
1670 /* Read next payload header. */
1671 rc = rpmcpioHeaderRead(archive, &(fsm->path), &(fsm->sb));
1673 /* Detect and exit on end-of-payload. */
1674 if (rc == CPIOERR_HDR_TRAILER) {
1681 /* Identify mapping index. */
1682 fsm->ix = mapFind(fsm->iter, fsm->path);
1686 if (fsm->failedFile && *fsm->failedFile == NULL)
1687 *fsm->failedFile = xstrdup(fsm->path);
1688 rc = CPIOERR_UNMAPPED_FILE;
1694 /* Exit on error. */
1700 /* Run fsm init hook for all plugins */
1701 rc = rpmpluginsCallFsmInit(fsm->plugins, fsm->path, fsm->sb.st_mode);
1703 /* Exit on error. */
1709 if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
1710 fsm->postpone = saveHardLink(fsm, &li);
1712 setFileState(rpmteGetFileStates(te), fsm->ix, fsm->action);
1714 if (!fsm->postpone) {
1715 if (S_ISREG(st->st_mode)) {
1716 rc = fsmVerify(fsm);
1717 if (!(rc == CPIOERR_ENOENT)) return rc;
1718 rc = expandRegular(fsm, psm, archive, nodigest);
1719 } else if (S_ISDIR(st->st_mode)) {
1720 /* Directories replacing something need early backup */
1721 rc = fsmBackup(fsm);
1722 rc = fsmVerify(fsm);
1723 if (rc == CPIOERR_ENOENT) {
1724 mode_t mode = st->st_mode;
1727 rc = fsmMkdir(fsm->path, mode);
1729 } else if (S_ISLNK(st->st_mode)) {
1730 if ((st->st_size + 1) > fsm->bufsize) {
1731 rc = CPIOERR_HDR_SIZE;
1732 } else if (rpmcpioRead(archive, fsm->buf, st->st_size) != st->st_size) {
1733 rc = CPIOERR_READ_FAILED;
1736 fsm->buf[st->st_size] = '\0';
1737 /* fsmVerify() assumes link target in fsm->buf */
1738 rc = fsmVerify(fsm);
1739 if (rc == CPIOERR_ENOENT) {
1740 rc = fsmSymlink(fsm->buf, fsm->path);
1743 } else if (S_ISFIFO(st->st_mode)) {
1744 /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
1745 rc = fsmVerify(fsm);
1746 if (rc == CPIOERR_ENOENT) {
1747 rc = fsmMkfifo(fsm->path, 0000);
1749 } else if (S_ISCHR(st->st_mode) ||
1750 S_ISBLK(st->st_mode) ||
1751 S_ISSOCK(st->st_mode))
1753 rc = fsmVerify(fsm);
1754 if (rc == CPIOERR_ENOENT) {
1755 rc = fsmMknod(fsm->path, fsm->sb.st_mode, fsm->sb.st_rdev);
1758 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
1759 if (!IS_DEV_LOG(fsm->path))
1760 rc = CPIOERR_UNKNOWN_FILETYPE;
1763 li->createdPath = li->linkIndex;
1764 rc = fsmMakeLinks(fsm, li);
1769 if (!fsm->postpone) {
1770 /* XXX only erase if temp fn w suffix is in use */
1772 if (S_ISDIR(st->st_mode)) {
1773 (void) fsmRmdir(fsm->path);
1775 (void) fsmUnlink(fsm->path, fsm->mapFlags);
1779 if (fsm->failedFile && *fsm->failedFile == NULL)
1780 *fsm->failedFile = xstrdup(fsm->path);
1786 /* Notify on success. */
1787 rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(archive));
1789 if (!fsm->postpone) {
1790 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
1791 ? fsmCommitLinks(fsm) : fsmCommit(fsm, fsm->ix));
1799 rc = checkHardLinks(fsm);
1801 /* No need to bother with close errors on read */
1802 rpmcpioFree(archive);
1809 int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfi fi,
1810 rpmpsm psm, char ** failedFile)
1812 rpmfs fs = rpmteGetFileStates(te);
1813 FSM_t fsm = fsmNew(FSM_PKGERASE, fs, fi, failedFile);
1816 if (!rpmteIsSource(te))
1817 fsm->mapFlags |= CPIO_SBIT_CHECK;
1820 /* Clean fsm, free'ing memory. */
1823 /* Identify mapping index. */
1824 fsm->ix = mapNextIterator(fsm->iter);
1826 /* Exit on end-of-payload. */
1833 rc = fsmBackup(fsm);
1835 /* Remove erased files. */
1836 if (!fsm->postpone && fsm->action == FA_ERASE) {
1837 int missingok = (fsm->fflags & (RPMFILE_MISSINGOK | RPMFILE_GHOST));
1839 if (S_ISDIR(fsm->sb.st_mode)) {
1840 rc = fsmRmdir(fsm->path);
1842 rc = fsmUnlink(fsm->path, fsm->mapFlags);
1846 * Missing %ghost or %missingok entries are not errors.
1847 * XXX: Are non-existent files ever an actual error here? Afterall
1848 * that's exactly what we're trying to accomplish here,
1849 * and complaining about job already done seems like kinderkarten
1850 * level "But it was MY turn!" whining...
1852 if (rc == CPIOERR_ENOENT && missingok) {
1857 * Dont whine on non-empty directories for now. We might be able
1858 * to track at least some of the expected failures though,
1859 * such as when we knowingly left config file backups etc behind.
1861 if (rc == CPIOERR_ENOTEMPTY) {
1866 int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
1867 rpmlog(lvl, _("%s %s: remove failed: %s\n"),
1868 S_ISDIR(fsm->sb.st_mode) ? _("directory") : _("file"),
1869 fsm->path, strerror(errno));
1872 /* XXX Failure to remove is not (yet) cause for failure. */
1873 if (!strict_erasures) rc = 0;
1877 /* Notify on success. */
1878 /* On erase we're iterating backwards, fixup for progress */
1879 rpm_loff_t amount = (fsm->ix >= 0) ?
1880 rpmfiFC(fsmGetFi(fsm)) - fsm->ix : 0;
1881 rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
1890 int rpmPackageFilesArchive(rpmfi fi, int isSrc, FD_t cfd,
1891 rpm_loff_t * archiveSize, char ** failedFile)
1893 rpmfs fs = rpmfsNew(rpmfiFC(fi), 0);;
1894 FSM_t fsm = fsmNew(FSM_PKGBUILD, fs, fi, failedFile);;
1895 rpmcpio_t archive = rpmcpioOpen(cfd, O_WRONLY);
1898 fsm->mapFlags |= CPIO_MAP_TYPE;
1900 fsm->mapFlags |= CPIO_FOLLOW_SYMLINKS;
1902 if (archive == NULL) {
1903 rc = CPIOERR_INTERNAL;
1905 int ghost, i, fc = rpmfiFC(fi);
1907 /* XXX Is this actually still needed? */
1908 for (i = 0; i < fc; i++) {
1909 ghost = (rpmfiFFlagsIndex(fi, i) & RPMFILE_GHOST);
1910 rpmfsSetAction(fs, i, ghost ? FA_SKIP : FA_COPYOUT);
1917 /* Identify mapping index. */
1918 fsm->ix = mapNextIterator(fsm->iter);
1920 /* Exit on end-of-payload. */
1926 /* Exit on error. */
1932 if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
1933 fsm->postpone = saveHardLink(fsm, NULL);
1935 if (fsm->postpone || fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
1937 /* Hardlinks are handled later */
1938 if (!(S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)) {
1939 /* Copy file into archive. */
1940 rc = writeFile(fsm, 1, archive, fsm->ix);
1944 if (!fsm->postpone) {
1945 if (fsm->failedFile && *fsm->failedFile == NULL)
1946 *fsm->failedFile = xstrdup(fsm->path);
1953 /* Flush partial sets of hard linked files. */
1955 rc = writeLinks(fsm, archive);
1957 /* Finish the payload stream */
1959 rc = rpmcpioClose(archive);
1962 *archiveSize = (rc == 0) ? rpmcpioTell(archive) : 0;
1964 rpmcpioFree(archive);