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