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