Untangle lib/fsm.c and lib/cpio.c
[platform/upstream/rpm.git] / lib / fsm.c
1 /** \ingroup payload
2  * \file lib/fsm.c
3  * File state machine to handle a payload from a package.
4  */
5
6 #include "system.h"
7
8 #include <utime.h>
9 #include <errno.h>
10 #if defined(HAVE_MMAP)
11 #include <sys/mman.h>
12 #endif
13 #if WITH_CAP
14 #include <sys/capability.h>
15 #endif
16
17 #include <rpm/rpmte.h>
18 #include <rpm/rpmts.h>
19 #include <rpm/rpmsq.h>
20 #include <rpm/rpmlog.h>
21
22 #include "rpmio/rpmio_internal.h"       /* fdInit/FiniDigest */
23 #include "lib/cpio.h"
24 #include "lib/fsm.h"
25 #define fsmUNSAFE       fsmStage
26 #include "lib/rpmfi_internal.h" /* XXX fi->apath, ... */
27 #include "lib/rpmte_internal.h" /* XXX rpmfs */
28 #include "lib/rpmts_internal.h" /* rpmtsSELabelFoo() only */
29 #include "lib/rpmug.h"
30
31 #include "debug.h"
32
33 #define _FSM_DEBUG      0
34 int _fsm_debug = _FSM_DEBUG;
35
36 /* XXX Failure to remove is not (yet) cause for failure. */
37 static int strict_erasures = 0;
38
39 /** \ingroup payload
40  * Keeps track of the set of all hard links to a file in an archive.
41  */
42 struct hardLink_s {
43     hardLink_t next;
44     const char ** nsuffix;
45     int * filex;
46     struct stat sb;
47     nlink_t nlink;
48     nlink_t linksLeft;
49     int linkIndex;
50     int createdPath;
51 };
52
53 /** \ingroup payload
54  * Iterator across package file info, forward on install, backward on erase.
55  */
56 struct fsmIterator_s {
57     rpmts ts;                   /*!< transaction set. */
58     rpmte te;                   /*!< transaction element. */
59     rpmfi fi;                   /*!< transaction element file info. */
60     int reverse;                /*!< reversed traversal? */
61     int isave;                  /*!< last returned iterator index. */
62     int i;                      /*!< iterator index. */
63 };
64
65 /**
66  * Retrieve transaction set from file state machine iterator.
67  * @param fsm           file state machine
68  * @return              transaction set
69  */
70 static rpmts fsmGetTs(const FSM_t fsm)
71 {
72     const FSMI_t iter = fsm->iter;
73     return (iter ? iter->ts : NULL);
74 }
75
76 /**
77  * Retrieve transaction element file info from file state machine iterator.
78  * @param fsm           file state machine
79  * @return              transaction element file info
80  */
81 static rpmfi fsmGetFi(const FSM_t fsm)
82 {
83     const FSMI_t iter = fsm->iter;
84     return (iter ? iter->fi : NULL);
85 }
86
87 static rpmte fsmGetTe(const FSM_t fsm)
88 {
89     const FSMI_t iter = fsm->iter;
90     return (iter ? iter->te : NULL);
91 }
92
93 #define SUFFIX_RPMORIG  ".rpmorig"
94 #define SUFFIX_RPMSAVE  ".rpmsave"
95 #define SUFFIX_RPMNEW   ".rpmnew"
96
97 /* Default directory and file permissions if not mapped */
98 #define _dirPerms 0755
99 #define _filePerms 0644
100
101 /* 
102  * XXX Forward declarations for previously exported functions to avoid moving 
103  * things around needlessly 
104  */ 
105 static const char * fileStageString(fileStage a);
106 static const char * fileActionString(rpmFileAction a);
107 static int fsmStage(FSM_t fsm, fileStage stage);
108
109 /** \ingroup payload
110  * Build path to file from file info, ornamented with subdir and suffix.
111  * @param fsm           file state machine data
112  * @param st            file stat info
113  * @param subdir        subdir to use (NULL disables)
114  * @param suffix        suffix to use (NULL disables)
115  * @retval              path to file (malloced)
116  */
117 static char * fsmFsPath(const FSM_t fsm,
118                 const struct stat * st,
119                 const char * subdir,
120                 const char * suffix)
121 {
122     char * s = NULL;
123
124     if (fsm) {
125         int isDir = (st && S_ISDIR(st->st_mode));
126         s = rstrscat(NULL, fsm->dirName,
127                            (!isDir && subdir) ? subdir : "",
128                            fsm->baseName,
129                            (!isDir && suffix) ? suffix : "",
130                            NULL);
131     }
132     return s;
133 }
134
135 /** \ingroup payload
136  * Destroy file info iterator.
137  * @param p             file info iterator
138  * @retval              NULL always
139  */
140 static FSMI_t mapFreeIterator(FSMI_t iter)
141 {
142     if (iter) {
143         iter->ts = rpmtsFree(iter->ts);
144         iter->te = NULL; /* XXX rpmte is not refcounted yet */
145         iter->fi = rpmfiFree(iter->fi);
146         free(iter);
147     }
148     return NULL;
149 }
150
151 /** \ingroup payload
152  * Create file info iterator.
153  * @param ts            transaction set
154  * @param fi            transaction element file info
155  * @return              file info iterator
156  */
157 static FSMI_t 
158 mapInitIterator(rpmts ts, rpmte te, rpmfi fi)
159 {
160     FSMI_t iter = NULL;
161
162     iter = xcalloc(1, sizeof(*iter));
163     iter->ts = rpmtsLink(ts);
164     iter->te = te; /* XXX rpmte is not refcounted yet */
165     iter->fi = rpmfiLink(fi);
166     iter->reverse = (rpmteType(te) == TR_REMOVED);
167     iter->i = (iter->reverse ? (rpmfiFC(fi) - 1) : 0);
168     iter->isave = iter->i;
169     return iter;
170 }
171
172 /** \ingroup payload
173  * Return next index into file info.
174  * @param a             file info iterator
175  * @return              next index, -1 on termination
176  */
177 static int mapNextIterator(FSMI_t iter)
178 {
179     int i = -1;
180
181     if (iter) {
182         const rpmfi fi = iter->fi;
183         if (iter->reverse) {
184             if (iter->i >= 0)   i = iter->i--;
185         } else {
186             if (iter->i < rpmfiFC(fi))  i = iter->i++;
187         }
188         iter->isave = i;
189     }
190     return i;
191 }
192
193 /** \ingroup payload
194  */
195 static int cpioStrCmp(const void * a, const void * b)
196 {
197     const char * afn = *(const char **)a;
198     const char * bfn = *(const char **)b;
199
200     /* Match rpm-4.0 payloads with ./ prefixes. */
201     if (afn[0] == '.' && afn[1] == '/') afn += 2;
202     if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
203
204     /* If either path is absolute, make it relative. */
205     if (afn[0] == '/')  afn += 1;
206     if (bfn[0] == '/')  bfn += 1;
207
208     return strcmp(afn, bfn);
209 }
210
211 /** \ingroup payload
212  * Locate archive path in file info.
213  * @param iter          file info iterator
214  * @param fsmPath       archive path
215  * @return              index into file info, -1 if archive path was not found
216  */
217 static int mapFind(FSMI_t iter, const char * fsmPath)
218 {
219     int ix = -1;
220
221     if (iter) {
222         const rpmfi fi = iter->fi;
223         int fc = rpmfiFC(fi);
224         if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) {
225             char ** p = NULL;
226
227             if (fi->apath != NULL)
228                 p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath),
229                         cpioStrCmp);
230             if (p) {
231                 iter->i = p - fi->apath;
232                 ix = mapNextIterator(iter);
233             }
234         }
235     }
236     return ix;
237 }
238
239 /** \ingroup payload
240  * Directory name iterator.
241  */
242 typedef struct dnli_s {
243     rpmfi fi;
244     char * active;
245     int reverse;
246     int isave;
247     int i;
248 } * DNLI_t;
249
250 /** \ingroup payload
251  * Destroy directory name iterator.
252  * @param a             directory name iterator
253  * @retval              NULL always
254  */
255 static DNLI_t dnlFreeIterator(DNLI_t dnli)
256 {
257     if (dnli) {
258         if (dnli->active) free(dnli->active);
259         free(dnli);
260     }
261     return NULL;
262 }
263
264 /** \ingroup payload
265  */
266 static inline int dnlCount(const DNLI_t dnli)
267 {
268     return (dnli ? rpmfiDC(dnli->fi) : 0);
269 }
270
271 /** \ingroup payload
272  */
273 static inline int dnlIndex(const DNLI_t dnli)
274 {
275     return (dnli ? dnli->isave : -1);
276 }
277
278 /** \ingroup payload
279  * Create directory name iterator.
280  * @param fsm           file state machine data
281  * @param reverse       traverse directory names in reverse order?
282  * @return              directory name iterator
283  */
284 static DNLI_t dnlInitIterator(const FSM_t fsm, int reverse)
285 {
286     rpmfi fi = fsmGetFi(fsm);
287     rpmfs fs = rpmteGetFileStates(fsmGetTe(fsm));
288     DNLI_t dnli;
289     int i, j;
290     int dc;
291
292     if (fi == NULL)
293         return NULL;
294     dc = rpmfiDC(fi);
295     dnli = xcalloc(1, sizeof(*dnli));
296     dnli->fi = fi;
297     dnli->reverse = reverse;
298     dnli->i = (reverse ? dc : 0);
299
300     if (dc) {
301         dnli->active = xcalloc(dc, sizeof(*dnli->active));
302         int fc = rpmfiFC(fi);
303
304         /* Identify parent directories not skipped. */
305         for (i = 0; i < fc; i++)
306             if (!XFA_SKIPPING(rpmfsGetAction(fs, i)))
307                 dnli->active[rpmfiDIIndex(fi, i)] = 1;
308
309         /* Exclude parent directories that are explicitly included. */
310         for (i = 0; i < fc; i++) {
311             int dil;
312             size_t dnlen, bnlen;
313
314             if (!S_ISDIR(rpmfiFModeIndex(fi, i)))
315                 continue;
316
317             dil = rpmfiDIIndex(fi, i);
318             dnlen = strlen(rpmfiDNIndex(fi, dil));
319             bnlen = strlen(rpmfiBNIndex(fi, i));
320
321             for (j = 0; j < dc; j++) {
322                 const char * dnl;
323                 size_t jlen;
324
325                 if (!dnli->active[j] || j == dil)
326                     continue;
327                 dnl = rpmfiDNIndex(fi, j);
328                 jlen = strlen(dnl);
329                 if (jlen != (dnlen+bnlen+1))
330                     continue;
331                 if (!rstreqn(dnl, rpmfiDNIndex(fi, dil), dnlen))
332                     continue;
333                 if (!rstreqn(dnl+dnlen, rpmfiBNIndex(fi, i), bnlen))
334                     continue;
335                 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
336                     continue;
337                 /* This directory is included in the package. */
338                 dnli->active[j] = 0;
339                 break;
340             }
341         }
342
343         /* Print only once per package. */
344         if (!reverse) {
345             j = 0;
346             for (i = 0; i < dc; i++) {
347                 if (!dnli->active[i]) continue;
348                 if (j == 0) {
349                     j = 1;
350                     rpmlog(RPMLOG_DEBUG,
351         "========== Directories not explicitly included in package:\n");
352                 }
353                 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfiDNIndex(fi, i));
354             }
355             if (j)
356                 rpmlog(RPMLOG_DEBUG, "==========\n");
357         }
358     }
359     return dnli;
360 }
361
362 /** \ingroup payload
363  * Return next directory name (from file info).
364  * @param dnli          directory name iterator
365  * @return              next directory name
366  */
367 static
368 const char * dnlNextIterator(DNLI_t dnli)
369 {
370     const char * dn = NULL;
371
372     if (dnli) {
373         rpmfi fi = dnli->fi;
374         int dc = rpmfiDC(fi);
375         int i = -1;
376
377         if (dnli->active)
378         do {
379             i = (!dnli->reverse ? dnli->i++ : --dnli->i);
380         } while (i >= 0 && i < dc && !dnli->active[i]);
381
382         if (i >= 0 && i < dc)
383             dn = rpmfiDNIndex(fi, i);
384         else
385             i = -1;
386         dnli->isave = i;
387     }
388     return dn;
389 }
390
391 int fsmNext(FSM_t fsm, fileStage nstage)
392 {
393     fsm->nstage = nstage;
394     return fsmStage(fsm, fsm->nstage);
395 }
396
397 /**
398  * Map next file path and action.
399  * @param fsm           file state machine
400  */
401 static int fsmMapPath(FSM_t fsm)
402 {
403     rpmfi fi = fsmGetFi(fsm);   /* XXX const except for fstates */
404     int rc = 0;
405     int i;
406
407     fsm->osuffix = NULL;
408     fsm->nsuffix = NULL;
409     fsm->action = FA_UNKNOWN;
410
411     i = fsm->ix;
412     if (fi && i >= 0 && i < rpmfiFC(fi)) {
413         rpmte te = fsmGetTe(fsm);
414         rpmfs fs = rpmteGetFileStates(te);
415         /* XXX these should use rpmfiFFlags() etc */
416         fsm->action = rpmfsGetAction(fs, i);
417         fsm->fflags = rpmfiFFlagsIndex(fi, i);
418
419         /* src rpms have simple base name in payload. */
420         fsm->dirName = rpmfiDNIndex(fi, rpmfiDIIndex(fi, i));
421         fsm->baseName = rpmfiBNIndex(fi, i);
422
423         if (rpmteType(te) == TR_ADDED) {
424             switch (fsm->action) {
425             case FA_SKIPNSTATE:
426                 rpmfsSetState(fs, i, RPMFILE_STATE_NOTINSTALLED);
427                 break;
428             case FA_SKIPNETSHARED:
429                 rpmfsSetState(fs, i, RPMFILE_STATE_NETSHARED);
430                 break;
431             case FA_SKIPCOLOR:
432                 rpmfsSetState(fs, i, RPMFILE_STATE_WRONGCOLOR);
433                 break;
434             case FA_ALTNAME:
435                 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
436                     fsm->nsuffix = SUFFIX_RPMNEW;
437                 break;
438             case FA_SAVE:
439                 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
440                     fsm->osuffix = SUFFIX_RPMSAVE;
441                 break;
442             default:
443                 break;
444             }
445         }
446
447         if (fsm->action == FA_BACKUP && !(fsm->fflags & RPMFILE_GHOST)) {
448             /* XXX Don't if %ghost file. */
449             fsm->osuffix = (rpmteType(te) == TR_ADDED) ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE;
450         }
451
452         if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
453             const struct stat * st = &fsm->sb;
454             fsm->path = _free(fsm->path);
455             fsm->path = fsmFsPath(fsm, st, NULL,
456                 (fsm->suffix ? fsm->suffix : fsm->nsuffix));
457         }
458     }
459     return rc;
460 }
461
462 /** \ingroup payload
463  * Save hard link in chain.
464  * @param fsm           file state machine data
465  * @return              Is chain only partially filled?
466  */
467 static int saveHardLink(FSM_t fsm)
468 {
469     struct stat * st = &fsm->sb;
470     int rc = 0;
471     int ix = -1;
472     int j;
473
474     /* Find hard link set. */
475     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
476         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
477             break;
478     }
479
480     /* New hard link encountered, add new link to set. */
481     if (fsm->li == NULL) {
482         fsm->li = xcalloc(1, sizeof(*fsm->li));
483         fsm->li->next = NULL;
484         fsm->li->sb = *st;      /* structure assignment */
485         fsm->li->nlink = st->st_nlink;
486         fsm->li->linkIndex = fsm->ix;
487         fsm->li->createdPath = -1;
488
489         fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
490         memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
491         fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
492
493         if (fsm->goal == FSM_PKGBUILD)
494             fsm->li->linksLeft = st->st_nlink;
495         if (fsm->goal == FSM_PKGINSTALL)
496             fsm->li->linksLeft = 0;
497
498         fsm->li->next = fsm->links;
499         fsm->links = fsm->li;
500     }
501
502     if (fsm->goal == FSM_PKGBUILD) --fsm->li->linksLeft;
503     fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
504     fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
505     if (fsm->goal == FSM_PKGINSTALL) fsm->li->linksLeft++;
506
507     if (fsm->goal == FSM_PKGBUILD)
508         return (fsm->li->linksLeft > 0);
509
510     if (fsm->goal != FSM_PKGINSTALL)
511         return 0;
512
513     if (!(st->st_size || fsm->li->linksLeft == st->st_nlink))
514         return 1;
515
516     /* Here come the bits, time to choose a non-skipped file name. */
517     {   rpmfs fs = rpmteGetFileStates(fsmGetTe(fsm));
518
519         for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
520             ix = fsm->li->filex[j];
521             if (ix < 0 || XFA_SKIPPING(rpmfsGetAction(fs, ix)))
522                 continue;
523             break;
524         }
525     }
526
527     /* Are all links skipped or not encountered yet? */
528     if (ix < 0 || j < 0)
529         return 1;       /* XXX W2DO? */
530
531     /* Save the non-skipped file name and map index. */
532     fsm->li->linkIndex = j;
533     fsm->path = _free(fsm->path);
534     fsm->ix = ix;
535     rc = fsmMapPath(fsm);
536     return rc;
537 }
538
539 /** \ingroup payload
540  * Destroy set of hard links.
541  * @param li            set of hard links
542  * @return              NULL always
543  */
544 static hardLink_t freeHardLink(hardLink_t li)
545 {
546     if (li) {
547         li->nsuffix = _free(li->nsuffix);       /* XXX elements are shared */
548         li->filex = _free(li->filex);
549         _free(li);
550     }
551     return NULL;
552 }
553
554 /* forward declaration*/
555 static int fsmMkdirs(DNLI_t dnli, struct selabel_handle *sehandle);
556
557 static int fsmCreate(FSM_t fsm)
558 {
559     int rc = 0;
560     fsm->path = _free(fsm->path);
561
562     fsm->buf = _free(fsm->buf);
563     fsm->bufsize = 0;
564     if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
565         fsm->bufsize = 8 * BUFSIZ;
566         fsm->buf = xmalloc(fsm->bufsize);
567     }
568
569     fsm->ix = -1;
570     fsm->links = NULL;
571     fsm->li = NULL;
572     errno = 0;  /* XXX get rid of EBADF */
573
574     /* Detect and create directories not explicitly in package. */
575     /* XXX This seems like a strange place to do this... */
576     if (fsm->goal == FSM_PKGINSTALL) {
577         DNLI_t dnli = dnlInitIterator(fsm, 0);
578         rc = fsmMkdirs(dnli, fsm->sehandle);
579         dnlFreeIterator(dnli);  
580     }
581     return rc;
582 }
583
584 static int fsmSetup(FSM_t fsm, fileStage goal,
585                 rpmts ts, rpmte te, rpmfi fi, FD_t cfd, rpmpsm psm,
586                 rpm_loff_t * archiveSize, char ** failedFile)
587 {
588     int rc, ec = 0;
589     int isSrc = rpmteIsSource(te);
590
591     fsm->goal = goal;
592     if (cfd != NULL) {
593         fsm->cfd = fdLink(cfd);
594     }
595     fsm->iter = mapInitIterator(ts, te, fi);
596     fsm->psm = psm;
597     fsm->sehandle = rpmtsSELabelHandle(ts);
598
599     fsm->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
600     if (goal == FSM_PKGBUILD) {
601         fsm->mapFlags |= CPIO_MAP_TYPE;
602         if (isSrc) {
603             fsm->mapFlags |= CPIO_FOLLOW_SYMLINKS;
604         }
605         fsm->archive = rpmcpioOpen(cfd, O_WRONLY);
606     } else {
607         if (!isSrc) {
608             fsm->mapFlags |= CPIO_SBIT_CHECK;
609         }
610         fsm->archive = rpmcpioOpen(cfd, O_RDONLY);
611     }
612
613     fsm->archiveSize = archiveSize;
614     if (fsm->archiveSize)
615         *fsm->archiveSize = 0;
616     fsm->failedFile = failedFile;
617     if (fsm->failedFile)
618         *fsm->failedFile = NULL;
619
620     if (fsm->goal == FSM_PKGINSTALL) {
621         rasprintf(&fsm->suffix, ";%08x", (unsigned)rpmtsGetTid(ts));
622     }
623
624     ec = fsm->rc = 0;
625     rc = fsmCreate(fsm);
626     if (rc && !ec) ec = rc;
627
628     rc = fsmUNSAFE(fsm, fsm->goal);
629     if (rc && !ec) ec = rc;
630
631     if (fsm->archiveSize && ec == 0)
632         *fsm->archiveSize = rpmcpioTell(fsm->archive);
633
634 /* FIX: *fsm->failedFile may be NULL */
635    return ec;
636 }
637
638 static int fsmTeardown(FSM_t fsm)
639 {
640     int rc = fsm->rc;
641
642     if (!rc)
643         rc = fsmUNSAFE(fsm, FSM_DESTROY);
644
645     rc = rpmcpioClose(fsm->archive) || rc;
646
647     fsm->iter = mapFreeIterator(fsm->iter);
648     if (fsm->cfd != NULL) {
649         fsm->cfd = fdFree(fsm->cfd);
650         fsm->cfd = NULL;
651     }
652     fsm->failedFile = NULL;
653
654     fsm->path = _free(fsm->path);
655     fsm->suffix = _free(fsm->suffix);
656     while ((fsm->li = fsm->links) != NULL) {
657         fsm->links = fsm->li->next;
658         fsm->li->next = NULL;
659         fsm->li = freeHardLink(fsm->li);
660     }
661     return rc;
662 }
663
664 /* Find and set file security context */
665 static int fsmSetSELabel(struct selabel_handle *sehandle,
666                          const char *path, mode_t mode)
667 {
668     int rc = 0;
669 #if WITH_SELINUX
670     if (sehandle) {
671         security_context_t scon = NULL;
672
673         if (selabel_lookup_raw(sehandle, &scon, path, mode) == 0) {
674             rc = lsetfilecon(path, scon);
675
676             if (_fsm_debug && (FSM_LSETFCON & FSM_SYSCALL)) {
677                 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n",
678                         fileStageString(FSM_LSETFCON), path, scon,
679                         (rc < 0 ? strerror(errno) : ""));
680             }
681
682             if (rc < 0 && errno == EOPNOTSUPP)
683                 rc = 0;
684         }
685
686         freecon(scon);
687     }
688 #endif
689     return rc ? CPIOERR_LSETFCON_FAILED : 0;
690 }
691
692 static int fsmSetFCaps(const char *path, const char *captxt)
693 {
694     int rc = 0;
695 #if WITH_CAP
696     if (captxt && *captxt != '\0') {
697         cap_t fcaps = cap_from_text(captxt);
698         if (fcaps == NULL || cap_set_file(path, fcaps) != 0) {
699             rc = CPIOERR_SETCAP_FAILED;
700         }
701         cap_free(fcaps);
702     } 
703 #endif
704     return rc;
705 }
706
707 /**
708  * Map file stat(2) info.
709  * @param fsm           file state machine
710  */
711 static int fsmMapAttrs(FSM_t fsm)
712 {
713     struct stat * st = &fsm->sb;
714     rpmfi fi = fsmGetFi(fsm);
715     int i = fsm->ix;
716
717     /* this check is pretty moot,  rpmfi accessors check array bounds etc */
718     if (fi && i >= 0 && i < rpmfiFC(fi)) {
719         ino_t finalInode = rpmfiFInodeIndex(fi, i);
720         mode_t finalMode = rpmfiFModeIndex(fi, i);
721         dev_t finalRdev = rpmfiFRdevIndex(fi, i);
722         time_t finalMtime = rpmfiFMtimeIndex(fi, i);
723         const char *user = rpmfiFUserIndex(fi, i);
724         const char *group = rpmfiFGroupIndex(fi, i);
725         uid_t uid = 0;
726         gid_t gid = 0;
727
728         if (user && rpmugUid(user, &uid)) {
729             if (fsm->goal == FSM_PKGINSTALL)
730                 rpmlog(RPMLOG_WARNING,
731                     _("user %s does not exist - using root\n"), user);
732             finalMode &= ~S_ISUID;      /* turn off suid bit */
733         }
734
735         if (group && rpmugGid(group, &gid)) {
736             if (fsm->goal == FSM_PKGINSTALL)
737                 rpmlog(RPMLOG_WARNING,
738                     _("group %s does not exist - using root\n"), group);
739             finalMode &= ~S_ISGID;      /* turn off sgid bit */
740         }
741
742         if (fsm->mapFlags & CPIO_MAP_MODE)
743             st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
744         if (fsm->mapFlags & CPIO_MAP_TYPE) {
745             st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
746             if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
747             && st->st_nlink == 0)
748                 st->st_nlink = 1;
749             st->st_ino = finalInode;
750             st->st_rdev = finalRdev;
751             st->st_mtime = finalMtime;
752         }
753         if (fsm->mapFlags & CPIO_MAP_UID)
754             st->st_uid = uid;
755         if (fsm->mapFlags & CPIO_MAP_GID)
756             st->st_gid = gid;
757     }
758     return 0;
759 }
760
761 /** \ingroup payload
762  * Create file from payload stream.
763  * @param fsm           file state machine data
764  * @return              0 on success
765  */
766 static int expandRegular(FSM_t fsm)
767 {
768     FD_t wfd = NULL;
769     const struct stat * st = &fsm->sb;
770     rpm_loff_t left = st->st_size;
771     const unsigned char * fidigest = NULL;
772     pgpHashAlgo digestalgo = 0;
773     int rc = 0;
774
775     wfd = Fopen(fsm->path, "w.ufdio");
776     if (Ferror(wfd)) {
777         rc = CPIOERR_OPEN_FAILED;
778         goto exit;
779     }
780
781     if (!(rpmtsFlags(fsmGetTs(fsm)) & RPMTRANS_FLAG_NOFILEDIGEST)) {
782         rpmfi fi = fsmGetFi(fsm);
783         digestalgo = rpmfiDigestAlgo(fi);
784         fidigest = rpmfiFDigestIndex(fi, fsm->ix, NULL, NULL);
785     }
786
787     if (st->st_size > 0 && fidigest)
788         fdInitDigest(wfd, digestalgo, 0);
789
790     while (left) {
791         size_t len;
792         len = (left > fsm->bufsize ? fsm->bufsize : left);
793         if (rpmcpioRead(fsm->archive, fsm->buf, len) != len) {
794             rc = CPIOERR_READ_FAILED;
795             goto exit;
796         }
797         if ((Fwrite(fsm->buf, sizeof(*fsm->buf), len, wfd) != len) || Ferror(wfd)) {
798             rc = CPIOERR_WRITE_FAILED;
799             goto exit;
800         }
801
802         left -= len;
803
804         /* don't call this with fileSize == fileComplete */
805         if (!rc && left)
806             (void) fsmNext(fsm, FSM_NOTIFY);
807     }
808
809     if (st->st_size > 0 && fidigest) {
810         void * digest = NULL;
811
812         (void) Fflush(wfd);
813         fdFiniDigest(wfd, digestalgo, &digest, NULL, 0);
814
815         if (digest != NULL && fidigest != NULL) {
816             size_t diglen = rpmDigestLength(digestalgo);
817             if (memcmp(digest, fidigest, diglen)) {
818                 rc = CPIOERR_DIGEST_MISMATCH;
819             }
820         } else {
821             rc = CPIOERR_DIGEST_MISMATCH;
822         }
823         free(digest);
824     }
825
826 exit:
827     if (wfd) {
828         int myerrno = errno;
829         rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
830                  fdOp(wfd, FDSTAT_DIGEST));
831         Fclose(wfd);
832         errno = myerrno;
833     }
834     return rc;
835 }
836
837 static int fsmReadLink(const char *path,
838                        char *buf, size_t bufsize, size_t *linklen)
839 {
840     ssize_t llen = readlink(path, buf, bufsize - 1);
841     int rc = CPIOERR_READLINK_FAILED;
842
843     if (_fsm_debug && (FSM_READLINK & FSM_SYSCALL)) {
844         rpmlog(RPMLOG_DEBUG, " %8s (%s, buf, %d) %s\n",
845                fileStageString(FSM_READLINK),
846                path, (int)(bufsize -1), (llen < 0 ? strerror(errno) : ""));
847     }
848
849     if (llen >= 0) {
850         buf[llen] = '\0';
851         rc = 0;
852         *linklen = llen;
853     }
854     return rc;
855 }
856
857 /** \ingroup payload
858  * Write next item to payload stream.
859  * @param fsm           file state machine data
860  * @param writeData     should data be written?
861  * @return              0 on success
862  */
863 static int writeFile(FSM_t fsm, int writeData)
864 {
865     FD_t rfd = NULL;
866     char * path = fsm->path;
867     struct stat * st = &fsm->sb;
868     struct stat * ost = &fsm->osb;
869     char * symbuf = NULL;
870     rpm_loff_t left;
871     int rc = 0;
872
873     st->st_size = (writeData ? ost->st_size : 0);
874
875     if (S_ISDIR(st->st_mode)) {
876         st->st_size = 0;
877     } else if (S_ISLNK(st->st_mode)) {
878         /*
879          * While linux puts the size of a symlink in the st_size field,
880          * I don't think that's a specified standard.
881          */
882         size_t linklen;
883         rc = fsmReadLink(fsm->path, fsm->buf, fsm->bufsize, &linklen);
884         if (rc) goto exit;
885         st->st_size = linklen;
886         rstrcat(&symbuf, fsm->buf);     /* XXX save readlink return. */
887     }
888
889     if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) {
890         fsm->path = rstrscat(NULL, (fsm->mapFlags & CPIO_MAP_ADDDOT) ? "." : "",
891                                    fsm->dirName, fsm->baseName, NULL);
892     } else if (fsm->mapFlags & CPIO_MAP_PATH) {
893         rpmfi fi = fsmGetFi(fsm);
894         fsm->path = xstrdup((fi->apath ? fi->apath[fsm->ix] : 
895                                          rpmfiBNIndex(fi, fsm->ix)));
896     }
897
898     rc = rpmcpioHeaderWrite(fsm->archive, fsm->path, st);
899     _free(fsm->path);
900     fsm->path = path;
901
902     if (rc) goto exit;
903
904
905     if (writeData && S_ISREG(st->st_mode)) {
906         size_t len;
907 #ifdef HAVE_MMAP
908         char * buf = NULL;
909         void * mapped = MAP_FAILED;
910         size_t nmapped;
911         int xx;
912 #endif
913
914         rfd = Fopen(fsm->path, "r.ufdio");
915         if (Ferror(rfd)) {
916             rc = CPIOERR_OPEN_FAILED;
917             goto exit;
918         }
919         
920         /* XXX unbuffered mmap generates *lots* of fdio debugging */
921 #ifdef HAVE_MMAP
922         nmapped = 0;
923         mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(rfd), 0);
924         if (mapped != MAP_FAILED) {
925             buf = fsm->buf;
926             fsm->buf = (char *) mapped;
927             len = nmapped = st->st_size;
928 #if defined(MADV_DONTNEED)
929             xx = madvise(mapped, nmapped, MADV_DONTNEED);
930 #endif
931         }
932 #endif
933
934         left = st->st_size;
935
936         while (left) {
937 #ifdef HAVE_MMAP
938           if (mapped != MAP_FAILED) {
939             len = nmapped;
940           } else
941 #endif
942           {
943               len = (left > fsm->bufsize ? fsm->bufsize : left);
944               if (Fread(fsm->buf, sizeof(*fsm->buf), len, rfd) != len || Ferror(rfd)) {
945                   rc = CPIOERR_READ_FAILED;
946                   goto exit;
947               }
948           }
949
950           if (rpmcpioWrite(fsm->archive, fsm->buf, len) != len) {
951               rc = CPIOERR_WRITE_FAILED;
952               goto exit;
953           }
954           left -= len;
955         }
956
957 #ifdef HAVE_MMAP
958         if (mapped != MAP_FAILED) {
959             xx = msync(mapped, nmapped, MS_ASYNC);
960 #if defined(MADV_DONTNEED)
961             xx = madvise(mapped, nmapped, MADV_DONTNEED);
962 #endif
963             xx = munmap(mapped, nmapped);
964             fsm->buf = buf;
965         }
966 #endif
967
968     } else if (writeData && S_ISLNK(st->st_mode)) {
969         size_t len = strlen(symbuf);
970         if (rpmcpioWrite(fsm->archive, symbuf, len) != len) {
971             rc = CPIOERR_WRITE_FAILED;
972             goto exit;
973         }
974     }
975
976 exit:
977     if (rfd) {
978         /* preserve any prior errno across close */
979         int myerrno = errno;
980         rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
981                  fdOp(rfd, FDSTAT_DIGEST));
982         Fclose(rfd);
983         errno = myerrno;
984     }
985     fsm->path = path;
986     free(symbuf);
987     if (rc)
988         printf(rpmcpioStrerror(rc));
989     return rc;
990 }
991
992 /** \ingroup payload
993  * Write set of linked files to payload stream.
994  * @param fsm           file state machine data
995  * @return              0 on success
996  */
997 static int writeLinkedFile(FSM_t fsm)
998 {
999     char * path = fsm->path;
1000     const char * nsuffix = fsm->nsuffix;
1001     int iterIndex = fsm->ix;
1002     int ec = 0;
1003     int rc;
1004     int i;
1005
1006     fsm->path = NULL;
1007     fsm->nsuffix = NULL;
1008     fsm->ix = -1;
1009
1010     for (i = fsm->li->nlink - 1; i >= 0; i--) {
1011
1012         if (fsm->li->filex[i] < 0) continue;
1013
1014         fsm->ix = fsm->li->filex[i];
1015         rc = fsmMapPath(fsm);
1016
1017         /* Write data after last link. */
1018         rc = writeFile(fsm, (i == 0));
1019         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
1020             ec = rc;
1021             *fsm->failedFile = xstrdup(fsm->path);
1022         }
1023
1024         fsm->path = _free(fsm->path);
1025         fsm->li->filex[i] = -1;
1026     }
1027
1028     fsm->ix = iterIndex;
1029     fsm->nsuffix = nsuffix;
1030     fsm->path = path;
1031     return ec;
1032 }
1033
1034 static int writeLinks(FSM_t fsm)
1035 {
1036     int j, rc = 0;
1037     nlink_t i, nlink;
1038
1039     while ((fsm->li = fsm->links) != NULL) {
1040         fsm->links = fsm->li->next;
1041         fsm->li->next = NULL;
1042
1043         /* Re-calculate link count for archive header. */
1044         for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) {
1045             if (fsm->li->filex[i] < 0)
1046                 continue;
1047             nlink++;
1048             if (j == -1) j = i;
1049         }
1050         /* XXX force the contents out as well. */
1051         if (j != 0) {
1052             fsm->li->filex[0] = fsm->li->filex[j];
1053             fsm->li->filex[j] = -1;
1054         }
1055         fsm->li->sb.st_nlink = nlink;
1056
1057         fsm->sb = fsm->li->sb;  /* structure assignment */
1058         fsm->osb = fsm->sb;     /* structure assignment */
1059
1060         if (!rc) rc = writeLinkedFile(fsm);
1061
1062         fsm->li = freeHardLink(fsm->li);
1063     }
1064     return rc;
1065 }
1066
1067 static int fsmStat(const char *path, int dolstat, struct stat *sb)
1068 {
1069     int rc;
1070     if (dolstat){
1071         rc = lstat(path, sb);
1072     } else {
1073         rc = stat(path, sb);
1074     }
1075     if (_fsm_debug && (FSM_STAT & FSM_SYSCALL) && rc && errno != ENOENT)
1076         rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n",
1077                fileStageString(dolstat ? FSM_LSTAT : FSM_STAT),
1078                path, (rc < 0 ? strerror(errno) : ""));
1079     if (rc < 0) {
1080         rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_LSTAT_FAILED);
1081         /* WTH is this, and is it really needed, still? */
1082         memset(sb, 0, sizeof(*sb));     /* XXX s390x hackery */
1083     }
1084     return rc;
1085 }
1086
1087 static int fsmVerify(FSM_t fsm);
1088
1089 /** \ingroup payload
1090  * Create pending hard links to existing file.
1091  * @param fsm           file state machine data
1092  * @return              0 on success
1093  */
1094 static int fsmMakeLinks(FSM_t fsm)
1095 {
1096     char * path = fsm->path;
1097     char * opath = NULL;
1098     const char * nsuffix = fsm->nsuffix;
1099     int iterIndex = fsm->ix;
1100     int ec = 0;
1101     int rc;
1102     int i;
1103
1104     fsm->path = NULL;
1105     fsm->nsuffix = NULL;
1106     fsm->ix = -1;
1107
1108     fsm->ix = fsm->li->filex[fsm->li->createdPath];
1109     rc = fsmMapPath(fsm);
1110     opath = fsm->path;
1111     fsm->path = NULL;
1112     for (i = 0; i < fsm->li->nlink; i++) {
1113         if (fsm->li->filex[i] < 0) continue;
1114         if (fsm->li->createdPath == i) continue;
1115
1116         fsm->ix = fsm->li->filex[i];
1117         fsm->path = _free(fsm->path);
1118         rc = fsmMapPath(fsm);
1119         if (XFA_SKIPPING(fsm->action)) continue;
1120
1121         rc = fsmVerify(fsm);
1122         if (!rc) continue;
1123         if (!(rc == CPIOERR_ENOENT)) break;
1124
1125         /* XXX link(opath, fsm->path) */
1126         rc = link(opath, fsm->path);
1127         if (_fsm_debug && (FSM_LINK & FSM_SYSCALL))
1128             rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", fileStageString(FSM_LINK),
1129                 opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
1130         if (rc < 0)     rc = CPIOERR_LINK_FAILED;
1131
1132         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
1133             ec = rc;
1134             *fsm->failedFile = xstrdup(fsm->path);
1135         }
1136
1137         fsm->li->linksLeft--;
1138     }
1139     fsm->path = _free(fsm->path);
1140     free(opath);
1141
1142     fsm->ix = iterIndex;
1143     fsm->nsuffix = nsuffix;
1144     fsm->path = path;
1145     return ec;
1146 }
1147
1148 /** \ingroup payload
1149  * Commit hard linked file set atomically.
1150  * @param fsm           file state machine data
1151  * @return              0 on success
1152  */
1153 static int fsmCommitLinks(FSM_t fsm)
1154 {
1155     char * path = fsm->path;
1156     const char * nsuffix = fsm->nsuffix;
1157     int iterIndex = fsm->ix;
1158     struct stat * st = &fsm->sb;
1159     int rc = 0;
1160     nlink_t i;
1161
1162     fsm->path = NULL;
1163     fsm->nsuffix = NULL;
1164     fsm->ix = -1;
1165
1166     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
1167         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
1168             break;
1169     }
1170
1171     for (i = 0; i < fsm->li->nlink; i++) {
1172         if (fsm->li->filex[i] < 0) continue;
1173         fsm->ix = fsm->li->filex[i];
1174         rc = fsmMapPath(fsm);
1175         if (!XFA_SKIPPING(fsm->action))
1176             rc = fsmNext(fsm, FSM_COMMIT);
1177         fsm->path = _free(fsm->path);
1178         fsm->li->filex[i] = -1;
1179     }
1180
1181     fsm->ix = iterIndex;
1182     fsm->nsuffix = nsuffix;
1183     fsm->path = path;
1184     return rc;
1185 }
1186
1187 static int fsmRmdir(const char *path)
1188 {
1189     int rc = rmdir(path);
1190     if (_fsm_debug && (FSM_RMDIR & FSM_SYSCALL))
1191         rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", fileStageString(FSM_RMDIR),
1192                path, (rc < 0 ? strerror(errno) : ""));
1193     if (rc < 0)
1194         switch (errno) {
1195         case ENOENT:        rc = CPIOERR_ENOENT;    break;
1196         case ENOTEMPTY:     rc = CPIOERR_ENOTEMPTY; break;
1197         default:            rc = CPIOERR_RMDIR_FAILED; break;
1198         }
1199     return rc;
1200 }
1201
1202 static int fsmMkdir(const char *path, mode_t mode)
1203 {
1204     int rc = mkdir(path, (mode & 07777));
1205     if (_fsm_debug && (FSM_MKDIR & FSM_SYSCALL))
1206         rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", fileStageString(FSM_MKDIR),
1207                path, (unsigned)(mode & 07777),
1208                (rc < 0 ? strerror(errno) : ""));
1209     if (rc < 0) rc = CPIOERR_MKDIR_FAILED;
1210     return rc;
1211 }
1212
1213 static int fsmMkfifo(const char *path, mode_t mode)
1214 {
1215     int rc = mkfifo(path, (mode & 07777));
1216
1217     if (_fsm_debug && (FSM_MKFIFO & FSM_SYSCALL)) {
1218         rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n",
1219                fileStageString(FSM_MKFIFO), path, (unsigned)(mode & 07777),
1220                (rc < 0 ? strerror(errno) : ""));
1221     }
1222
1223     if (rc < 0)
1224         rc = CPIOERR_MKFIFO_FAILED;
1225
1226     return rc;
1227 }
1228
1229 static int fsmMknod(const char *path, mode_t mode, dev_t dev)
1230 {
1231     /* FIX: check S_IFIFO or dev != 0 */
1232     int rc = mknod(path, (mode & ~07777), dev);
1233
1234     if (_fsm_debug && (FSM_MKNOD & FSM_SYSCALL)) {
1235         rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n",
1236                fileStageString(FSM_MKNOD), path, (unsigned)(mode & ~07777),
1237                (unsigned)dev, (rc < 0 ? strerror(errno) : ""));
1238     }
1239
1240     if (rc < 0)
1241         rc = CPIOERR_MKNOD_FAILED;
1242
1243     return rc;
1244 }
1245
1246 /**
1247  * Create (if necessary) directories not explicitly included in package.
1248  * @param dnli          file state machine data
1249  * @param sehandle      selinux label handle (bah)
1250  * @return              0 on success
1251  */
1252 static int fsmMkdirs(DNLI_t dnli, struct selabel_handle *sehandle)
1253 {
1254     struct stat sb;
1255     const char *dpath;
1256     int dc = dnlCount(dnli);
1257     int rc = 0;
1258     int i;
1259     int ldnlen = 0;
1260     int ldnalloc = 0;
1261     char * ldn = NULL;
1262     short * dnlx = NULL; 
1263
1264     dnlx = (dc ? xcalloc(dc, sizeof(*dnlx)) : NULL);
1265
1266     if (dnlx != NULL)
1267     while ((dpath = dnlNextIterator(dnli)) != NULL) {
1268         size_t dnlen = strlen(dpath);
1269         char * te, dn[dnlen+1];
1270
1271         dc = dnlIndex(dnli);
1272         if (dc < 0) continue;
1273         dnlx[dc] = dnlen;
1274         if (dnlen <= 1)
1275             continue;
1276
1277         if (dnlen <= ldnlen && rstreq(dpath, ldn))
1278             continue;
1279
1280         /* Copy as we need to modify the string */
1281         (void) stpcpy(dn, dpath);
1282
1283         /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
1284         for (i = 1, te = dn + 1; *te != '\0'; te++, i++) {
1285             if (*te != '/')
1286                 continue;
1287
1288             *te = '\0';
1289
1290             /* Already validated? */
1291             if (i < ldnlen &&
1292                 (ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i))
1293             {
1294                 *te = '/';
1295                 /* Move pre-existing path marker forward. */
1296                 dnlx[dc] = (te - dn);
1297                 continue;
1298             }
1299
1300             /* Validate next component of path. */
1301             rc = fsmStat(dn, 1, &sb); /* lstat */
1302             *te = '/';
1303
1304             /* Directory already exists? */
1305             if (rc == 0 && S_ISDIR(sb.st_mode)) {
1306                 /* Move pre-existing path marker forward. */
1307                 dnlx[dc] = (te - dn);
1308             } else if (rc == CPIOERR_ENOENT) {
1309                 *te = '\0';
1310                 mode_t mode = S_IFDIR | (_dirPerms & 07777);
1311                 rc = fsmMkdir(dn, mode);
1312                 if (!rc) {
1313                     rc = fsmSetSELabel(sehandle, dn, mode);
1314
1315                     rpmlog(RPMLOG_DEBUG,
1316                             "%s directory created with perms %04o\n",
1317                             dn, (unsigned)(mode & 07777));
1318                 }
1319                 *te = '/';
1320             }
1321             if (rc)
1322                 break;
1323         }
1324         if (rc) break;
1325
1326         /* Save last validated path. */
1327         if (ldnalloc < (dnlen + 1)) {
1328             ldnalloc = dnlen + 100;
1329             ldn = xrealloc(ldn, ldnalloc);
1330         }
1331         if (ldn != NULL) { /* XXX can't happen */
1332             strcpy(ldn, dn);
1333             ldnlen = dnlen;
1334         }
1335     }
1336     free(dnlx);
1337     free(ldn);
1338
1339     return rc;
1340 }
1341
1342 static void removeSBITS(const char *path)
1343 {
1344     struct stat stb;
1345     if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) {
1346         if ((stb.st_mode & 06000) != 0) {
1347             (void) chmod(path, stb.st_mode & 0777);
1348         }
1349 #if WITH_CAP
1350         if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
1351             (void) cap_set_file(path, NULL);
1352         }
1353 #endif
1354     }
1355 }
1356
1357 /********************************************************************/
1358
1359 static int fsmInit(FSM_t fsm)
1360 {
1361     int rc = 0;
1362
1363     fsm->path = _free(fsm->path);
1364     fsm->postpone = 0;
1365     fsm->diskchecked = fsm->exists = 0;
1366     fsm->action = FA_UNKNOWN;
1367     fsm->osuffix = NULL;
1368     fsm->nsuffix = NULL;
1369
1370     if (fsm->goal == FSM_PKGINSTALL) {
1371         /* Read next header from payload, checking for end-of-payload. */
1372         rc = fsmUNSAFE(fsm, FSM_NEXT);
1373     }
1374     if (rc) return rc;
1375
1376     /* Identify mapping index. */
1377     fsm->ix = ((fsm->goal == FSM_PKGINSTALL)
1378                ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
1379
1380     /* Detect end-of-loop and/or mapping error. */
1381     if (fsm->ix < 0) {
1382         if (fsm->goal == FSM_PKGINSTALL) {
1383 #if 0
1384             rpmlog(RPMLOG_WARNING,
1385                    _("archive file %s was not found in header file list\n"),
1386                    fsm->path);
1387 #endif
1388             if (fsm->failedFile && *fsm->failedFile == NULL)
1389                 *fsm->failedFile = xstrdup(fsm->path);
1390             rc = CPIOERR_UNMAPPED_FILE;
1391         } else {
1392             rc = CPIOERR_HDR_TRAILER;
1393         }
1394         return rc;
1395     }
1396
1397     /* On non-install, mode must be known so that dirs don't get suffix. */
1398     if (fsm->goal != FSM_PKGINSTALL) {
1399         rpmfi fi = fsmGetFi(fsm);
1400         fsm->sb.st_mode = rpmfiFModeIndex(fi, fsm->ix);
1401     }
1402
1403     /* Generate file path. */
1404     rc = fsmMapPath(fsm);
1405     if (rc) return rc;
1406
1407     /* Perform lstat/stat for disk file. */
1408     if (fsm->path != NULL &&
1409         !(fsm->goal == FSM_PKGINSTALL && S_ISREG(fsm->sb.st_mode)))
1410     {
1411         int dolstat = !(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS);
1412         rc = fsmStat(fsm->path, dolstat, &fsm->osb);
1413         if (rc == CPIOERR_ENOENT) {
1414             // errno = saveerrno; XXX temporary commented out
1415             rc = 0;
1416             fsm->exists = 0;
1417         } else if (rc == 0) {
1418             fsm->exists = 1;
1419         }
1420     } else {
1421         /* Skip %ghost files on build. */
1422         fsm->exists = 0;
1423     }
1424     fsm->diskchecked = 1;
1425     if (rc) return rc;
1426
1427     /* On non-install, the disk file stat is what's remapped. */
1428     if (fsm->goal != FSM_PKGINSTALL)
1429         fsm->sb = fsm->osb;                     /* structure assignment */
1430
1431     /* Remap file perms, owner, and group. */
1432     rc = fsmMapAttrs(fsm);
1433     if (rc) return rc;
1434
1435     fsm->postpone = XFA_SKIPPING(fsm->action);
1436     if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
1437         /* FIX: saveHardLink can modify fsm */
1438         if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
1439             fsm->postpone = saveHardLink(fsm);
1440     }
1441     return rc;
1442
1443 }
1444
1445 static int fsmSymlink(const char *opath, const char *path)
1446 {
1447     int rc = symlink(opath, path);
1448
1449     if (_fsm_debug && (FSM_SYMLINK & FSM_SYSCALL)) {
1450         rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", fileStageString(FSM_SYMLINK),
1451                opath, path, (rc < 0 ? strerror(errno) : ""));
1452     }
1453
1454     if (rc < 0)
1455         rc = CPIOERR_SYMLINK_FAILED;
1456     return rc;
1457 }
1458
1459 static int fsmUnlink(const char *path, cpioMapFlags mapFlags)
1460 {
1461     int rc = 0;
1462     if (mapFlags & CPIO_SBIT_CHECK)
1463         removeSBITS(path);
1464     rc = unlink(path);
1465     if (_fsm_debug && (FSM_UNLINK & FSM_SYSCALL))
1466         rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", fileStageString(FSM_UNLINK),
1467                path, (rc < 0 ? strerror(errno) : ""));
1468     if (rc < 0)
1469         rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_UNLINK_FAILED);
1470     return rc;
1471 }
1472
1473 static int fsmRename(const char *opath, const char *path,
1474                      cpioMapFlags mapFlags)
1475 {
1476     if (mapFlags & CPIO_SBIT_CHECK)
1477         removeSBITS(path);
1478     int rc = rename(opath, path);
1479 #if defined(ETXTBSY) && defined(__HPUX__)
1480     /* XXX HP-UX (and other os'es) don't permit rename to busy files. */
1481     if (rc && errno == ETXTBSY) {
1482         char *rmpath = NULL;
1483         rstrscat(&rmpath, path, "-RPMDELETE", NULL);
1484         rc = rename(path, rmpath);
1485         if (!rc) rc = rename(opath, path);
1486         free(rmpath);
1487     }
1488 #endif
1489     if (_fsm_debug && (FSM_RENAME & FSM_SYSCALL))
1490         rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", fileStageString(FSM_RENAME),
1491                opath, path, (rc < 0 ? strerror(errno) : ""));
1492     if (rc < 0) rc = CPIOERR_RENAME_FAILED;
1493     return rc;
1494 }
1495
1496
1497 static int fsmChown(const char *path, uid_t uid, gid_t gid)
1498 {
1499     int rc = chown(path, uid, gid);
1500     if (rc < 0) {
1501         struct stat st;
1502         if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
1503             rc = 0;
1504     }
1505     if (_fsm_debug && (FSM_CHOWN & FSM_SYSCALL))
1506         rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", fileStageString(FSM_CHOWN),
1507                path, (int)uid, (int)gid,
1508                (rc < 0 ? strerror(errno) : ""));
1509     if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
1510     return rc;
1511 }
1512
1513 static int fsmLChown(const char *path, uid_t uid, gid_t gid)
1514 {
1515     int rc = lchown(path, uid, gid);
1516     if (rc < 0) {
1517         struct stat st;
1518         if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
1519             rc = 0;
1520     }
1521     if (_fsm_debug && (FSM_LCHOWN & FSM_SYSCALL))
1522         rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", fileStageString(FSM_LCHOWN),
1523                path, (int)uid, (int)gid,
1524                (rc < 0 ? strerror(errno) : ""));
1525     if (rc < 0) rc = CPIOERR_CHOWN_FAILED;
1526     return rc;
1527 }
1528
1529 static int fsmChmod(const char *path, mode_t mode)
1530 {
1531     int rc = chmod(path, (mode & 07777));
1532     if (rc < 0) {
1533         struct stat st;
1534         if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777))
1535             rc = 0;
1536     }
1537     if (_fsm_debug && (FSM_CHMOD & FSM_SYSCALL))
1538         rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", fileStageString(FSM_CHMOD),
1539                path, (unsigned)(mode & 07777),
1540                (rc < 0 ? strerror(errno) : ""));
1541     if (rc < 0) rc = CPIOERR_CHMOD_FAILED;
1542     return rc;
1543 }
1544
1545 static int fsmUtime(const char *path, time_t mtime)
1546 {
1547     int rc = 0;
1548     struct utimbuf stamp;
1549     stamp.actime = mtime;
1550     stamp.modtime = mtime;
1551     rc = utime(path, &stamp);
1552     if (_fsm_debug && (FSM_UTIME & FSM_SYSCALL))
1553         rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", fileStageString(FSM_UTIME),
1554                path, (unsigned)mtime, (rc < 0 ? strerror(errno) : ""));
1555     if (rc < 0) rc = CPIOERR_UTIME_FAILED;
1556     return rc;
1557 }
1558
1559 static int fsmVerify(FSM_t fsm)
1560 {
1561     int rc;
1562     struct stat * st = &fsm->sb;
1563     struct stat * ost = &fsm->osb;
1564     int saveerrno = errno;
1565
1566     if (fsm->diskchecked && !fsm->exists) {
1567         return CPIOERR_ENOENT;
1568     }
1569     if (S_ISREG(st->st_mode)) {
1570         /* HP-UX (and other os'es) don't permit unlink on busy files. */
1571         char *rmpath = rstrscat(NULL, fsm->path, "-RPMDELETE", NULL);
1572         rc = fsmRename(fsm->path, rmpath, fsm->mapFlags);
1573         /* XXX shouldn't we take unlink return code here? */
1574         if (!rc)
1575             (void) fsmUnlink(rmpath, fsm->mapFlags);
1576         else
1577             rc = CPIOERR_UNLINK_FAILED;
1578         free(rmpath);
1579         return (rc ? rc : CPIOERR_ENOENT);      /* XXX HACK */
1580     } else if (S_ISDIR(st->st_mode)) {
1581         if (S_ISDIR(ost->st_mode)) return 0;
1582         if (S_ISLNK(ost->st_mode)) {
1583             rc = fsmStat(fsm->path, 0, &fsm->osb);
1584             if (rc == CPIOERR_ENOENT) rc = 0;
1585             if (rc) return rc;
1586             errno = saveerrno;
1587             if (S_ISDIR(ost->st_mode)) return 0;
1588         }
1589     } else if (S_ISLNK(st->st_mode)) {
1590         if (S_ISLNK(ost->st_mode)) {
1591             char buf[8 * BUFSIZ];
1592             size_t len;
1593             rc = fsmReadLink(fsm->path, buf, 8 * BUFSIZ, &len);
1594             errno = saveerrno;
1595             if (rc) return rc;
1596             /* FSM_PROCESS puts link target to fsm->buf. */
1597             if (rstreq(fsm->buf, buf)) return 0;
1598         }
1599     } else if (S_ISFIFO(st->st_mode)) {
1600         if (S_ISFIFO(ost->st_mode)) return 0;
1601     } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
1602         if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
1603             (ost->st_rdev == st->st_rdev)) return 0;
1604     } else if (S_ISSOCK(st->st_mode)) {
1605         if (S_ISSOCK(ost->st_mode)) return 0;
1606     }
1607     /* XXX shouldn't do this with commit/undo. */
1608     rc = 0;
1609     if (fsm->stage == FSM_PROCESS) rc = fsmUnlink(fsm->path, fsm->mapFlags);
1610     if (rc == 0)        rc = CPIOERR_ENOENT;
1611     return (rc ? rc : CPIOERR_ENOENT);  /* XXX HACK */
1612 }
1613
1614 /********************************************************************/
1615
1616 #define IS_DEV_LOG(_x)  \
1617         ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
1618         rstreqn((_x), "/dev/log", sizeof("/dev/log")-1) && \
1619         ((_x)[sizeof("/dev/log")-1] == '\0' || \
1620          (_x)[sizeof("/dev/log")-1] == ';'))
1621
1622 /**
1623  * File state machine driver.
1624  * @param fsm           file state machine
1625  * @param stage         next stage
1626  * @return              0 on success
1627  */
1628 static int fsmStage(FSM_t fsm, fileStage stage)
1629 {
1630     const char * const cur = fileStageString(stage);
1631     struct stat * st = &fsm->sb;
1632     struct stat * ost = &fsm->osb;
1633     int saveerrno = errno;
1634     int rc = fsm->rc;
1635
1636 #define _fafilter(_a)   \
1637     (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
1638         ? fileActionString(_a) : "")
1639
1640     if (stage & FSM_DEAD) {
1641         /* do nothing */
1642     } else if (stage & FSM_INTERNAL) {
1643         if (_fsm_debug && !(stage & FSM_SYSCALL))
1644             rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%10d %s %s\n",
1645                 cur,
1646                 (unsigned)st->st_mode, (int)st->st_nlink,
1647                 (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
1648                 (fsm->path ? fsm->path : ""),
1649                 _fafilter(fsm->action));
1650     } else {
1651         fsm->stage = stage;
1652         if (_fsm_debug || !(stage & FSM_VERBOSE))
1653             rpmlog(RPMLOG_DEBUG, "%-8s  %06o%3d (%4d,%4d)%10d %s %s\n",
1654                 cur,
1655                 (unsigned)st->st_mode, (int)st->st_nlink,
1656                 (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
1657                 (fsm->path ? fsm->path : ""),
1658                 _fafilter(fsm->action));
1659     }
1660 #undef  _fafilter
1661
1662     switch (stage) {
1663     case FSM_UNKNOWN:
1664         break;
1665     case FSM_PKGINSTALL:
1666         while (1) {
1667             /* Clean fsm, free'ing memory. Read next archive header. */
1668             rc = fsmInit(fsm);
1669
1670             /* Exit on end-of-payload. */
1671             if (rc == CPIOERR_HDR_TRAILER) {
1672                 rc = 0;
1673                 break;
1674             }
1675
1676             /* Exit on error. */
1677             if (rc) {
1678                 fsm->postpone = 1;
1679                 (void) fsmNext(fsm, FSM_UNDO);
1680                 break;
1681             }
1682
1683             /* Extract file from archive. */
1684             rc = fsmNext(fsm, FSM_PROCESS);
1685             if (rc) {
1686                 (void) fsmNext(fsm, FSM_UNDO);
1687                 break;
1688             }
1689
1690             /* Notify on success. */
1691             (void) fsmNext(fsm, FSM_NOTIFY);
1692
1693             rc = fsmNext(fsm, FSM_FINI);
1694             if (rc) {
1695                 break;
1696             }
1697         }
1698         break;
1699     case FSM_PKGERASE:
1700         while (1) {
1701             /* Clean fsm, free'ing memory. */
1702             rc = fsmInit(fsm);
1703
1704             /* Exit on end-of-payload. */
1705             if (rc == CPIOERR_HDR_TRAILER) {
1706                 rc = 0;
1707                 break;
1708             }
1709
1710             /* Rename/erase next item. */
1711             if (fsmNext(fsm, FSM_FINI))
1712                 break;
1713
1714             /* Notify on success. */
1715             (void) fsmNext(fsm, FSM_NOTIFY);
1716         }
1717         break;
1718     case FSM_PKGBUILD:
1719         while (1) {
1720
1721             rc = fsmInit(fsm);
1722
1723             /* Exit on end-of-payload. */
1724             if (rc == CPIOERR_HDR_TRAILER) {
1725                 rc = 0;
1726                 break;
1727             }
1728
1729             /* Exit on error. */
1730             if (rc) {
1731                 fsm->postpone = 1;
1732                 (void) fsmNext(fsm, FSM_UNDO);
1733                 break;
1734             }
1735
1736             /* Copy file into archive. */
1737             rc = fsmNext(fsm, FSM_PROCESS);
1738             if (rc) {
1739                 (void) fsmNext(fsm, FSM_UNDO);
1740                 break;
1741             }
1742
1743             if (fsmNext(fsm, FSM_FINI))
1744                 break;
1745         }
1746
1747         /* Flush partial sets of hard linked files. */
1748         rc = writeLinks(fsm);
1749
1750         break;
1751     case FSM_PROCESS:
1752         if (fsm->postpone) {
1753             break;
1754         }
1755
1756         if (fsm->goal == FSM_PKGBUILD) {
1757             if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
1758                 break;
1759             /* Hardlinks are handled later */
1760             if (!(S_ISREG(st->st_mode) && st->st_nlink > 1)) {
1761                 rc = writeFile(fsm, 1);
1762             }
1763             break;
1764         }
1765
1766         if (fsm->goal != FSM_PKGINSTALL)
1767             break;
1768
1769         if (S_ISREG(st->st_mode)) {
1770             char * path = fsm->path;
1771             if (fsm->osuffix)
1772                 fsm->path = fsmFsPath(fsm, st, NULL, NULL);
1773             rc = fsmVerify(fsm);
1774
1775             if (rc == 0 && fsm->osuffix) {
1776                 char * spath = fsmFsPath(fsm, st, NULL, fsm->osuffix);
1777                 rc = fsmRename(fsm->path, spath, fsm->mapFlags);
1778                 if (!rc)
1779                     rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"),
1780                            fsm->path, spath);
1781                 free(spath);
1782             }
1783
1784             if (fsm->osuffix)
1785                 free(fsm->path);
1786
1787             fsm->path = path;
1788             if (!(rc == CPIOERR_ENOENT)) return rc;
1789             rc = expandRegular(fsm);
1790         } else if (S_ISDIR(st->st_mode)) {
1791             rc = fsmVerify(fsm);
1792             if (rc == CPIOERR_ENOENT) {
1793                 mode_t mode = st->st_mode;
1794                 mode &= ~07777;
1795                 mode |=  00700;
1796                 rc = fsmMkdir(fsm->path, mode);
1797             }
1798         } else if (S_ISLNK(st->st_mode)) {
1799             if ((st->st_size + 1) > fsm->bufsize) {
1800                 rc = CPIOERR_HDR_SIZE;
1801                 break;
1802             }
1803
1804             if (rpmcpioRead(fsm->archive, fsm->buf, st->st_size) != st->st_size) {
1805                 rc = CPIOERR_READ_FAILED;
1806                 break;
1807             }
1808
1809             fsm->buf[st->st_size] = '\0';
1810             /* fsmVerify() assumes link target in fsm->buf */
1811             rc = fsmVerify(fsm);
1812             if (rc == CPIOERR_ENOENT) {
1813                 rc = fsmSymlink(fsm->buf, fsm->path);
1814             }
1815         } else if (S_ISFIFO(st->st_mode)) {
1816             /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
1817             rc = fsmVerify(fsm);
1818             if (rc == CPIOERR_ENOENT) {
1819                 rc = fsmMkfifo(fsm->path, 0000);
1820             }
1821         } else if (S_ISCHR(st->st_mode) ||
1822                    S_ISBLK(st->st_mode) ||
1823     S_ISSOCK(st->st_mode))
1824         {
1825             rc = fsmVerify(fsm);
1826             if (rc == CPIOERR_ENOENT) {
1827                 rc = fsmMknod(fsm->path, fsm->sb.st_mode, fsm->sb.st_rdev);
1828             }
1829         } else {
1830             /* XXX Special case /dev/log, which shouldn't be packaged anyways */
1831             if (!IS_DEV_LOG(fsm->path))
1832                 rc = CPIOERR_UNKNOWN_FILETYPE;
1833         }
1834         if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
1835             fsm->li->createdPath = fsm->li->linkIndex;
1836             rc = fsmMakeLinks(fsm);
1837         }
1838         break;
1839     case FSM_POST:
1840         break;
1841     case FSM_NOTIFY:            /* XXX move from fsm to psm -> tsm */
1842         if (fsm->goal == FSM_PKGINSTALL) {
1843             rpmpsmNotify(fsm->psm, RPMCALLBACK_INST_PROGRESS, rpmcpioTell(fsm->archive));
1844         } else if (fsm->goal == FSM_PKGERASE) {
1845             /* On erase we're iterating backwards, fixup for progress */
1846             rpm_loff_t amount = (fsm->ix >= 0) ?
1847                                 rpmfiFC(fsmGetFi(fsm)) - fsm->ix : 0;
1848             rpmpsmNotify(fsm->psm, RPMCALLBACK_UNINST_PROGRESS, amount);
1849         }
1850         break;
1851     case FSM_UNDO:
1852         if (fsm->postpone)
1853             break;
1854         if (fsm->goal == FSM_PKGINSTALL) {
1855             /* XXX only erase if temp fn w suffix is in use */
1856             if (fsm->suffix) {
1857                 if (S_ISDIR(st->st_mode)) {
1858                     (void) fsmRmdir(fsm->path);
1859                 } else {
1860                     (void) fsmUnlink(fsm->path, fsm->mapFlags);
1861                 }
1862             }
1863             errno = saveerrno;
1864         }
1865         if (fsm->failedFile && *fsm->failedFile == NULL)
1866             *fsm->failedFile = xstrdup(fsm->path);
1867         break;
1868     case FSM_FINI:
1869         if (!fsm->postpone) {
1870             if (fsm->goal == FSM_PKGINSTALL)
1871                 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
1872                         ? fsmCommitLinks(fsm) : fsmNext(fsm, FSM_COMMIT));
1873             if (fsm->goal == FSM_PKGERASE)
1874                 rc = fsmNext(fsm, FSM_COMMIT);
1875         }
1876         fsm->path = _free(fsm->path);
1877         memset(st, 0, sizeof(*st));
1878         memset(ost, 0, sizeof(*ost));
1879         break;
1880     case FSM_COMMIT:
1881         /* Rename pre-existing modified or unmanaged file. */
1882         if (fsm->osuffix && fsm->diskchecked &&
1883           (fsm->exists || (fsm->goal == FSM_PKGINSTALL && S_ISREG(st->st_mode))))
1884         {
1885             char * opath = fsmFsPath(fsm, st, NULL, NULL);
1886             char * path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
1887             rc = fsmRename(opath, path, fsm->mapFlags);
1888             if (!rc) {
1889                 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path);
1890             }
1891             free(path);
1892             free(opath);
1893         }
1894
1895         /* Remove erased files. */
1896         if (fsm->goal == FSM_PKGERASE) {
1897             if (fsm->action == FA_ERASE) {
1898                 rpmte te = fsmGetTe(fsm);
1899                 if (S_ISDIR(st->st_mode)) {
1900                     rc = fsmRmdir(fsm->path);
1901                     if (!rc) break;
1902                     switch (rc) {
1903                     case CPIOERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
1904                     case CPIOERR_ENOTEMPTY:
1905         /* XXX make sure that build side permits %missingok on directories. */
1906                         if (fsm->fflags & RPMFILE_MISSINGOK)
1907                             break;
1908
1909                         /* XXX common error message. */
1910                         rpmlog(
1911                             (strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
1912                             _("%s rmdir of %s failed: Directory not empty\n"), 
1913                                 rpmteTypeString(te), fsm->path);
1914                         break;
1915                     default:
1916                         rpmlog(
1917                             (strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
1918                                 _("%s rmdir of %s failed: %s\n"),
1919                                 rpmteTypeString(te), fsm->path, strerror(errno));
1920                         break;
1921                     }
1922                 } else {
1923                     rc = fsmUnlink(fsm->path, fsm->mapFlags);
1924                     if (!rc) break;
1925                     switch (rc) {
1926                     case CPIOERR_ENOENT:
1927                         if (fsm->fflags & RPMFILE_MISSINGOK)
1928                             break;
1929                     default:
1930                         rpmlog(
1931                             (strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
1932                                 _("%s unlink of %s failed: %s\n"),
1933                                 rpmteTypeString(te), fsm->path, strerror(errno));
1934                         break;
1935                     }
1936                 }
1937             }
1938             /* XXX Failure to remove is not (yet) cause for failure. */
1939             if (!strict_erasures) rc = 0;
1940             break;
1941         }
1942
1943         /* XXX Special case /dev/log, which shouldn't be packaged anyways */
1944         if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
1945             /* Rename temporary to final file name. */
1946             if (!S_ISDIR(st->st_mode) && (fsm->suffix || fsm->nsuffix)) {
1947                 char *npath = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
1948                 rc = fsmRename(fsm->path, npath, fsm->mapFlags);
1949                 if (!rc && fsm->nsuffix) {
1950                     char * opath = fsmFsPath(fsm, st, NULL, NULL);
1951                     rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
1952                            opath, npath);
1953                     free(opath);
1954                 }
1955                 free(fsm->path);
1956                 fsm->path = npath;
1957             }
1958             /* Set file security context (if enabled) */
1959             if (!rc && !getuid()) {
1960                 rc = fsmSetSELabel(fsm->sehandle, fsm->path, fsm->sb.st_mode);
1961             }
1962             if (S_ISLNK(st->st_mode)) {
1963                 if (!rc && !getuid())
1964                     rc = fsmLChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
1965             } else {
1966                 rpmfi fi = fsmGetFi(fsm);
1967                 if (!rc && !getuid())
1968                     rc = fsmChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
1969                 if (!rc)
1970                     rc = fsmChmod(fsm->path, fsm->sb.st_mode);
1971                 if (!rc) {
1972                     rc = fsmUtime(fsm->path, rpmfiFMtimeIndex(fi, fsm->ix));
1973                     /* utime error is not critical for directories */
1974                     if (rc && S_ISDIR(st->st_mode))
1975                         rc = 0;
1976                 }
1977                 /* Set file capabilities (if enabled) */
1978                 if (!rc && !S_ISDIR(st->st_mode) && !getuid()) {
1979                     rc = fsmSetFCaps(fsm->path, rpmfiFCapsIndex(fi, fsm->ix));
1980                 }
1981             }
1982         }
1983
1984         /* Notify on success. */
1985         if (!rc)                rc = fsmNext(fsm, FSM_NOTIFY);
1986         else if (fsm->failedFile && *fsm->failedFile == NULL) {
1987             *fsm->failedFile = fsm->path;
1988             fsm->path = NULL;
1989         }
1990         break;
1991     case FSM_DESTROY:
1992         fsm->path = _free(fsm->path);
1993
1994         /* Check for hard links missing from payload. */
1995         while ((fsm->li = fsm->links) != NULL) {
1996             fsm->links = fsm->li->next;
1997             fsm->li->next = NULL;
1998             if (fsm->goal == FSM_PKGINSTALL && fsm->li->linksLeft) {
1999                 for (nlink_t i = 0 ; i < fsm->li->linksLeft; i++) {
2000                     if (fsm->li->filex[i] < 0)
2001                         continue;
2002                     rc = CPIOERR_MISSING_HARDLINK;
2003                     if (fsm->failedFile && *fsm->failedFile == NULL) {
2004                         fsm->ix = fsm->li->filex[i];
2005                         if (!fsmMapPath(fsm)) {
2006                             /* Out-of-sync hardlinks handled as sub-state */
2007                             *fsm->failedFile = fsm->path;
2008                             fsm->path = NULL;
2009                         }
2010                     }
2011                     break;
2012                 }
2013             }
2014             fsm->li = freeHardLink(fsm->li);
2015         }
2016         fsm->buf = _free(fsm->buf);
2017         fsm->bufsize = 0;
2018         break;
2019     case FSM_NEXT:
2020         if (!rc) {
2021             _free(fsm->path);
2022             rc = rpmcpioHeaderRead(fsm->archive, &(fsm->path), st);     /* Read next payload header. */
2023         }
2024         if (rc) break;
2025         if (rstreq(fsm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
2026             fsm->path = _free(fsm->path);
2027             rc = CPIOERR_HDR_TRAILER;
2028         }
2029         break;
2030     default:
2031         break;
2032     }
2033
2034     if (!(stage & FSM_INTERNAL)) {
2035         fsm->rc = (rc == CPIOERR_HDR_TRAILER ? 0 : rc);
2036     }
2037     return rc;
2038 }
2039
2040 /**
2041  * Return formatted string representation of file disposition.
2042  * @param a             file dispostion
2043  * @return              formatted string
2044  */
2045 static const char * fileActionString(rpmFileAction a)
2046 {
2047     switch (a) {
2048     case FA_UNKNOWN:    return "unknown";
2049     case FA_CREATE:     return "create";
2050     case FA_COPYOUT:    return "copyout";
2051     case FA_COPYIN:     return "copyin";
2052     case FA_BACKUP:     return "backup";
2053     case FA_SAVE:       return "save";
2054     case FA_SKIP:       return "skip";
2055     case FA_ALTNAME:    return "altname";
2056     case FA_ERASE:      return "erase";
2057     case FA_SKIPNSTATE: return "skipnstate";
2058     case FA_SKIPNETSHARED: return "skipnetshared";
2059     case FA_SKIPCOLOR:  return "skipcolor";
2060     default:            return "???";
2061     }
2062 }
2063
2064 /**
2065  * Return formatted string representation of file stages.
2066  * @param a             file stage
2067  * @return              formatted string
2068  */
2069 static const char * fileStageString(fileStage a)
2070 {
2071     switch(a) {
2072     case FSM_UNKNOWN:   return "unknown";
2073
2074     case FSM_PKGINSTALL:return "INSTALL";
2075     case FSM_PKGERASE:  return "ERASE";
2076     case FSM_PKGBUILD:  return "BUILD";
2077     case FSM_PKGUNDO:   return "UNDO";
2078
2079     case FSM_CREATE:    return "create";
2080     case FSM_INIT:      return "init";
2081     case FSM_MAP:       return "map";
2082     case FSM_MKDIRS:    return "mkdirs";
2083     case FSM_RMDIRS:    return "rmdirs";
2084     case FSM_PRE:       return "pre";
2085     case FSM_PROCESS:   return "process";
2086     case FSM_POST:      return "post";
2087     case FSM_MKLINKS:   return "mklinks";
2088     case FSM_NOTIFY:    return "notify";
2089     case FSM_UNDO:      return "undo";
2090     case FSM_FINI:      return "fini";
2091     case FSM_COMMIT:    return "commit";
2092     case FSM_DESTROY:   return "destroy";
2093     case FSM_VERIFY:    return "verify";
2094
2095     case FSM_UNLINK:    return "unlink";
2096     case FSM_RENAME:    return "rename";
2097     case FSM_MKDIR:     return "mkdir";
2098     case FSM_RMDIR:     return "rmdir";
2099     case FSM_LSETFCON:  return "lsetfcon";
2100     case FSM_CHOWN:     return "chown";
2101     case FSM_LCHOWN:    return "lchown";
2102     case FSM_CHMOD:     return "chmod";
2103     case FSM_UTIME:     return "utime";
2104     case FSM_SYMLINK:   return "symlink";
2105     case FSM_LINK:      return "link";
2106     case FSM_MKFIFO:    return "mkfifo";
2107     case FSM_MKNOD:     return "mknod";
2108     case FSM_LSTAT:     return "lstat";
2109     case FSM_STAT:      return "stat";
2110     case FSM_READLINK:  return "readlink";
2111     case FSM_SETCAP:    return "setcap";
2112
2113     case FSM_NEXT:      return "next";
2114     case FSM_EAT:       return "eat";
2115     case FSM_POS:       return "pos";
2116     case FSM_PAD:       return "pad";
2117     case FSM_TRAILER:   return "trailer";
2118     case FSM_HREAD:     return "hread";
2119     case FSM_HWRITE:    return "hwrite";
2120     case FSM_DREAD:     return "Fread";
2121     case FSM_DWRITE:    return "Fwrite";
2122
2123     default:            return "???";
2124     }
2125 }
2126
2127 int rpmfsmRun(fileStage goal, rpmts ts, rpmte te, rpmfi fi, FD_t cfd,
2128               rpmpsm psm, rpm_loff_t * archiveSize, char ** failedFile)
2129 {
2130     struct fsm_s fsm;
2131     int sc = 0;
2132     int ec = 0;
2133
2134     memset(&fsm, 0, sizeof(fsm));
2135     sc = fsmSetup(&fsm, goal, ts, te, fi, cfd, psm, archiveSize, failedFile);
2136     ec = fsmTeardown(&fsm);
2137
2138     /* Return the relevant code: if setup failed, teardown doesn't matter */
2139     return (sc ? sc : ec);
2140 }