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