rpm  5.2.1
iosm.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include <rpmio_internal.h> /* XXX urlPath, fdGetCpioPos */
9 #include <rpmcb.h> /* XXX fnpyKey */
10 #include <ugid.h> /* XXX unameToUid() and gnameToGid() */
11 
12 #include <rpmsq.h> /* XXX rpmsqJoin()/rpmsqThread() */
13 #include <rpmsw.h> /* XXX rpmswAdd() */
14 
15 #include "../rpmdb/rpmtag.h"
16 
17 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmts_s * rpmts;
18 typedef /*@abstract@*/ struct rpmte_s * rpmte;
19 
20 #define _IOSM_INTERNAL
21 #include <iosm.h>
22 #define iosmUNSAFE iosmStage
23 
24 #include "cpio.h"
25 #include "tar.h"
26 #include "ar.h"
27 
29 #define _RPMFI_INTERNAL
30 #define _RPMFI_NOMETHODS
31 #include "../lib/rpmfi.h"
32 
33 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmds_s * rpmds;
34 typedef struct rpmRelocation_s * rpmRelocation;
35 #undef _USE_RPMTE
36 #if defined(_USE_RPMTE)
37 typedef /*@abstract@*/ void * alKey;
38 #include "rpmte.h"
39 #endif
40 
41 #undef _USE_RPMSX
42 #if defined(_USE_RPMSX)
43 #include "../lib/rpmsx.h" /* XXX rpmsx rpmsxFContext rpmsxFree */
44 #endif
45 
46 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmdb_s * rpmdb;
47 typedef /*@abstract@*/ struct rpmmi_s * rpmmi;
48 typedef struct rpmPRCO_s * rpmPRCO;
49 typedef struct Spec_s * Spec;
50 #undef _USE_RPMTS
51 #if defined(_USE_RPMTS)
52 #include "rpmts.h"
53 #endif
54 
55 #include "debug.h"
56 
57 /*@access FD_t @*/ /* XXX void ptr args */
58 /*@access IOSMI_t @*/
59 /*@access IOSM_t @*/
60 
61 /*@access rpmfi @*/
62 
63 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
64 
65 #define _IOSM_DEBUG 0
66 /*@unchecked@*/
68 
69 /*@-exportheadervar@*/
70 /*@unchecked@*/
71 int _iosm_threads = 0;
72 /*@=exportheadervar@*/
73 
74 /*@-redecl@*/
75 int (*_iosmNext) (IOSM_t iosm, iosmFileStage nstage)
76  /*@modifies iosm @*/ = &iosmNext;
77 /*@=redecl@*/
78 
79 #if defined(_USE_RPMTS)
80 void * iosmGetTs(const IOSM_t iosm)
81 {
82  const IOSMI_t iter = iosm->iter;
83  /*@-compdef -refcounttrans -retexpose -usereleased @*/
84  return (iter ? iter->ts : NULL);
85  /*@=compdef =refcounttrans =retexpose =usereleased @*/
86 }
87 #endif
88 
89 void * iosmGetFi(const IOSM_t iosm)
90 {
91  const IOSMI_t iter = iosm->iter;
92  /*@-compdef -refcounttrans -retexpose -usereleased @*/
93  return (iter ? iter->fi : NULL);
94  /*@=compdef =refcounttrans =retexpose =usereleased @*/
95 }
96 
97 #define SUFFIX_RPMORIG ".rpmorig"
98 #define SUFFIX_RPMSAVE ".rpmsave"
99 #define SUFFIX_RPMNEW ".rpmnew"
100 
109 static /*@only@*//*@null@*/
110 const char * iosmFsPath(/*@special@*/ /*@null@*/ const IOSM_t iosm,
111  /*@null@*/ const struct stat * st,
112  /*@null@*/ const char * subdir,
113  /*@null@*/ const char * suffix)
114  /*@uses iosm->dirName, iosm->baseName */
115  /*@*/
116 {
117  const char * s = NULL;
118 
119  if (iosm) {
120  char * t;
121  int nb;
122  nb = strlen(iosm->dirName) +
123  (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) +
124  (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) +
125  strlen(iosm->baseName) + 1;
126  s = t = xmalloc(nb);
127  t = stpcpy(t, iosm->dirName);
128  if (st && !S_ISDIR(st->st_mode))
129  if (subdir) t = stpcpy(t, subdir);
130  t = stpcpy(t, iosm->baseName);
131  if (st && !S_ISDIR(st->st_mode))
132  if (suffix) t = stpcpy(t, suffix);
133  }
134  return s;
135 }
136 
142 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p)
143  /*@modifies p @*/
144 {
145  IOSMI_t iter = p;
146  if (iter) {
147 #if !defined(_RPMFI_NOMETHODS)
148  iter->fi = rpmfiUnlink(iter->fi, "mapIterator");
149 #endif
150  iter->fi = NULL;
151  }
152  return _free(p);
153 }
154 
161 /*@-mustmod@*/
162 static void *
164  /*@modifies fi @*/
165 {
166  IOSMI_t iter = NULL;
167 
168  iter = xcalloc(1, sizeof(*iter));
169 #if !defined(_RPMFI_NOMETHODS)
170  iter->fi = rpmfiLink(fi, "mapIterator");
171 #else
172 /*@i@*/ iter->fi = fi;
173 #endif
174  iter->reverse = reverse;
175  iter->i = (iter->reverse ? (fi->fc - 1) : 0);
176  iter->isave = iter->i;
177  return iter;
178 }
179 /*@=mustmod@*/
180 
186 static int mapNextIterator(/*@null@*/ void * a)
187  /*@*/
188 {
189  IOSMI_t iter = a;
190  int i = -1;
191 
192  if (iter) {
193  if (iter->reverse) {
194  if (iter->i >= 0) i = iter->i--;
195  } else {
196  if (iter->i < (int) ((rpmfi)iter->fi)->fc) i = iter->i++;
197  }
198  iter->isave = i;
199  }
200  return i;
201 }
202 
205 static int iosmStrCmp(const void * a, const void * b)
206  /*@*/
207 {
208  const char * aurl = *(const char **)a;
209  const char * burl = *(const char **)b;
210  const char * afn = NULL;
211  const char * bfn = NULL;
212 
213  (void) urlPath(aurl, &afn);
214  (void) urlPath(burl, &bfn);
215 
216 #ifdef VERY_OLD_BUGGY_RPM_PACKAGES
217  /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */
218  if (strchr(afn, '/') == NULL)
219  bfn = strrchr(bfn, '/') + 1;
220 #endif
221 
222  /* Match rpm-4.0 payloads with ./ prefixes. */
223  if (afn[0] == '.' && afn[1] == '/') afn += 2;
224  if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
225 
226  /* If either path is absolute, make it relative to '/'. */
227  if (afn[0] == '/') afn += 1;
228  if (bfn[0] == '/') bfn += 1;
229 
230  return strcmp(afn, bfn);
231 }
232 
239 static int mapFind(/*@null@*/ IOSMI_t iter, const char * iosmPath)
240  /*@modifies iter @*/
241 {
242  int ix = -1;
243 
244  if (iter) {
245 /*@-onlytrans@*/
246  const rpmfi fi = iter->fi;
247 /*@=onlytrans@*/
248 #if !defined(_RPMFI_NOMETHODS)
249  size_t fc = rpmfiFC(fi);
250 #else
251  size_t fc = (fi ? fi->fc : 0);
252 #endif
253  if (fi && fc > 0 && fi->apath && iosmPath && *iosmPath) {
254  const char ** p = NULL;
255 
256  if (fi->apath != NULL)
257  p = bsearch(&iosmPath, fi->apath, fc, sizeof(iosmPath),
258  iosmStrCmp);
259  if (p) {
260  iter->i = p - fi->apath;
261  ix = mapNextIterator(iter);
262  }
263  }
264  }
265  return ix;
266 }
267 
271 typedef struct dnli_s {
272  rpmfi fi;
273 /*@only@*/ /*@null@*/
274  char * active;
275  int reverse;
276  int isave;
277  int i;
278 } * DNLI_t;
279 
285 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a)
286  /*@modifies a @*/
287 {
288  if (a) {
289  DNLI_t dnli = (void *)a;
290  if (dnli->active) free(dnli->active);
291  }
292  return _free(a);
293 }
294 
297 static inline int dnlCount(/*@null@*/ const DNLI_t dnli)
298  /*@*/
299 {
300  return (int) (dnli ? dnli->fi->dc : 0);
301 }
302 
305 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli)
306  /*@*/
307 {
308  return (dnli ? dnli->isave : -1);
309 }
310 
317 /*@-usereleased@*/
318 static /*@only@*/ /*@null@*/
319 void * dnlInitIterator(/*@special@*/ const IOSM_t iosm,
320  int reverse)
321  /*@uses iosm->iter @*/
322  /*@*/
323 {
324  rpmfi fi = iosmGetFi(iosm);
325  const char * dnl;
326  DNLI_t dnli;
327  int i, j;
328 
329  if (fi == NULL)
330  return NULL;
331  dnli = xcalloc(1, sizeof(*dnli));
332  dnli->fi = fi;
333  dnli->reverse = reverse;
334  dnli->i = (int) (reverse ? fi->dc : 0);
335 
336  if (fi->dc) {
337  dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
338 
339  /* Identify parent directories not skipped. */
340 #if !defined(_RPMFI_NOMETHODS)
341  if ((fi = rpmfiInit(fi, 0)) != NULL)
342  while ((i = rpmfiNext(fi)) >= 0)
343 #else
344  for (i = 0; i < (int)fi->fc; i++)
345 #endif
346  {
347  if (!iosmFileActionSkipped(fi->actions[i]))
348  dnli->active[fi->dil[i]] = (char)1;
349  }
350 
351  /* Exclude parent directories that are explicitly included. */
352 #if !defined(_RPMFI_NOMETHODS)
353  if ((fi = rpmfiInit(fi, 0)) != NULL)
354  while ((i = rpmfiNext(fi)) >= 0)
355 #else
356  for (i = 0; i < (int)fi->fc; i++)
357 #endif
358  {
359  rpmuint32_t dil;
360  size_t dnlen, bnlen;
361 
362  if (!S_ISDIR(fi->fmodes[i]))
363  continue;
364 
365  dil = fi->dil[i];
366  dnlen = strlen(fi->dnl[dil]);
367  bnlen = strlen(fi->bnl[i]);
368 
369  for (j = 0; j < (int)fi->dc; j++) {
370  size_t jlen;
371 
372  if (!dnli->active[j] || j == (int)dil)
373  /*@innercontinue@*/ continue;
374  (void) urlPath(fi->dnl[j], &dnl);
375  jlen = strlen(dnl);
376  if (jlen != (dnlen+bnlen+1))
377  /*@innercontinue@*/ continue;
378  if (strncmp(dnl, fi->dnl[dil], dnlen))
379  /*@innercontinue@*/ continue;
380  if (strncmp(dnl+dnlen, fi->bnl[i], bnlen))
381  /*@innercontinue@*/ continue;
382  if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
383  /*@innercontinue@*/ continue;
384  /* This directory is included in the package. */
385  dnli->active[j] = (char)0;
386  /*@innerbreak@*/ break;
387  }
388  }
389 
390  /* Print only once per package. */
391  if (!reverse) {
392  j = 0;
393  for (i = 0; i < (int)fi->dc; i++) {
394  if (!dnli->active[i]) continue;
395  if (j == 0) {
396  j = 1;
398  D_("========== Directories not explicitly included in package:\n"));
399  }
400  (void) urlPath(fi->dnl[i], &dnl);
401  rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl);
402  }
403  if (j)
404  rpmlog(RPMLOG_DEBUG, "==========\n");
405  }
406  }
407  return dnli;
408 }
409 /*@=usereleased@*/
410 
416 static /*@observer@*/ /*@null@*/
417 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli)
418  /*@modifies dnli @*/
419 {
420  const char * dn = NULL;
421 
422  if (dnli) {
423  rpmfi fi = dnli->fi;
424  int i = -1;
425 
426  if (dnli->active)
427  do {
428  i = (!dnli->reverse ? dnli->i++ : --dnli->i);
429  } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]);
430 
431  if (i >= 0 && i < (int)fi->dc)
432  dn = fi->dnl[i];
433  else
434  i = -1;
435  dnli->isave = i;
436  }
437  return dn;
438 }
439 
440 #if defined(WITH_PTHREADS)
441 static void * iosmThread(void * arg)
442  /*@globals h_errno, fileSystem, internalState @*/
443  /*@modifies arg, fileSystem, internalState @*/
444 {
445  IOSM_t iosm = arg;
446 /*@-unqualifiedtrans@*/
447  return ((void *) ((long)iosmStage(iosm, iosm->nstage)));
448 /*@=unqualifiedtrans@*/
449 }
450 #endif
451 
452 int iosmNext(IOSM_t iosm, iosmFileStage nstage)
453  /*@globals h_errno, fileSystem, internalState @*/
454  /*@modifies iosm, fileSystem, internalState @*/
455 {
456  iosm->nstage = nstage;
457 #if defined(WITH_PTHREADS)
458  if (iosm->multithreaded)
459  return rpmsqJoin( rpmsqThread(iosmThread, iosm) );
460 #endif
461  return iosmStage(iosm, iosm->nstage);
462 }
463 
469 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t iosm)
470  /*@uses iosm->links, iosm->ix, iosm->sb, iosm->goal, iosm->nsuffix @*/
471  /*@defines iosm->li @*/
472  /*@releases iosm->path @*/
473  /*@globals h_errno, fileSystem, internalState @*/
474  /*@modifies iosm, fileSystem, internalState @*/
475 {
476  struct stat * st = &iosm->sb;
477  int rc = 0;
478  int ix = -1;
479  int j;
480 
481  /* Find hard link set. */
482  for (iosm->li = iosm->links; iosm->li; iosm->li = iosm->li->next) {
483  if (iosm->li->sb.st_ino == st->st_ino && iosm->li->sb.st_dev == st->st_dev)
484  break;
485  }
486 
487  /* New hard link encountered, add new link to set. */
488  if (iosm->li == NULL) {
489  iosm->li = xcalloc(1, sizeof(*iosm->li));
490  iosm->li->next = NULL;
491  iosm->li->sb = *st; /* structure assignment */
492  iosm->li->nlink = (int) st->st_nlink;
493  iosm->li->linkIndex = iosm->ix;
494  iosm->li->createdPath = -1;
495 
496  iosm->li->filex = xcalloc(st->st_nlink, sizeof(iosm->li->filex[0]));
497  memset(iosm->li->filex, -1, (st->st_nlink * sizeof(iosm->li->filex[0])));
498  iosm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*iosm->li->nsuffix));
499 
500  if (iosm->goal == IOSM_PKGBUILD)
501  iosm->li->linksLeft = (int) st->st_nlink;
502  if (iosm->goal == IOSM_PKGINSTALL)
503  iosm->li->linksLeft = 0;
504 
505  /*@-kepttrans@*/
506  iosm->li->next = iosm->links;
507  /*@=kepttrans@*/
508  iosm->links = iosm->li;
509  }
510 
511  if (iosm->goal == IOSM_PKGBUILD) --iosm->li->linksLeft;
512  iosm->li->filex[iosm->li->linksLeft] = iosm->ix;
513  /*@-observertrans -dependenttrans@*/
514  iosm->li->nsuffix[iosm->li->linksLeft] = iosm->nsuffix;
515  /*@=observertrans =dependenttrans@*/
516  if (iosm->goal == IOSM_PKGINSTALL) iosm->li->linksLeft++;
517 
518  if (iosm->goal == IOSM_PKGBUILD)
519  return (iosm->li->linksLeft > 0);
520 
521  if (iosm->goal != IOSM_PKGINSTALL)
522  return 0;
523 
524  if (!(st->st_size || iosm->li->linksLeft == (int) st->st_nlink))
525  return 1;
526 
527  /* Here come the bits, time to choose a non-skipped file name. */
528  { rpmfi fi = iosmGetFi(iosm);
529 
530  for (j = iosm->li->linksLeft - 1; j >= 0; j--) {
531  ix = iosm->li->filex[j];
532  if (ix < 0 || iosmFileActionSkipped(fi->actions[ix]))
533  continue;
534  break;
535  }
536  }
537 
538  /* Are all links skipped or not encountered yet? */
539  if (ix < 0 || j < 0)
540  return 1; /* XXX W2DO? */
541 
542  /* Save the non-skipped file name and map index. */
543  iosm->li->linkIndex = j;
544  iosm->path = _free(iosm->path);
545  iosm->ix = ix;
546  rc = iosmNext(iosm, IOSM_MAP);
547  return rc;
548 }
549 
555 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li)
556  /*@modifies li @*/
557 {
558  if (li) {
559  li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
560  li->filex = _free(li->filex);
561  }
562  return _free(li);
563 }
564 
566 {
567  IOSM_t iosm = xcalloc(1, sizeof(*iosm));
568  return iosm;
569 }
570 
572 {
573  if (iosm) {
574  iosm->path = _free(iosm->path);
575  while ((iosm->li = iosm->links) != NULL) {
576  iosm->links = iosm->li->next;
577  iosm->li->next = NULL;
578  iosm->li = freeHardLink(iosm->li);
579  }
580  iosm->dnlx = _free(iosm->dnlx);
581  iosm->ldn = _free(iosm->ldn);
582  iosm->iter = mapFreeIterator(iosm->iter);
583  }
584  return _free(iosm);
585 }
586 
587 static int arSetup(IOSM_t iosm, rpmfi fi)
588  /*@modifies iosm @*/
589 {
590  const char * path;
591  char * t;
592  size_t lmtablen = 0;
593  size_t nb;
594 
595  /* Calculate size of ar(1) long member table. */
596 #if !defined(_RPMFI_NOMETHODS)
597  if ((fi = rpmfiInit(fi, 0)) != NULL)
598  while (rpmfiNext(fi) >= 0)
599 #else
600  int i;
601  if (fi != NULL)
602  for (i = 0; i < (int)fi->fc; i++)
603 #endif
604  {
605 #ifdef NOTYET
606  if (fi->apath) {
607  const char * apath = NULL;
608  (void) urlPath(fi->apath[ix], &apath);
609  path = apath + fi->striplen;
610  } else
611 #endif
612 #if !defined(_RPMFI_NOMETHODS)
613  path = rpmfiBN(fi);
614 #else
615  path = fi->bnl[i];
616 #endif
617  if ((nb = strlen(path)) < 15)
618  continue;
619  lmtablen += nb + 1; /* trailing \n */
620  }
621 
622  /* Anything to do? */
623  if (lmtablen == 0)
624  return 0;
625 
626  /* Create and load ar(1) long member table. */
627  iosm->lmtab = t = xmalloc(lmtablen + 1); /* trailing \0 */
628  iosm->lmtablen = lmtablen;
629  iosm->lmtaboff = 0;
630 #if !defined(_RPMFI_NOMETHODS)
631  if ((fi = rpmfiInit(fi, 0)) != NULL)
632  while (rpmfiNext(fi) >= 0)
633 #else
634  if (fi != NULL)
635  for (i = 0; i < (int)fi->fc; i++)
636 #endif
637  {
638 #ifdef NOTYET
639  if (fi->apath) {
640  const char * apath = NULL;
641  (void) urlPath(fi->apath[ix], &apath);
642  path = apath + fi->striplen;
643  } else
644 #endif
645 #if !defined(_RPMFI_NOMETHODS)
646  path = rpmfiBN(fi);
647 #else
648  path = fi->bnl[i];
649 #endif
650  if ((nb = strlen(path)) < 15)
651  continue;
652  t = stpcpy(t, path);
653  *t++ = '\n';
654  }
655  *t = '\0';
656 
657  return 0;
658 }
659 
660 int iosmSetup(IOSM_t iosm, iosmFileStage goal, const char * afmt,
661  const void * _ts, const void * _fi, FD_t cfd,
662  unsigned int * archiveSize, const char ** failedFile)
663 {
664 #if defined(_USE_RPMTS)
665  const rpmts ts = (const rpmts) _ts;
666 #endif
667 /*@i@*/ const rpmfi fi = (const rpmfi) _fi;
668 #if defined(_USE_RPMTE)
669  int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT);
670  int adding = (rpmteType(fi->te) == TR_ADDED);
671 #else
672  int reverse = 0; /* XXX HACK: devise alternative means */
673  int adding = 1; /* XXX HACK: devise alternative means */
674 #endif
675  size_t pos = 0;
676  int rc, ec = 0;
677 
678  iosm->debug = _iosm_debug;
679  iosm->multithreaded = _iosm_threads;
680  iosm->adding = adding;
681 
682 /*@+voidabstract -nullpass@*/
683 if (iosm->debug < 0)
684 fprintf(stderr, "--> iosmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", iosm, goal, afmt, (void *)_ts, _fi, cfd, archiveSize, failedFile);
685 /*@=voidabstract =nullpass@*/
686 
687  _iosmNext = &iosmNext;
688  if (iosm->headerRead == NULL) {
689  if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) {
690 if (iosm->debug < 0)
691 fprintf(stderr, "\ttar vectors set\n");
692  iosm->headerRead = &tarHeaderRead;
693  iosm->headerWrite = &tarHeaderWrite;
694  iosm->trailerWrite = &tarTrailerWrite;
695  iosm->blksize = TAR_BLOCK_SIZE;
696  } else
697  if (afmt != NULL && !strcmp(afmt, "ar")) {
698 if (iosm->debug < 0)
699 fprintf(stderr, "\tar vectors set\n");
700  iosm->headerRead = &arHeaderRead;
701  iosm->headerWrite = &arHeaderWrite;
702  iosm->trailerWrite = &arTrailerWrite;
703  iosm->blksize = 2;
704  if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE)
705  (void) arSetup(iosm, fi);
706  } else
707  {
708 if (iosm->debug < 0)
709 fprintf(stderr, "\tcpio vectors set\n");
710  iosm->headerRead = &cpioHeaderRead;
711  iosm->headerWrite = &cpioHeaderWrite;
712  iosm->trailerWrite = &cpioTrailerWrite;
713  iosm->blksize = 4;
714  }
715  }
716 
717  iosm->goal = goal;
718  if (cfd != NULL) {
719 /*@-assignexpose@*/
720  iosm->cfd = fdLink(cfd, "persist (iosm)");
721 /*@=assignexpose@*/
722  pos = fdGetCpioPos(iosm->cfd);
723  fdSetCpioPos(iosm->cfd, 0);
724  }
725 /*@-mods@*/ /* WTF? */
726  iosm->iter = mapInitIterator(fi, reverse);
727 /*@=mods@*/
728 #if defined(_USE_RPMTS)
729  iosm->iter->ts = rpmtsLink(ts, "mapIterator");
730  iosm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS);
731  iosm->nofdigests =
732  (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS))
733  ? 0 : 1;
734 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
735  iosm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) &&
736  iosm->goal != IOSM_PKGCOMMIT) ? 0 : 1);
737 #undef _tsmask
738 #else
739 /*@-assignexpose -temptrans @*/
740  iosm->iter->ts = (void *)_ts;
741 /*@=assignexpose =temptrans @*/
742  iosm->nofcontexts = 1;
743  iosm->nofdigests = 1;
744  iosm->commit = 1;
745 #endif
746 
747  if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
748  fi->archivePos = 0;
749 #if defined(_USE_RPMTS)
750  (void) rpmtsNotify(ts, fi->te,
751  RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize);
752 #endif
753  }
754 
755  /*@-assignexpose@*/
756  iosm->archiveSize = archiveSize;
757  if (iosm->archiveSize)
758  *iosm->archiveSize = 0;
759  iosm->failedFile = failedFile;
760  if (iosm->failedFile)
761  *iosm->failedFile = NULL;
762  /*@=assignexpose@*/
763 
764  memset(iosm->sufbuf, 0, sizeof(iosm->sufbuf));
765  if (iosm->goal == IOSM_PKGINSTALL) {
766  rpmuint32_t tid;
767 #if defined(_USE_RPMTS)
768  tid = (ts != NULL ? rpmtsGetTid(ts) : 0);
769 #else
770  static time_t now = 0;
771  if (now == 0) now = time(NULL);
772  tid = (rpmuint32_t) now;
773 #endif
774  if (tid > 0 && tid < 0xffffffff)
775  sprintf(iosm->sufbuf, ";%08x", (unsigned)tid);
776  }
777 
778  ec = iosm->rc = 0;
779  rc = iosmUNSAFE(iosm, IOSM_CREATE);
780  if (rc && !ec) ec = rc;
781 
782  rc = iosmUNSAFE(iosm, iosm->goal);
783  if (rc && !ec) ec = rc;
784 
785  if (iosm->archiveSize && ec == 0)
786  *iosm->archiveSize = (fdGetCpioPos(iosm->cfd) - pos);
787 
788 /*@-nullstate@*/ /* FIX: *iosm->failedFile may be NULL */
789  return ec;
790 /*@=nullstate@*/
791 }
792 
794 {
795  int rc = iosm->rc;
796 
797 if (iosm->debug < 0)
798 fprintf(stderr, "--> iosmTeardown(%p)\n", iosm);
799  if (!rc)
800  rc = iosmUNSAFE(iosm, IOSM_DESTROY);
801 
802  iosm->lmtab = _free(iosm->lmtab);
803 
804 #if defined(_USE_RPMTS)
805  (void) rpmswAdd(rpmtsOp(iosmGetTs(iosm), RPMTS_OP_DIGEST),
806  &iosm->op_digest);
807  (void)rpmtsFree(iter->ts);
808  iter->ts = NULL;
809 #else
810  iosm->iter->ts = NULL;
811 #endif
812  iosm->iter = mapFreeIterator(iosm->iter);
813  if (iosm->cfd != NULL) {
814  iosm->cfd = fdFree(iosm->cfd, "persist (iosm)");
815  iosm->cfd = NULL;
816  }
817  iosm->failedFile = NULL;
818  return rc;
819 }
820 
821 /*
822  * Set file security context (if not disabled).
823  * @param iosm file state machine data
824  * @return 0 always
825  */
826 static int iosmMapFContext(IOSM_t iosm)
827  /*@modifies iosm @*/
828 {
829  /*
830  * Find file security context (if not disabled).
831  */
832  iosm->fcontext = NULL;
833  if (!iosm->nofcontexts) {
834  security_context_t scon = NULL;
835  int xx = matchpathcon(iosm->path, iosm->sb.st_mode, &scon);
836 
837 /*@-moduncon@*/
838  if (!xx && scon != NULL)
839  iosm->fcontext = scon;
840 #ifdef DYING /* XXX SELinux file contexts not set from package content. */
841  else {
842  rpmfi fi = iosmGetFi(iosm);
843  int i = iosm->ix;
844 
845  /* Get file security context from package. */
846  if (fi && i >= 0 && i < (int)fi->fc)
847  iosm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL);
848  }
849 #endif
850 /*@=moduncon@*/
851  }
852  return 0;
853 }
854 
856 {
857  rpmfi fi = iosmGetFi(iosm); /* XXX const except for fstates */
858  int teAdding = iosm->adding;
859  int rc = 0;
860  int i = iosm->ix;
861 
862  iosm->osuffix = NULL;
863  iosm->nsuffix = NULL;
864  iosm->astriplen = 0;
865  iosm->action = FA_UNKNOWN;
866  iosm->mapFlags = fi->mapflags;
867 
868  if (fi && i >= 0 && i < (int)fi->fc) {
869 
870  iosm->astriplen = fi->astriplen;
871  iosm->action = (fi->actions ? fi->actions[i] : fi->action);
872  iosm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
873  iosm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
874 
875  /* src rpms have simple base name in payload. */
876  iosm->dirName = fi->dnl[fi->dil[i]];
877  iosm->baseName = fi->bnl[i];
878 
879  switch (iosm->action) {
880  case FA_SKIP:
881  break;
882  case FA_UNKNOWN:
883  break;
884 
885  case FA_COPYOUT:
886  break;
887  case FA_COPYIN:
888  case FA_CREATE:
889 assert(teAdding);
890  break;
891 
892  case FA_SKIPNSTATE:
893  if (fi->fstates && teAdding)
894  fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_NOTINSTALLED;
895  break;
896 
897  case FA_SKIPNETSHARED:
898  if (fi->fstates && teAdding)
899  fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_NETSHARED;
900  break;
901 
902  case FA_SKIPCOLOR:
903  if (fi->fstates && teAdding)
904  fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_WRONGCOLOR;
905  break;
906 
907  case FA_BACKUP:
908  if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
909  iosm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE);
910  break;
911 
912  case FA_ALTNAME:
913 assert(teAdding);
914  if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
915  iosm->nsuffix = SUFFIX_RPMNEW;
916  break;
917 
918  case FA_SAVE:
919 assert(teAdding);
920  if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
921  iosm->osuffix = SUFFIX_RPMSAVE;
922  break;
923  case FA_ERASE:
924 #if 0 /* XXX is this a genhdlist fix? */
925  assert(rpmteType(fi->te) == TR_REMOVED);
926 #endif
927  /*
928  * XXX TODO: %ghost probably shouldn't be removed, but that changes
929  * legacy rpm behavior.
930  */
931  break;
932  default:
933  break;
934  }
935 
936  if ((iosm->mapFlags & IOSM_MAP_PATH) || iosm->nsuffix) {
937  const struct stat * st = &iosm->sb;
938  iosm->path = _free(iosm->path);
939  iosm->path = iosmFsPath(iosm, st, iosm->subdir,
940  (iosm->suffix ? iosm->suffix : iosm->nsuffix));
941  }
942  }
943  return rc;
944 }
945 
947 {
948  struct stat * st = &iosm->sb;
949  rpmfi fi = iosmGetFi(iosm);
950  int i = iosm->ix;
951 
952  if (fi && i >= 0 && i < (int)fi->fc) {
953  mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
954  mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms);
955  dev_t finalRdev = (fi->frdevs ? fi->frdevs[i] : 0);
956  rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
957  uid_t uid = fi->uid;
958  gid_t gid = fi->gid;
959 
960 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
961  /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during
962  installation of _source_ RPMs. Instead, let it use the current
963  run-time owner/group, because most of the time the owner/group in
964  the source RPM (which is the owner/group of the files as staying on
965  the package author system) is not existing on the target system, of
966  course. */
967 #endif
968  if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
969 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
970  if (!fi->isSource) {
971 #endif
972  if (iosm->goal == IOSM_PKGINSTALL)
974  _("user %s does not exist - using root\n"), fi->fuser[i]);
975  uid = 0;
976  finalMode &= ~S_ISUID; /* turn off suid bit */
977 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
978  }
979 #endif
980  }
981 
982  if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
983 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
984  if (!fi->isSource) {
985 #endif
986  if (iosm->goal == IOSM_PKGINSTALL)
988  _("group %s does not exist - using root\n"), fi->fgroup[i]);
989  gid = 0;
990  finalMode &= ~S_ISGID; /* turn off sgid bit */
991 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
992  }
993 #endif
994  }
995 
996  if (iosm->mapFlags & IOSM_MAP_MODE)
997  st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
998  if (iosm->mapFlags & IOSM_MAP_TYPE) {
999  st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
1000  if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
1001  && st->st_nlink == 0)
1002  st->st_nlink = 1;
1003  st->st_rdev = finalRdev;
1004  st->st_mtime = finalMtime;
1005  }
1006  if (iosm->mapFlags & IOSM_MAP_UID)
1007  st->st_uid = uid;
1008  if (iosm->mapFlags & IOSM_MAP_GID)
1009  st->st_gid = gid;
1010 
1011  /*
1012  * Set file digest (if not disabled).
1013  */
1014  if (!iosm->nofdigests) {
1015  iosm->fdigestalgo = fi->digestalgo;
1016  iosm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL);
1017  iosm->digestlen = fi->digestlen;
1018  iosm->digest = (fi->digests ? (fi->digests + (iosm->digestlen * i)) : NULL);
1019  } else {
1020  iosm->fdigestalgo = 0;
1021  iosm->fdigest = NULL;
1022  iosm->digestlen = 0;
1023  iosm->digest = NULL;
1024  }
1025  }
1026  return 0;
1027 }
1028 
1034 /*@-compdef@*/
1035 static int extractRegular(/*@special@*/ IOSM_t iosm)
1036  /*@uses iosm->fdigest, iosm->digest, iosm->sb, iosm->wfd @*/
1037  /*@globals h_errno, fileSystem, internalState @*/
1038  /*@modifies iosm, fileSystem, internalState @*/
1039 {
1040  const struct stat * st = &iosm->sb;
1041  size_t left = (size_t) st->st_size;
1042  int rc = 0;
1043  int xx;
1044 
1045  rc = iosmNext(iosm, IOSM_WOPEN);
1046  if (rc)
1047  goto exit;
1048 
1049  if (st->st_size > 0 && (iosm->fdigest != NULL || iosm->digest != NULL))
1050  fdInitDigest(iosm->wfd, iosm->fdigestalgo, 0);
1051 
1052  while (left) {
1053 
1054  iosm->wrlen = (left > iosm->wrsize ? iosm->wrsize : left);
1055  rc = iosmNext(iosm, IOSM_DREAD);
1056  if (rc)
1057  goto exit;
1058 
1059  rc = iosmNext(iosm, IOSM_WRITE);
1060  if (rc)
1061  goto exit;
1062 
1063  left -= iosm->wrnb;
1064 
1065  /* Notify iff progress, completion is done elsewhere */
1066  if (!rc && left)
1067  (void) iosmNext(iosm, IOSM_NOTIFY);
1068  }
1069 
1070  xx = fsync(Fileno(iosm->wfd));
1071 
1072  if (st->st_size > 0 && (iosm->fdigest || iosm->digest)) {
1073  void * digest = NULL;
1074  int asAscii = (iosm->digest == NULL ? 1 : 0);
1075 
1076  (void) Fflush(iosm->wfd);
1077  fdFiniDigest(iosm->wfd, iosm->fdigestalgo, &digest, NULL, asAscii);
1078 
1079  if (digest == NULL) {
1080  rc = IOSMERR_DIGEST_MISMATCH;
1081  goto exit;
1082  }
1083 
1084  if (iosm->digest != NULL) {
1085  if (memcmp(digest, iosm->digest, iosm->digestlen))
1086  rc = IOSMERR_DIGEST_MISMATCH;
1087  } else {
1088  if (strcmp(digest, iosm->fdigest))
1089  rc = IOSMERR_DIGEST_MISMATCH;
1090  }
1091  digest = _free(digest);
1092  }
1093 
1094 exit:
1095  (void) iosmNext(iosm, IOSM_WCLOSE);
1096  return rc;
1097 }
1098 /*@=compdef@*/
1099 
1106 /*@-compdef -compmempass@*/
1107 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t iosm, int writeData)
1108  /*@uses iosm->path, iosm->opath, iosm->sb, iosm->osb, iosm->cfd @*/
1109  /*@globals h_errno, fileSystem, internalState @*/
1110  /*@modifies iosm, fileSystem, internalState @*/
1111 {
1112  const char * path = iosm->path;
1113  const char * opath = iosm->opath;
1114  struct stat * st = &iosm->sb;
1115  struct stat * ost = &iosm->osb;
1116  size_t left;
1117  int xx;
1118  int rc;
1119 
1120  st->st_size = (writeData ? ost->st_size : 0);
1121 
1122  if (S_ISDIR(st->st_mode)) {
1123  st->st_size = 0;
1124  } else if (S_ISLNK(st->st_mode)) {
1125  /*
1126  * While linux puts the size of a symlink in the st_size field,
1127  * I don't think that's a specified standard.
1128  */
1129  /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */
1130  rc = iosmUNSAFE(iosm, IOSM_READLINK);
1131  if (rc) goto exit;
1132  st->st_size = iosm->rdnb;
1133  iosm->lpath = xstrdup(iosm->rdbuf); /* XXX save readlink return. */
1134  }
1135 
1136  if (iosm->mapFlags & IOSM_MAP_ABSOLUTE) {
1137  size_t nb=strlen(iosm->dirName) + strlen(iosm->baseName) + sizeof(".");
1138  char * t = alloca(nb);
1139  *t = '\0';
1140  iosm->path = t;
1141  if (iosm->mapFlags & IOSM_MAP_ADDDOT)
1142  *t++ = '.';
1143  t = stpcpy( stpcpy(t, iosm->dirName), iosm->baseName);
1144  } else if (iosm->mapFlags & IOSM_MAP_PATH) {
1145  rpmfi fi = iosmGetFi(iosm);
1146  if (fi->apath) {
1147  const char * apath = NULL;
1148  (void) urlPath(fi->apath[iosm->ix], &apath);
1149  iosm->path = apath + fi->striplen;
1150  } else
1151  iosm->path = fi->bnl[iosm->ix];
1152  }
1153 
1154  rc = iosmNext(iosm, IOSM_HWRITE);
1155  iosm->path = path;
1156  if (rc) goto exit;
1157 
1158  if (writeData && S_ISREG(st->st_mode)) {
1159 #if defined(HAVE_MMAP)
1160  char * rdbuf = NULL;
1161  void * mapped = (void *)-1;
1162  size_t nmapped = 0;
1163  /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
1164  int use_mmap = (st->st_size <= 0x07ffffff);
1165 #endif
1166 
1167  rc = iosmNext(iosm, IOSM_ROPEN);
1168  if (rc) goto exit;
1169 
1170  /* XXX unbuffered mmap generates *lots* of fdio debugging */
1171 #if defined(HAVE_MMAP)
1172  if (use_mmap) {
1173  mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(iosm->rfd), 0);
1174  if (mapped != (void *)-1) {
1175  rdbuf = iosm->rdbuf;
1176  iosm->rdbuf = (char *) mapped;
1177  iosm->rdlen = nmapped = st->st_size;
1178 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
1179  xx = madvise(mapped, nmapped, MADV_DONTNEED);
1180 #endif
1181  }
1182  }
1183 #endif
1184 
1185  left = st->st_size;
1186 
1187  while (left) {
1188 #if defined(HAVE_MMAP)
1189  if (mapped != (void *)-1) {
1190  iosm->rdnb = nmapped;
1191  } else
1192 #endif
1193  {
1194  iosm->rdlen = (left > iosm->rdsize ? iosm->rdsize : left),
1195  rc = iosmNext(iosm, IOSM_READ);
1196  if (rc) goto exit;
1197  }
1198 
1199  /* XXX DWRITE uses rdnb for I/O length. */
1200  rc = iosmNext(iosm, IOSM_DWRITE);
1201  if (rc) goto exit;
1202 
1203  left -= iosm->wrnb;
1204  }
1205 
1206 #if defined(HAVE_MMAP)
1207  if (mapped != (void *)-1) {
1208 /* XXX splint misses size_t 2nd arg. */
1209 /*@i@*/ xx = msync(mapped, nmapped, MS_ASYNC);
1210 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
1211  xx = madvise(mapped, nmapped, MADV_DONTNEED);
1212 #endif
1213  xx = munmap(mapped, nmapped);
1214  iosm->rdbuf = rdbuf;
1215  } else
1216 #endif
1217  xx = fsync(Fileno(iosm->rfd));
1218 
1219  }
1220 
1221  rc = iosmNext(iosm, IOSM_PAD);
1222  if (rc) goto exit;
1223 
1224  rc = 0;
1225 
1226 exit:
1227  if (iosm->rfd != NULL)
1228  (void) iosmNext(iosm, IOSM_RCLOSE);
1229 /*@-dependenttrans@*/
1230  iosm->opath = opath;
1231  iosm->path = path;
1232 /*@=dependenttrans@*/
1233  return rc;
1234 }
1235 /*@=compdef =compmempass@*/
1236 
1242 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t iosm)
1243  /*@uses iosm->path, iosm->nsuffix, iosm->ix, iosm->li, iosm->failedFile @*/
1244  /*@globals h_errno, fileSystem, internalState @*/
1245  /*@modifies iosm, fileSystem, internalState @*/
1246 {
1247  const char * path = iosm->path;
1248  const char * lpath = iosm->lpath;
1249  const char * nsuffix = iosm->nsuffix;
1250  int iterIndex = iosm->ix;
1251  int ec = 0;
1252  int rc;
1253  int i;
1254  const char * linkpath = NULL;
1255  int firstfile = 1;
1256 
1257  iosm->path = NULL;
1258  iosm->lpath = NULL;
1259  iosm->nsuffix = NULL;
1260  iosm->ix = -1;
1261 
1262  for (i = iosm->li->nlink - 1; i >= 0; i--) {
1263 
1264  if (iosm->li->filex[i] < 0) continue;
1265 
1266  iosm->ix = iosm->li->filex[i];
1267 /*@-compdef@*/
1268  rc = iosmNext(iosm, IOSM_MAP);
1269 /*@=compdef@*/
1270 
1271  /* XXX tar and cpio have to do things differently. */
1272  if (iosm->headerWrite == tarHeaderWrite) {
1273  if (firstfile) {
1274  const char * apath = NULL;
1275  char *t;
1276  (void) urlPath(iosm->path, &apath);
1277  /* Remove the buildroot prefix. */
1278  t = xmalloc(sizeof(".") + strlen(apath + iosm->astriplen));
1279  (void) stpcpy( stpcpy(t, "."), apath + iosm->astriplen);
1280  linkpath = t;
1281  firstfile = 0;
1282  } else
1283  iosm->lpath = linkpath;
1284 
1285  /* Write data after first link for tar. */
1286  rc = writeFile(iosm, (iosm->lpath == NULL));
1287  } else {
1288  /* Write data after last link for cpio. */
1289  rc = writeFile(iosm, (i == 0));
1290  }
1291  if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) {
1292  ec = rc;
1293  *iosm->failedFile = xstrdup(iosm->path);
1294  }
1295 
1296  iosm->path = _free(iosm->path);
1297  iosm->li->filex[i] = -1;
1298  }
1299 
1300 /*@-dependenttrans@*/
1301  linkpath = _free(linkpath);
1302 /*@=dependenttrans@*/
1303  iosm->ix = iterIndex;
1304  iosm->nsuffix = nsuffix;
1305  iosm->lpath = lpath;
1306  iosm->path = path;
1307  return ec;
1308 }
1309 
1315 /*@-compdef@*/
1316 static int iosmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t iosm)
1317  /*@uses iosm->path, iosm->opath, iosm->nsuffix, iosm->ix, iosm->li @*/
1318  /*@globals h_errno, fileSystem, internalState @*/
1319  /*@modifies iosm, fileSystem, internalState @*/
1320 {
1321  const char * path = iosm->path;
1322  const char * opath = iosm->opath;
1323  const char * nsuffix = iosm->nsuffix;
1324  int iterIndex = iosm->ix;
1325  int ec = 0;
1326  int rc;
1327  int i;
1328 
1329  iosm->path = NULL;
1330  iosm->opath = NULL;
1331  iosm->nsuffix = NULL;
1332  iosm->ix = -1;
1333 
1334  iosm->ix = iosm->li->filex[iosm->li->createdPath];
1335  rc = iosmNext(iosm, IOSM_MAP);
1336  iosm->opath = iosm->path;
1337  iosm->path = NULL;
1338  for (i = 0; i < iosm->li->nlink; i++) {
1339  if (iosm->li->filex[i] < 0) continue;
1340  if (iosm->li->createdPath == i) continue;
1341 
1342  iosm->ix = iosm->li->filex[i];
1343  iosm->path = _free(iosm->path);
1344  rc = iosmNext(iosm, IOSM_MAP);
1345  if (iosmFileActionSkipped(iosm->action)) continue;
1346 
1347  rc = iosmUNSAFE(iosm, IOSM_VERIFY);
1348  if (!rc) continue;
1349  if (!(rc == IOSMERR_ENOENT)) break;
1350 
1351  /* XXX link(iosm->opath, iosm->path) */
1352  rc = iosmNext(iosm, IOSM_LINK);
1353  if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) {
1354  ec = rc;
1355  *iosm->failedFile = xstrdup(iosm->path);
1356  }
1357 
1358  iosm->li->linksLeft--;
1359  }
1360  iosm->path = _free(iosm->path);
1361  iosm->opath = _free(iosm->opath);
1362 
1363  iosm->ix = iterIndex;
1364  iosm->nsuffix = nsuffix;
1365  iosm->path = path;
1366  iosm->opath = opath;
1367  return ec;
1368 }
1369 /*@=compdef@*/
1370 
1376 /*@-compdef@*/
1377 static int iosmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t iosm)
1378  /*@uses iosm->path, iosm->nsuffix, iosm->ix, iosm->sb,
1379  iosm->li, iosm->links @*/
1380  /*@globals h_errno, fileSystem, internalState @*/
1381  /*@modifies iosm, fileSystem, internalState @*/
1382 {
1383  const char * path = iosm->path;
1384  const char * nsuffix = iosm->nsuffix;
1385  int iterIndex = iosm->ix;
1386  struct stat * st = &iosm->sb;
1387  int rc = 0;
1388  int i;
1389 
1390  iosm->path = NULL;
1391  iosm->nsuffix = NULL;
1392  iosm->ix = -1;
1393 
1394  for (iosm->li = iosm->links; iosm->li; iosm->li = iosm->li->next) {
1395  if (iosm->li->sb.st_ino == st->st_ino && iosm->li->sb.st_dev == st->st_dev)
1396  break;
1397  }
1398 
1399  for (i = 0; i < iosm->li->nlink; i++) {
1400  if (iosm->li->filex[i] < 0) continue;
1401  iosm->ix = iosm->li->filex[i];
1402  rc = iosmNext(iosm, IOSM_MAP);
1403  if (!iosmFileActionSkipped(iosm->action))
1404  rc = iosmNext(iosm, IOSM_COMMIT);
1405  iosm->path = _free(iosm->path);
1406  iosm->li->filex[i] = -1;
1407  }
1408 
1409  iosm->ix = iterIndex;
1410  iosm->nsuffix = nsuffix;
1411  iosm->path = path;
1412  return rc;
1413 }
1414 /*@=compdef@*/
1415 
1421 static int iosmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t iosm)
1422  /*@uses iosm->path, iosm->dnlx, iosm->ldn, iosm->rdbuf, iosm->iter @*/
1423  /*@globals h_errno, fileSystem, internalState @*/
1424  /*@modifies iosm, fileSystem, internalState @*/
1425 {
1426  const char * path = iosm->path;
1427  void * dnli = dnlInitIterator(iosm, 1);
1428  char * dn = iosm->rdbuf;
1429  int dc = dnlCount(dnli);
1430  int rc = 0;
1431 
1432  iosm->path = NULL;
1433  dn[0] = '\0';
1434  /*@-observertrans -dependenttrans@*/
1435  if (iosm->ldn != NULL && iosm->dnlx != NULL)
1436  while ((iosm->path = dnlNextIterator(dnli)) != NULL) {
1437  size_t dnlen = strlen(iosm->path);
1438  char * te;
1439 
1440  dc = dnlIndex(dnli);
1441  if (iosm->dnlx[dc] < 1 || (size_t)iosm->dnlx[dc] >= dnlen)
1442  continue;
1443 
1444  /* Copy to avoid const on iosm->path. */
1445  te = stpcpy(dn, iosm->path) - 1;
1446  iosm->path = dn;
1447 
1448  /* Remove generated directories. */
1449  /*@-usereleased@*/ /* LCL: te used after release? */
1450  do {
1451  if (*te == '/') {
1452  *te = '\0';
1453 /*@-compdef@*/
1454  rc = iosmNext(iosm, IOSM_RMDIR);
1455 /*@=compdef@*/
1456  *te = '/';
1457  }
1458  if (rc)
1459  /*@innerbreak@*/ break;
1460  te--;
1461  } while ((te - iosm->path) > iosm->dnlx[dc]);
1462  /*@=usereleased@*/
1463  }
1464  dnli = dnlFreeIterator(dnli);
1465  /*@=observertrans =dependenttrans@*/
1466 
1467  iosm->path = path;
1468  return rc;
1469 }
1470 
1476 static int iosmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t iosm)
1477  /*@uses iosm->path, iosm->sb, iosm->osb, iosm->rdbuf, iosm->iter,
1478  iosm->ldn, iosm->ldnlen, iosm->ldnalloc @*/
1479  /*@defines iosm->dnlx, iosm->ldn @*/
1480  /*@globals h_errno, fileSystem, internalState @*/
1481  /*@modifies iosm, fileSystem, internalState @*/
1482 {
1483  struct stat * st = &iosm->sb;
1484  struct stat * ost = &iosm->osb;
1485  const char * path = iosm->path;
1486  mode_t st_mode = st->st_mode;
1487  void * dnli = dnlInitIterator(iosm, 0);
1488  char * dn = iosm->rdbuf;
1489  int dc = dnlCount(dnli);
1490  int rc = 0;
1491  size_t i;
1492 
1493  iosm->path = NULL;
1494 
1495  dn[0] = '\0';
1496  iosm->dnlx = (dc ? xcalloc(dc, sizeof(*iosm->dnlx)) : NULL);
1497  /*@-observertrans -dependenttrans@*/
1498  if (iosm->dnlx != NULL)
1499  while ((iosm->path = dnlNextIterator(dnli)) != NULL) {
1500  size_t dnlen = strlen(iosm->path);
1501  char * te;
1502 
1503  dc = dnlIndex(dnli);
1504  if (dc < 0) continue;
1505  iosm->dnlx[dc] = (unsigned short) dnlen;
1506  if (dnlen <= 1)
1507  continue;
1508 
1509  /*@-compdef -nullpass@*/ /* FIX: iosm->ldn not defined ??? */
1510  if (dnlen <= iosm->ldnlen && !strcmp(iosm->path, iosm->ldn))
1511  continue;
1512  /*@=compdef =nullpass@*/
1513 
1514  /* Copy to avoid const on iosm->path. */
1515  (void) stpcpy(dn, iosm->path);
1516  iosm->path = dn;
1517 
1518  /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
1519  (void) urlPath(dn, (const char **)&te);
1520  for (i = 1, te++; *te != '\0'; te++, i++) {
1521  if (*te != '/')
1522  /*@innercontinue@*/ continue;
1523 
1524  *te = '\0';
1525 
1526  /* Already validated? */
1527  /*@-usedef -compdef -nullpass -nullderef@*/
1528  if (i < iosm->ldnlen &&
1529  (iosm->ldn[i] == '/' || iosm->ldn[i] == '\0') &&
1530  !strncmp(iosm->path, iosm->ldn, i))
1531  {
1532  *te = '/';
1533  /* Move pre-existing path marker forward. */
1534  iosm->dnlx[dc] = (te - dn);
1535  /*@innercontinue@*/ continue;
1536  }
1537  /*@=usedef =compdef =nullpass =nullderef@*/
1538 
1539  /* Validate next component of path. */
1540  rc = iosmUNSAFE(iosm, IOSM_LSTAT);
1541  *te = '/';
1542 
1543  /* Directory already exists? */
1544  if (rc == 0 && S_ISDIR(ost->st_mode)) {
1545  /* Move pre-existing path marker forward. */
1546  iosm->dnlx[dc] = (te - dn);
1547  } else if (rc == IOSMERR_ENOENT) {
1548  rpmfi fi = iosmGetFi(iosm);
1549  *te = '\0';
1550  st->st_mode = S_IFDIR | (fi->dperms & 07777);
1551  rc = iosmNext(iosm, IOSM_MKDIR);
1552  if (!rc) {
1553 #if defined(_USE_RPMSX)
1554  security_context_t scon = NULL;
1555  /* XXX FIXME? only new dir will have context set. */
1556  /* Get file security context from patterns. */
1557  if (!fsm->nofcontexts
1558  && !matchpathcon(iosm->path, st->st_mode, &scon)
1559  && scon != NULL)
1560  {
1561  iosm->fcontext = scon;
1562  rc = iosmNext(iosm, IOSM_LSETFCON);
1563  } else
1564 #endif
1565  iosm->fcontext = NULL;
1566  if (iosm->fcontext == NULL)
1568  D_("%s directory created with perms %04o, no context.\n"),
1569  iosm->path, (unsigned)(st->st_mode & 07777));
1570  else {
1572  D_("%s directory created with perms %04o, context %s.\n"),
1573  iosm->path, (unsigned)(st->st_mode & 07777),
1574  iosm->fcontext);
1575 #if defined(_USE_RPMSX)
1576  iosm->fcontext = NULL;
1577  scon = _free(scon);
1578 #endif
1579  }
1580  }
1581  *te = '/';
1582  }
1583  if (rc)
1584  /*@innerbreak@*/ break;
1585  }
1586  if (rc) break;
1587 
1588  /* Save last validated path. */
1589 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
1590  if (iosm->ldnalloc < (dnlen + 1)) {
1591  iosm->ldnalloc = dnlen + 100;
1592  iosm->ldn = xrealloc(iosm->ldn, iosm->ldnalloc);
1593  }
1594  if (iosm->ldn != NULL) { /* XXX can't happen */
1595  strcpy(iosm->ldn, iosm->path);
1596  iosm->ldnlen = dnlen;
1597  }
1598 /*@=compdef@*/
1599  }
1600  dnli = dnlFreeIterator(dnli);
1601  /*@=observertrans =dependenttrans@*/
1602 
1603  iosm->path = path;
1604  st->st_mode = st_mode; /* XXX restore st->st_mode */
1605 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
1606  return rc;
1607 /*@=compdef@*/
1608 }
1609 
1610 #ifdef NOTYET
1611 
1616 static int iosmStat(/*@special@*/ /*@partial@*/ IOSM_t iosm)
1617  /*@globals fileSystem, internalState @*/
1618  /*@modifies iosm, fileSystem, internalState @*/
1619 {
1620  int rc = 0;
1621 
1622  if (iosm->path != NULL) {
1623  int saveernno = errno;
1624  rc = iosmUNSAFE(iosm, (!(iosm->mapFlags & IOSM_FOLLOW_SYMLINKS)
1625  ? IOSM_LSTAT : IOSM_STAT));
1626  if (rc == IOSMERR_ENOENT) {
1627  errno = saveerrno;
1628  rc = 0;
1629  iosm->exists = 0;
1630  } else if (rc == 0) {
1631  iosm->exists = 1;
1632  }
1633  } else {
1634  /* Skip %ghost files on build. */
1635  iosm->exists = 0;
1636  }
1637  return rc;
1638 }
1639 #endif
1640 
1641 #define IS_DEV_LOG(_x) \
1642  ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
1643  !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \
1644  ((_x)[sizeof("/dev/log")-1] == '\0' || \
1645  (_x)[sizeof("/dev/log")-1] == ';'))
1646 
1647 /*@-compmempass@*/
1649 {
1650 #ifdef NOTUSED
1651  iosmFileStage prevStage = iosm->stage;
1652  const char * const prev = iosmFileStageString(prevStage);
1653 #endif
1654  const char * const cur = iosmFileStageString(stage);
1655  struct stat * st = &iosm->sb;
1656  struct stat * ost = &iosm->osb;
1657  int saveerrno = errno;
1658  int rc = iosm->rc;
1659  size_t left;
1660  int i;
1661 
1662 #define _fafilter(_a) \
1663  (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
1664  ? iosmFileActionString(_a) : "")
1665 
1666  if (stage & IOSM_DEAD) {
1667  /* do nothing */
1668  } else if (stage & IOSM_INTERNAL) {
1669  if (iosm->debug && !(stage & IOSM_SYSCALL))
1670  rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n",
1671  cur,
1672  (unsigned)st->st_mode, (int)st->st_nlink,
1673  (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
1674  (iosm->path ? iosm->path : ""),
1675  _fafilter(iosm->action));
1676  } else {
1677  const char * apath = NULL;
1678  if (iosm->path)
1679  (void) urlPath(iosm->path, &apath);
1680  iosm->stage = stage;
1681  if (iosm->debug || !(stage & IOSM_VERBOSE))
1682  rpmlog(RPMLOG_DEBUG, "%-8s %06o%3d (%4d,%4d)%12lu %s %s\n",
1683  cur,
1684  (unsigned)st->st_mode, (int)st->st_nlink,
1685  (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
1686  (apath ? apath + iosm->astriplen : ""),
1687  _fafilter(iosm->action));
1688  }
1689 #undef _fafilter
1690 
1691  switch (stage) {
1692  case IOSM_UNKNOWN:
1693  break;
1694  case IOSM_PKGINSTALL:
1695  while (1) {
1696  /* Clean iosm, free'ing memory. Read next archive header. */
1697  rc = iosmUNSAFE(iosm, IOSM_INIT);
1698 
1699  /* Exit on end-of-payload. */
1700  if (rc == IOSMERR_HDR_TRAILER) {
1701  rc = 0;
1702  /*@loopbreak@*/ break;
1703  }
1704 
1705  /* Exit on error. */
1706  if (rc) {
1707  iosm->postpone = 1;
1708  (void) iosmNext(iosm, IOSM_UNDO);
1709  /*@loopbreak@*/ break;
1710  }
1711 
1712  /* Extract file from archive. */
1713  rc = iosmNext(iosm, IOSM_PROCESS);
1714  if (rc) {
1715  (void) iosmNext(iosm, IOSM_UNDO);
1716  /*@loopbreak@*/ break;
1717  }
1718 
1719  /* Notify on success. */
1720  (void) iosmNext(iosm, IOSM_NOTIFY);
1721 
1722  rc = iosmNext(iosm, IOSM_FINI);
1723  if (rc) {
1724  /*@loopbreak@*/ break;
1725  }
1726  }
1727  break;
1728  case IOSM_PKGERASE:
1729  case IOSM_PKGCOMMIT:
1730  while (1) {
1731  /* Clean iosm, free'ing memory. */
1732  rc = iosmUNSAFE(iosm, IOSM_INIT);
1733 
1734  /* Exit on end-of-payload. */
1735  if (rc == IOSMERR_HDR_TRAILER) {
1736  rc = 0;
1737  /*@loopbreak@*/ break;
1738  }
1739 
1740  /* Rename/erase next item. */
1741  if (iosmNext(iosm, IOSM_FINI))
1742  /*@loopbreak@*/ break;
1743  }
1744  break;
1745  case IOSM_PKGBUILD:
1746  while (1) {
1747 
1748  rc = iosmUNSAFE(iosm, IOSM_INIT);
1749 
1750  /* Exit on end-of-payload. */
1751  if (rc == IOSMERR_HDR_TRAILER) {
1752  rc = 0;
1753  /*@loopbreak@*/ break;
1754  }
1755 
1756  /* Exit on error. */
1757  if (rc) {
1758  iosm->postpone = 1;
1759  (void) iosmNext(iosm, IOSM_UNDO);
1760  /*@loopbreak@*/ break;
1761  }
1762 
1763  /* Copy file into archive. */
1764  rc = iosmNext(iosm, IOSM_PROCESS);
1765  if (rc) {
1766  (void) iosmNext(iosm, IOSM_UNDO);
1767  /*@loopbreak@*/ break;
1768  }
1769 
1770  /* Notify on success. */
1771  (void) iosmNext(iosm, IOSM_NOTIFY);
1772 
1773  if (iosmNext(iosm, IOSM_FINI))
1774  /*@loopbreak@*/ break;
1775  }
1776 
1777  /* Flush partial sets of hard linked files. */
1778  if (!(iosm->mapFlags & IOSM_ALL_HARDLINKS)) {
1779  int nlink, j;
1780  while ((iosm->li = iosm->links) != NULL) {
1781  iosm->links = iosm->li->next;
1782  iosm->li->next = NULL;
1783 
1784  /* Re-calculate link count for archive header. */
1785  for (j = -1, nlink = 0, i = 0; i < iosm->li->nlink; i++) {
1786  if (iosm->li->filex[i] < 0)
1787  /*@innercontinue@*/ continue;
1788  nlink++;
1789  if (j == -1) j = i;
1790  }
1791  /* XXX force the contents out as well. */
1792  if (j != 0) {
1793  iosm->li->filex[0] = iosm->li->filex[j];
1794  iosm->li->filex[j] = -1;
1795  }
1796  iosm->li->sb.st_nlink = nlink;
1797 
1798  iosm->sb = iosm->li->sb; /* structure assignment */
1799  iosm->osb = iosm->sb; /* structure assignment */
1800 
1801  if (!rc) rc = writeLinkedFile(iosm);
1802 
1803  iosm->li = freeHardLink(iosm->li);
1804  }
1805  }
1806 
1807  if (!rc)
1808  rc = iosmNext(iosm, IOSM_TRAILER);
1809 
1810  break;
1811  case IOSM_CREATE:
1812  iosm->path = _free(iosm->path);
1813  iosm->lpath = _free(iosm->lpath);
1814  iosm->opath = _free(iosm->opath);
1815  iosm->dnlx = _free(iosm->dnlx);
1816 
1817  iosm->ldn = _free(iosm->ldn);
1818  iosm->ldnalloc = iosm->ldnlen = 0;
1819 
1820  iosm->rdsize = iosm->wrsize = 0;
1821  iosm->rdbuf = iosm->rdb = _free(iosm->rdb);
1822  iosm->wrbuf = iosm->wrb = _free(iosm->wrb);
1823  if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
1824  iosm->rdsize = 16 * BUFSIZ;
1825  iosm->rdbuf = iosm->rdb = xmalloc(iosm->rdsize);
1826  iosm->wrsize = 16 * BUFSIZ;
1827  iosm->wrbuf = iosm->wrb = xmalloc(iosm->wrsize);
1828  }
1829 
1830  iosm->mkdirsdone = 0;
1831  iosm->ix = -1;
1832  iosm->links = NULL;
1833  iosm->li = NULL;
1834  errno = 0; /* XXX get rid of EBADF */
1835 
1836  /* Detect and create directories not explicitly in package. */
1837  if (iosm->goal == IOSM_PKGINSTALL) {
1838 /*@-compdef@*/
1839  rc = iosmNext(iosm, IOSM_MKDIRS);
1840 /*@=compdef@*/
1841  if (!rc) iosm->mkdirsdone = 1;
1842  }
1843 
1844  break;
1845  case IOSM_INIT:
1846  iosm->path = _free(iosm->path);
1847  iosm->lpath = _free(iosm->lpath);
1848  iosm->postpone = 0;
1849  iosm->diskchecked = iosm->exists = 0;
1850  iosm->subdir = NULL;
1851  iosm->suffix = (iosm->sufbuf[0] != '\0' ? iosm->sufbuf : NULL);
1852  iosm->action = FA_UNKNOWN;
1853  iosm->osuffix = NULL;
1854  iosm->nsuffix = NULL;
1855 
1856  if (iosm->goal == IOSM_PKGINSTALL) {
1857  /* Read next header from payload, checking for end-of-payload. */
1858  rc = iosmUNSAFE(iosm, IOSM_NEXT);
1859  }
1860  if (rc) break;
1861 
1862  /* Identify mapping index. */
1863  iosm->ix = ((iosm->goal == IOSM_PKGINSTALL)
1864  ? mapFind(iosm->iter, iosm->path) : mapNextIterator(iosm->iter));
1865 
1866 { rpmfi fi = iosmGetFi(iosm);
1867 if (!(fi->mapflags & IOSM_PAYLOAD_LIST)) {
1868  /* Detect end-of-loop and/or mapping error. */
1869 if (!(fi->mapflags & IOSM_PAYLOAD_EXTRACT)) {
1870  if (iosm->ix < 0) {
1871  if (iosm->goal == IOSM_PKGINSTALL) {
1872 #if 0
1874  _("archive file %s was not found in header file list\n"),
1875  iosm->path);
1876 #endif
1877  if (iosm->failedFile && *iosm->failedFile == NULL)
1878  *iosm->failedFile = xstrdup(iosm->path);
1879  rc = IOSMERR_UNMAPPED_FILE;
1880  } else {
1881  rc = IOSMERR_HDR_TRAILER;
1882  }
1883  break;
1884  }
1885 }
1886 
1887  /* On non-install, mode must be known so that dirs don't get suffix. */
1888  if (iosm->goal != IOSM_PKGINSTALL) {
1889  st->st_mode = fi->fmodes[iosm->ix];
1890  }
1891 }
1892 }
1893 
1894  /* Generate file path. */
1895  rc = iosmNext(iosm, IOSM_MAP);
1896  if (rc) break;
1897 
1898  /* Perform lstat/stat for disk file. */
1899 #ifdef NOTYET
1900  rc = iosmStat(iosm);
1901 #else
1902  if (iosm->path != NULL &&
1903  !(iosm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))
1904  {
1905  rc = iosmUNSAFE(iosm, (!(iosm->mapFlags & IOSM_FOLLOW_SYMLINKS)
1906  ? IOSM_LSTAT : IOSM_STAT));
1907  if (rc == IOSMERR_ENOENT) {
1908  errno = saveerrno;
1909  rc = 0;
1910  iosm->exists = 0;
1911  } else if (rc == 0) {
1912  iosm->exists = 1;
1913  }
1914  } else {
1915  /* Skip %ghost files on build. */
1916  iosm->exists = 0;
1917  }
1918 #endif
1919  iosm->diskchecked = 1;
1920  if (rc) break;
1921 
1922  /* On non-install, the disk file stat is what's remapped. */
1923  if (iosm->goal != IOSM_PKGINSTALL)
1924  *st = *ost; /* structure assignment */
1925 
1926  /* Remap file perms, owner, and group. */
1927  rc = iosmMapAttrs(iosm);
1928  if (rc) break;
1929 
1930  iosm->postpone = iosmFileActionSkipped(iosm->action);
1931  if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
1932  /*@-evalorder@*/ /* FIX: saveHardLink can modify iosm */
1933  if (S_ISREG(st->st_mode) && st->st_nlink > 1)
1934  iosm->postpone = saveHardLink(iosm);
1935  /*@=evalorder@*/
1936  }
1937 { rpmfi fi = iosmGetFi(iosm);
1938 if (fi->mapflags & IOSM_PAYLOAD_LIST) iosm->postpone = 1;
1939 }
1940  break;
1941  case IOSM_PRE:
1942  break;
1943  case IOSM_MAP:
1944  rc = iosmMapPath(iosm);
1945  break;
1946  case IOSM_MKDIRS:
1947  rc = iosmMkdirs(iosm);
1948  break;
1949  case IOSM_RMDIRS:
1950  if (iosm->dnlx)
1951  rc = iosmRmdirs(iosm);
1952  break;
1953  case IOSM_PROCESS:
1954  if (iosm->postpone) {
1955  if (iosm->goal == IOSM_PKGINSTALL) {
1956  /* XXX Skip over file body, archive headers already done. */
1957  if (S_ISREG(st->st_mode))
1958  rc = iosmNext(iosm, IOSM_EAT);
1959  }
1960  break;
1961  }
1962 
1963  if (iosm->goal == IOSM_PKGBUILD) {
1964  if (iosm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
1965  break;
1966  if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
1967  struct hardLink_s * li, * prev;
1968 
1969 if (!(iosm->mapFlags & IOSM_ALL_HARDLINKS)) break;
1970  rc = writeLinkedFile(iosm);
1971  if (rc) break; /* W2DO? */
1972 
1973  for (li = iosm->links, prev = NULL; li; prev = li, li = li->next)
1974  if (li == iosm->li)
1975  /*@loopbreak@*/ break;
1976 
1977  if (prev == NULL)
1978  iosm->links = iosm->li->next;
1979  else
1980  prev->next = iosm->li->next;
1981  iosm->li->next = NULL;
1982  iosm->li = freeHardLink(iosm->li);
1983  } else {
1984  rc = writeFile(iosm, 1);
1985  }
1986  break;
1987  }
1988 
1989  if (iosm->goal != IOSM_PKGINSTALL)
1990  break;
1991 
1992  if (S_ISREG(st->st_mode) && iosm->lpath != NULL) {
1993  const char * opath = iosm->opath;
1994  char * t = xmalloc(strlen(iosm->lpath+1) + strlen(iosm->suffix) + 1);
1995  (void) stpcpy(t, iosm->lpath+1);
1996  iosm->opath = t;
1997  /* XXX link(iosm->opath, iosm->path) */
1998  rc = iosmNext(iosm, IOSM_LINK);
1999  if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) {
2000  *iosm->failedFile = xstrdup(iosm->path);
2001  }
2002  iosm->opath = _free(iosm->opath);
2003  iosm->opath = opath;
2004  break; /* XXX so that delayed hard links get skipped. */
2005  }
2006  if (S_ISREG(st->st_mode)) {
2007  const char * path = iosm->path;
2008  if (iosm->osuffix)
2009  iosm->path = iosmFsPath(iosm, st, NULL, NULL);
2010  rc = iosmUNSAFE(iosm, IOSM_VERIFY);
2011 
2012  if (rc == 0 && iosm->osuffix) {
2013  const char * opath = iosm->opath;
2014  iosm->opath = iosm->path;
2015  iosm->path = iosmFsPath(iosm, st, NULL, iosm->osuffix);
2016  rc = iosmNext(iosm, IOSM_RENAME);
2017  if (!rc)
2019  _("%s saved as %s\n"),
2020  (iosm->opath ? iosm->opath : ""),
2021  (iosm->path ? iosm->path : ""));
2022  iosm->path = _free(iosm->path);
2023  iosm->opath = opath;
2024  }
2025 
2026  /*@-dependenttrans@*/
2027  iosm->path = path;
2028  /*@=dependenttrans@*/
2029  if (!(rc == IOSMERR_ENOENT)) return rc;
2030  rc = extractRegular(iosm);
2031  } else if (S_ISDIR(st->st_mode)) {
2032  mode_t st_mode = st->st_mode;
2033  rc = iosmUNSAFE(iosm, IOSM_VERIFY);
2034  if (rc == IOSMERR_ENOENT) {
2035  st->st_mode &= ~07777; /* XXX abuse st->st_mode */
2036  st->st_mode |= 00700;
2037  rc = iosmNext(iosm, IOSM_MKDIR);
2038  st->st_mode = st_mode; /* XXX restore st->st_mode */
2039  }
2040  } else if (S_ISLNK(st->st_mode)) {
2041 assert(iosm->lpath != NULL);
2042  rc = iosmUNSAFE(iosm, IOSM_VERIFY);
2043  if (rc == IOSMERR_ENOENT)
2044  rc = iosmNext(iosm, IOSM_SYMLINK);
2045  } else if (S_ISFIFO(st->st_mode)) {
2046  mode_t st_mode = st->st_mode;
2047  /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
2048  rc = iosmUNSAFE(iosm, IOSM_VERIFY);
2049  if (rc == IOSMERR_ENOENT) {
2050  st->st_mode = 0000; /* XXX abuse st->st_mode */
2051  rc = iosmNext(iosm, IOSM_MKFIFO);
2052  st->st_mode = st_mode; /* XXX restore st->st_mode */
2053  }
2054  } else if (S_ISCHR(st->st_mode) ||
2055  S_ISBLK(st->st_mode) ||
2056  /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
2057  {
2058  rc = iosmUNSAFE(iosm, IOSM_VERIFY);
2059  if (rc == IOSMERR_ENOENT)
2060  rc = iosmNext(iosm, IOSM_MKNOD);
2061  } else {
2062  /* XXX Repackaged payloads may be missing files. */
2063  if (iosm->repackaged)
2064  break;
2065 
2066  /* XXX Special case /dev/log, which shouldn't be packaged anyways */
2067  if (!IS_DEV_LOG(iosm->path))
2068  rc = IOSMERR_UNKNOWN_FILETYPE;
2069  }
2070  if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
2071  iosm->li->createdPath = iosm->li->linkIndex;
2072  rc = iosmMakeLinks(iosm);
2073  }
2074  break;
2075  case IOSM_POST:
2076  break;
2077  case IOSM_MKLINKS:
2078  rc = iosmMakeLinks(iosm);
2079  break;
2080  case IOSM_NOTIFY: /* XXX move from iosm to psm -> tsm */
2081  if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
2082  rpmfi fi = iosmGetFi(iosm);
2083  rpmuint64_t archivePos = fdGetCpioPos(iosm->cfd);
2084  if (archivePos > fi->archivePos) {
2085  fi->archivePos = (unsigned long long) archivePos;
2086 #if defined(_USE_RPMTS)
2087  (void) rpmtsNotify(iosmGetTs(iosm), fi->te,RPMCALLBACK_INST_PROGRESS,
2088  fi->archivePos, fi->archiveSize);
2089 #endif
2090  }
2091  }
2092  break;
2093  case IOSM_UNDO:
2094  if (iosm->postpone)
2095  break;
2096  if (iosm->goal == IOSM_PKGINSTALL) {
2097  /* XXX only erase if temp fn w suffix is in use */
2098  if (iosm->sufbuf[0] != '\0')
2099  (void) iosmNext(iosm,
2100  (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK));
2101 
2102 #ifdef NOTYET /* XXX remove only dirs just created, not all. */
2103  if (iosm->dnlx)
2104  (void) iosmNext(iosm, IOSM_RMDIRS);
2105 #endif
2106  errno = saveerrno;
2107  }
2108  if (iosm->failedFile && *iosm->failedFile == NULL)
2109  *iosm->failedFile = xstrdup(iosm->path);
2110  break;
2111  case IOSM_FINI:
2112  if (!iosm->postpone && iosm->commit) {
2113  if (iosm->goal == IOSM_PKGINSTALL)
2114  rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
2115  ? iosmCommitLinks(iosm) : iosmNext(iosm, IOSM_COMMIT));
2116  if (iosm->goal == IOSM_PKGCOMMIT)
2117  rc = iosmNext(iosm, IOSM_COMMIT);
2118  if (iosm->goal == IOSM_PKGERASE)
2119  rc = iosmNext(iosm, IOSM_COMMIT);
2120  }
2121  iosm->path = _free(iosm->path);
2122  iosm->lpath = _free(iosm->lpath);
2123  iosm->opath = _free(iosm->opath);
2124  memset(st, 0, sizeof(*st));
2125  memset(ost, 0, sizeof(*ost));
2126  break;
2127  case IOSM_COMMIT:
2128  /* Rename pre-existing modified or unmanaged file. */
2129  if (iosm->osuffix && iosm->diskchecked &&
2130  (iosm->exists || (iosm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))))
2131  {
2132  const char * opath = iosm->opath;
2133  const char * path = iosm->path;
2134  iosm->opath = iosmFsPath(iosm, st, NULL, NULL);
2135  iosm->path = iosmFsPath(iosm, st, NULL, iosm->osuffix);
2136  rc = iosmNext(iosm, IOSM_RENAME);
2137  if (!rc) {
2138  rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"),
2139  (iosm->opath ? iosm->opath : ""),
2140  (iosm->path ? iosm->path : ""));
2141  }
2142  iosm->path = _free(iosm->path);
2143  iosm->path = path;
2144  iosm->opath = _free(iosm->opath);
2145  iosm->opath = opath;
2146  }
2147 
2148  /* Remove erased files. */
2149  if (iosm->goal == IOSM_PKGERASE) {
2150  if (iosm->action == FA_ERASE) {
2151  if (S_ISDIR(st->st_mode)) {
2152  rc = iosmNext(iosm, IOSM_RMDIR);
2153  if (!rc) break;
2154  switch (rc) {
2155  case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
2156  case IOSMERR_ENOTEMPTY:
2157  /* XXX make sure that build side permits %missingok on directories. */
2158  if (iosm->fflags & RPMFILE_MISSINGOK)
2159  /*@innerbreak@*/ break;
2160 
2161  /* XXX common error message. */
2162  rpmlog(
2163  (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
2164  _("rmdir of %s failed: Directory not empty\n"),
2165  iosm->path);
2166  /*@innerbreak@*/ break;
2167  default:
2168  rpmlog(
2169  (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
2170  _("rmdir of %s failed: %s\n"),
2171  iosm->path, strerror(errno));
2172  /*@innerbreak@*/ break;
2173  }
2174  } else {
2175  rc = iosmNext(iosm, IOSM_UNLINK);
2176  if (!rc) break;
2177  switch (rc) {
2178  case IOSMERR_ENOENT:
2179  if (iosm->fflags & RPMFILE_MISSINGOK)
2180  /*@innerbreak@*/ break;
2181  /*@fallthrough@*/
2182  default:
2183  rpmlog(
2184  (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
2185  _("unlink of %s failed: %s\n"),
2186  iosm->path, strerror(errno));
2187  /*@innerbreak@*/ break;
2188  }
2189  }
2190  }
2191  /* XXX Failure to remove is not (yet) cause for failure. */
2192  if (!iosm->strict_erasures) rc = 0;
2193  break;
2194  }
2195 
2196  /* XXX Special case /dev/log, which shouldn't be packaged anyways */
2197 { rpmfi fi = iosmGetFi(iosm);
2198 if (!(fi->mapflags & IOSM_PAYLOAD_EXTRACT)) {
2199  if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(iosm->path)) {
2200  /* Rename temporary to final file name. */
2201  if (!S_ISDIR(st->st_mode) &&
2202  (iosm->subdir || iosm->suffix || iosm->nsuffix))
2203  {
2204  iosm->opath = iosm->path;
2205  iosm->path = iosmFsPath(iosm, st, NULL, iosm->nsuffix);
2206  rc = iosmNext(iosm, IOSM_RENAME);
2207  if (rc)
2208  (void) Unlink(iosm->opath);
2209  else if (iosm->nsuffix) {
2210  const char * opath = iosmFsPath(iosm, st, NULL, NULL);
2211  rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
2212  (opath ? opath : ""),
2213  (iosm->path ? iosm->path : ""));
2214  opath = _free(opath);
2215  }
2216  iosm->opath = _free(iosm->opath);
2217  }
2218  /*
2219  * Set file security context (if not disabled).
2220  */
2221  if (!rc && !getuid()) {
2222  rc = iosmMapFContext(iosm);
2223  if (!rc)
2224  rc = iosmNext(iosm, IOSM_LSETFCON);
2225  iosm->fcontext = NULL;
2226  }
2227  if (S_ISLNK(st->st_mode)) {
2228  if (!rc && !getuid())
2229  rc = iosmNext(iosm, IOSM_LCHOWN);
2230  } else {
2231  if (!rc && !getuid())
2232  rc = iosmNext(iosm, IOSM_CHOWN);
2233  if (!rc)
2234  rc = iosmNext(iosm, IOSM_CHMOD);
2235  if (!rc) {
2236  time_t mtime = st->st_mtime;
2237  if (fi->fmtimes)
2238  st->st_mtime = fi->fmtimes[iosm->ix];
2239  rc = iosmNext(iosm, IOSM_UTIME);
2240  st->st_mtime = mtime;
2241  }
2242  }
2243  }
2244 }
2245 }
2246 
2247  /* Notify on success. */
2248  if (!rc) rc = iosmNext(iosm, IOSM_NOTIFY);
2249  else if (iosm->failedFile && *iosm->failedFile == NULL) {
2250  *iosm->failedFile = iosm->path;
2251  iosm->path = NULL;
2252  }
2253  break;
2254  case IOSM_DESTROY:
2255  iosm->path = _free(iosm->path);
2256 
2257  /* Check for hard links missing from payload. */
2258  while ((iosm->li = iosm->links) != NULL) {
2259  iosm->links = iosm->li->next;
2260  iosm->li->next = NULL;
2261  if (iosm->goal == IOSM_PKGINSTALL &&
2262  iosm->commit && iosm->li->linksLeft)
2263  {
2264  for (i = 0 ; i < iosm->li->linksLeft; i++) {
2265  if (iosm->li->filex[i] < 0)
2266  /*@innercontinue@*/ continue;
2267  rc = IOSMERR_MISSING_HARDLINK;
2268  if (iosm->failedFile && *iosm->failedFile == NULL) {
2269  iosm->ix = iosm->li->filex[i];
2270  if (!iosmNext(iosm, IOSM_MAP)) {
2271  *iosm->failedFile = iosm->path;
2272  iosm->path = NULL;
2273  }
2274  }
2275  /*@loopbreak@*/ break;
2276  }
2277  }
2278  if (iosm->goal == IOSM_PKGBUILD &&
2279  (iosm->mapFlags & IOSM_ALL_HARDLINKS))
2280  {
2281  rc = IOSMERR_MISSING_HARDLINK;
2282  }
2283  iosm->li = freeHardLink(iosm->li);
2284  }
2285  iosm->ldn = _free(iosm->ldn);
2286  iosm->ldnalloc = iosm->ldnlen = 0;
2287  iosm->rdbuf = iosm->rdb = _free(iosm->rdb);
2288  iosm->wrbuf = iosm->wrb = _free(iosm->wrb);
2289  break;
2290  case IOSM_VERIFY:
2291  if (iosm->diskchecked && !iosm->exists) {
2292  rc = IOSMERR_ENOENT;
2293  break;
2294  }
2295  if (S_ISREG(st->st_mode)) {
2296  char * path = alloca(strlen(iosm->path) + sizeof("-RPMDELETE"));
2297  (void) stpcpy( stpcpy(path, iosm->path), "-RPMDELETE");
2298  /*
2299  * XXX HP-UX (and other os'es) don't permit unlink on busy
2300  * XXX files.
2301  */
2302  iosm->opath = iosm->path;
2303  iosm->path = path;
2304  rc = iosmNext(iosm, IOSM_RENAME);
2305  if (!rc)
2306  (void) iosmNext(iosm, IOSM_UNLINK);
2307  else
2308  rc = IOSMERR_UNLINK_FAILED;
2309  iosm->path = iosm->opath;
2310  iosm->opath = NULL;
2311  return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */
2312  /*@notreached@*/ break;
2313  } else if (S_ISDIR(st->st_mode)) {
2314  if (S_ISDIR(ost->st_mode)) return 0;
2315  if (S_ISLNK(ost->st_mode)) {
2316  rc = iosmUNSAFE(iosm, IOSM_STAT);
2317  if (rc == IOSMERR_ENOENT) rc = 0;
2318  if (rc) break;
2319  errno = saveerrno;
2320  if (S_ISDIR(ost->st_mode)) return 0;
2321  }
2322  } else if (S_ISLNK(st->st_mode)) {
2323  if (S_ISLNK(ost->st_mode)) {
2324  /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */
2325  rc = iosmUNSAFE(iosm, IOSM_READLINK);
2326  errno = saveerrno;
2327  if (rc) break;
2328  if (!strcmp(iosm->lpath, iosm->rdbuf)) return 0;
2329  }
2330  } else if (S_ISFIFO(st->st_mode)) {
2331  if (S_ISFIFO(ost->st_mode)) return 0;
2332  } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
2333  if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
2334  (ost->st_rdev == st->st_rdev)) return 0;
2335  } else if (S_ISSOCK(st->st_mode)) {
2336  if (S_ISSOCK(ost->st_mode)) return 0;
2337  }
2338  /* XXX shouldn't do this with commit/undo. */
2339  rc = 0;
2340  if (iosm->stage == IOSM_PROCESS) rc = iosmNext(iosm, IOSM_UNLINK);
2341  if (rc == 0) rc = IOSMERR_ENOENT;
2342  return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */
2343  /*@notreached@*/ break;
2344 
2345  case IOSM_UNLINK:
2346  /* XXX Remove setuid/setgid bits on possibly hard linked files. */
2347  if (iosm->mapFlags & IOSM_SBIT_CHECK) {
2348  struct stat stb;
2349  if (Lstat(iosm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
2350  /* XXX rc = iosmNext(iosm, IOSM_CHMOD); instead */
2351  (void)Chmod(iosm->path, stb.st_mode & 0777);
2352  }
2353  }
2354  rc = Unlink(iosm->path);
2355  if (iosm->debug && (stage & IOSM_SYSCALL))
2356  rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", cur,
2357  iosm->path, (rc < 0 ? strerror(errno) : ""));
2358  if (rc < 0)
2359  rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_UNLINK_FAILED);
2360  break;
2361  case IOSM_RENAME:
2362  /* XXX Remove setuid/setgid bits on possibly hard linked files. */
2363  if (iosm->mapFlags & IOSM_SBIT_CHECK) {
2364  struct stat stb;
2365  if (Lstat(iosm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
2366  /* XXX rc = iosmNext(iosm, IOSM_CHMOD); instead */
2367  (void)Chmod(iosm->path, stb.st_mode & 0777);
2368  }
2369  }
2370  rc = Rename(iosm->opath, iosm->path);
2371  /* XXX Repackaged payloads may be missing files. */
2372  if (iosm->repackaged)
2373  rc = 0;
2374 #if defined(ETXTBSY)
2375  if (rc && errno == ETXTBSY) {
2376  char * path = alloca(strlen(iosm->path) + sizeof("-RPMDELETE"));
2377  (void) stpcpy( stpcpy(path, iosm->path), "-RPMDELETE");
2378  /*
2379  * XXX HP-UX (and other os'es) don't permit rename to busy
2380  * XXX files.
2381  */
2382  rc = Rename(iosm->path, path);
2383  if (!rc) rc = Rename(iosm->opath, iosm->path);
2384  }
2385 #endif
2386  if (iosm->debug && (stage & IOSM_SYSCALL))
2387  rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
2388  iosm->opath, iosm->path, (rc < 0 ? strerror(errno) : ""));
2389  if (rc < 0) rc = IOSMERR_RENAME_FAILED;
2390  break;
2391  case IOSM_MKDIR:
2392  rc = Mkdir(iosm->path, (st->st_mode & 07777));
2393  if (iosm->debug && (stage & IOSM_SYSCALL))
2394  rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
2395  iosm->path, (unsigned)(st->st_mode & 07777),
2396  (rc < 0 ? strerror(errno) : ""));
2397  if (rc < 0) rc = IOSMERR_MKDIR_FAILED;
2398  break;
2399  case IOSM_RMDIR:
2400  rc = Rmdir(iosm->path);
2401  if (iosm->debug && (stage & IOSM_SYSCALL))
2402  rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", cur,
2403  iosm->path, (rc < 0 ? strerror(errno) : ""));
2404  if (rc < 0)
2405  switch (errno) {
2406  case ENOENT: rc = IOSMERR_ENOENT; /*@switchbreak@*/ break;
2407  case ENOTEMPTY: rc = IOSMERR_ENOTEMPTY; /*@switchbreak@*/ break;
2408  default: rc = IOSMERR_RMDIR_FAILED; /*@switchbreak@*/ break;
2409  }
2410  break;
2411  case IOSM_LSETFCON:
2412  { const char * iosmpath = NULL;
2413  if (iosm->fcontext == NULL || *iosm->fcontext == '\0'
2414  || !strcmp(iosm->fcontext, "<<none>>"))
2415  break;
2416  (void) urlPath(iosm->path, &iosmpath); /* XXX iosm->path */
2417  rc = lsetfilecon(iosmpath, (security_context_t)iosm->fcontext);
2418  if (iosm->debug && (stage & IOSM_SYSCALL))
2419  rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
2420  iosm->path, iosm->fcontext,
2421  (rc < 0 ? strerror(errno) : ""));
2422  if (rc < 0) rc = (errno == EOPNOTSUPP ? 0 : IOSMERR_LSETFCON_FAILED);
2423  } break;
2424  case IOSM_CHOWN:
2425  rc = Chown(iosm->path, st->st_uid, st->st_gid);
2426  if (iosm->debug && (stage & IOSM_SYSCALL))
2427  rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
2428  iosm->path, (int)st->st_uid, (int)st->st_gid,
2429  (rc < 0 ? strerror(errno) : ""));
2430  if (rc < 0) rc = IOSMERR_CHOWN_FAILED;
2431  break;
2432  case IOSM_LCHOWN:
2433 #if ! CHOWN_FOLLOWS_SYMLINK
2434  rc = Lchown(iosm->path, st->st_uid, st->st_gid);
2435  if (iosm->debug && (stage & IOSM_SYSCALL))
2436  rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
2437  iosm->path, (int)st->st_uid, (int)st->st_gid,
2438  (rc < 0 ? strerror(errno) : ""));
2439  if (rc < 0) rc = IOSMERR_CHOWN_FAILED;
2440 #endif
2441  break;
2442  case IOSM_CHMOD:
2443  rc = Chmod(iosm->path, (st->st_mode & 07777));
2444  if (iosm->debug && (stage & IOSM_SYSCALL))
2445  rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
2446  iosm->path, (unsigned)(st->st_mode & 07777),
2447  (rc < 0 ? strerror(errno) : ""));
2448  if (rc < 0) rc = IOSMERR_CHMOD_FAILED;
2449  break;
2450  case IOSM_UTIME:
2451  { struct utimbuf stamp;
2452  stamp.actime = st->st_mtime;
2453  stamp.modtime = st->st_mtime;
2454  rc = Utime(iosm->path, &stamp);
2455  if (iosm->debug && (stage & IOSM_SYSCALL))
2456  rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
2457  iosm->path, (unsigned)st->st_mtime,
2458  (rc < 0 ? strerror(errno) : ""));
2459  if (rc < 0) rc = IOSMERR_UTIME_FAILED;
2460  }
2461  break;
2462  case IOSM_SYMLINK:
2463  rc = Symlink(iosm->lpath, iosm->path);
2464  if (iosm->debug && (stage & IOSM_SYSCALL))
2465  rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
2466  iosm->lpath, iosm->path, (rc < 0 ? strerror(errno) : ""));
2467  if (rc < 0) rc = IOSMERR_SYMLINK_FAILED;
2468  break;
2469  case IOSM_LINK:
2470  rc = Link(iosm->opath, iosm->path);
2471  if (iosm->debug && (stage & IOSM_SYSCALL))
2472  rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
2473  iosm->opath, iosm->path, (rc < 0 ? strerror(errno) : ""));
2474  if (rc < 0) rc = IOSMERR_LINK_FAILED;
2475  break;
2476  case IOSM_MKFIFO:
2477  rc = Mkfifo(iosm->path, (st->st_mode & 07777));
2478  if (iosm->debug && (stage & IOSM_SYSCALL))
2479  rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
2480  iosm->path, (unsigned)(st->st_mode & 07777),
2481  (rc < 0 ? strerror(errno) : ""));
2482  if (rc < 0) rc = IOSMERR_MKFIFO_FAILED;
2483  break;
2484  case IOSM_MKNOD:
2485  /*@-unrecog -portability @*/ /* FIX: check S_IFIFO or dev != 0 */
2486  rc = Mknod(iosm->path, (st->st_mode & ~07777), st->st_rdev);
2487  /*@=unrecog =portability @*/
2488  if (iosm->debug && (stage & IOSM_SYSCALL))
2489  rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
2490  iosm->path, (unsigned)(st->st_mode & ~07777),
2491  (unsigned)st->st_rdev,
2492  (rc < 0 ? strerror(errno) : ""));
2493  if (rc < 0) rc = IOSMERR_MKNOD_FAILED;
2494  break;
2495  case IOSM_LSTAT:
2496  rc = Lstat(iosm->path, ost);
2497  if (iosm->debug && (stage & IOSM_SYSCALL) && rc && errno != ENOENT)
2498  rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", cur,
2499  iosm->path, (rc < 0 ? strerror(errno) : ""));
2500  if (rc < 0) {
2501  rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_LSTAT_FAILED);
2502  memset(ost, 0, sizeof(*ost)); /* XXX s390x hackery */
2503  }
2504  break;
2505  case IOSM_STAT:
2506  rc = Stat(iosm->path, ost);
2507  if (iosm->debug && (stage & IOSM_SYSCALL) && rc && errno != ENOENT)
2508  rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", cur,
2509  iosm->path, (rc < 0 ? strerror(errno) : ""));
2510  if (rc < 0) {
2511  rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_STAT_FAILED);
2512  memset(ost, 0, sizeof(*ost)); /* XXX s390x hackery */
2513  }
2514  break;
2515  case IOSM_READLINK:
2516  /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */
2517  rc = Readlink(iosm->path, iosm->rdbuf, iosm->rdsize - 1);
2518  if (iosm->debug && (stage & IOSM_SYSCALL))
2519  rpmlog(RPMLOG_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
2520  iosm->path, (int)(iosm->rdsize -1), (rc < 0 ? strerror(errno) : ""));
2521  if (rc < 0) rc = IOSMERR_READLINK_FAILED;
2522  else {
2523  iosm->rdnb = rc;
2524  iosm->rdbuf[iosm->rdnb] = '\0';
2525  rc = 0;
2526  }
2527  break;
2528  case IOSM_CHROOT:
2529  break;
2530 
2531  case IOSM_NEXT:
2532  rc = iosmUNSAFE(iosm, IOSM_HREAD);
2533  if (rc) break;
2534  if (!strcmp(iosm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
2535  iosm->path = _free(iosm->path);
2536  rc = IOSMERR_HDR_TRAILER;
2537  }
2538  if (!rc)
2539  rc = iosmNext(iosm, IOSM_POS);
2540  break;
2541  case IOSM_EAT:
2542  for (left = st->st_size; left > 0; left -= iosm->rdnb) {
2543  iosm->wrlen = (left > iosm->wrsize ? iosm->wrsize : left);
2544  rc = iosmNext(iosm, IOSM_DREAD);
2545  if (rc)
2546  /*@loopbreak@*/ break;
2547  }
2548  break;
2549  case IOSM_POS:
2550  left = (iosm->blksize - (fdGetCpioPos(iosm->cfd) % iosm->blksize)) % iosm->blksize;
2551  if (left) {
2552  iosm->wrlen = left;
2553  (void) iosmNext(iosm, IOSM_DREAD);
2554  }
2555  break;
2556  case IOSM_PAD:
2557  left = (iosm->blksize - (fdGetCpioPos(iosm->cfd) % iosm->blksize)) % iosm->blksize;
2558  if (left) {
2559  if (iosm->blksize == 2)
2560  iosm->rdbuf[0] = '\n'; /* XXX ar(1) pads with '\n' */
2561  else
2562  memset(iosm->rdbuf, 0, left);
2563  /* XXX DWRITE uses rdnb for I/O length. */
2564  iosm->rdnb = left;
2565  (void) iosmNext(iosm, IOSM_DWRITE);
2566  }
2567  break;
2568  case IOSM_TRAILER:
2569  rc = (*iosm->trailerWrite) (iosm); /* Write payload trailer. */
2570  break;
2571  case IOSM_HREAD:
2572  rc = iosmNext(iosm, IOSM_POS);
2573  if (!rc)
2574  rc = (*iosm->headerRead) (iosm, st); /* Read next payload header. */
2575  break;
2576  case IOSM_HWRITE:
2577  rc = (*iosm->headerWrite) (iosm, st); /* Write next payload header. */
2578  break;
2579  case IOSM_DREAD:
2580  iosm->rdnb = Fread(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->wrlen, iosm->cfd);
2581  if (iosm->debug && (stage & IOSM_SYSCALL))
2582  rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
2583  cur, (iosm->wrbuf == iosm->wrb ? "wrbuf" : "mmap"),
2584  (int)iosm->wrlen, (int)iosm->rdnb);
2585  if (iosm->rdnb != iosm->wrlen || Ferror(iosm->cfd))
2586  rc = IOSMERR_READ_FAILED;
2587  if (iosm->rdnb > 0)
2588  fdSetCpioPos(iosm->cfd, fdGetCpioPos(iosm->cfd) + iosm->rdnb);
2589  break;
2590  case IOSM_DWRITE:
2591  iosm->wrnb = Fwrite(iosm->rdbuf, sizeof(*iosm->rdbuf), iosm->rdnb, iosm->cfd);
2592  if (iosm->debug && (stage & IOSM_SYSCALL))
2593  rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
2594  cur, (iosm->rdbuf == iosm->rdb ? "rdbuf" : "mmap"),
2595  (int)iosm->rdnb, (int)iosm->wrnb);
2596  if (iosm->rdnb != iosm->wrnb || Ferror(iosm->cfd))
2597  rc = IOSMERR_WRITE_FAILED;
2598  if (iosm->wrnb > 0)
2599  fdSetCpioPos(iosm->cfd, fdGetCpioPos(iosm->cfd) + iosm->wrnb);
2600  break;
2601 
2602  case IOSM_ROPEN:
2603  iosm->rfd = Fopen(iosm->path, "r.fdio");
2604  if (iosm->rfd == NULL || Ferror(iosm->rfd)) {
2605  if (iosm->rfd != NULL) (void) iosmNext(iosm, IOSM_RCLOSE);
2606  iosm->rfd = NULL;
2607  rc = IOSMERR_OPEN_FAILED;
2608  break;
2609  }
2610  if (iosm->debug && (stage & IOSM_SYSCALL))
2611  rpmlog(RPMLOG_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
2612  iosm->path, iosm->rfd, iosm->rdbuf);
2613  break;
2614  case IOSM_READ:
2615  iosm->rdnb = Fread(iosm->rdbuf, sizeof(*iosm->rdbuf), iosm->rdlen, iosm->rfd);
2616  if (iosm->debug && (stage & IOSM_SYSCALL))
2617  rpmlog(RPMLOG_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
2618  cur, (int)iosm->rdlen, (int)iosm->rdnb);
2619  if (iosm->rdnb != iosm->rdlen || Ferror(iosm->rfd))
2620  rc = IOSMERR_READ_FAILED;
2621  break;
2622  case IOSM_RCLOSE:
2623  if (iosm->rfd != NULL) {
2624  if (iosm->debug && (stage & IOSM_SYSCALL))
2625  rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->rfd);
2626  (void) rpmswAdd(&iosm->op_digest,
2627  fdstat_op(iosm->rfd, FDSTAT_DIGEST));
2628  (void) Fclose(iosm->rfd);
2629  errno = saveerrno;
2630  }
2631  iosm->rfd = NULL;
2632  break;
2633  case IOSM_WOPEN:
2634  iosm->wfd = Fopen(iosm->path, "w.fdio");
2635  if (iosm->wfd == NULL || Ferror(iosm->wfd)) {
2636  if (iosm->wfd != NULL) (void) iosmNext(iosm, IOSM_WCLOSE);
2637  iosm->wfd = NULL;
2638  rc = IOSMERR_OPEN_FAILED;
2639  }
2640  if (iosm->debug && (stage & IOSM_SYSCALL))
2641  rpmlog(RPMLOG_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
2642  iosm->path, iosm->wfd, iosm->wrbuf);
2643  break;
2644  case IOSM_WRITE:
2645  iosm->wrnb = Fwrite(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->rdnb, iosm->wfd);
2646  if (iosm->debug && (stage & IOSM_SYSCALL))
2647  rpmlog(RPMLOG_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
2648  cur, (int)iosm->rdnb, (int)iosm->wrnb);
2649  if (iosm->rdnb != iosm->wrnb || Ferror(iosm->wfd))
2650  rc = IOSMERR_WRITE_FAILED;
2651  break;
2652  case IOSM_WCLOSE:
2653  if (iosm->wfd != NULL) {
2654  if (iosm->debug && (stage & IOSM_SYSCALL))
2655  rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->wfd);
2656  (void) rpmswAdd(&iosm->op_digest,
2657  fdstat_op(iosm->wfd, FDSTAT_DIGEST));
2658  (void) Fclose(iosm->wfd);
2659  errno = saveerrno;
2660  }
2661  iosm->wfd = NULL;
2662  break;
2663 
2664  default:
2665  break;
2666  }
2667 
2668  if (!(stage & IOSM_INTERNAL)) {
2669  iosm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc);
2670  }
2671  return rc;
2672 }
2673 /*@=compmempass@*/
2674 
2675 #define IOSM_SKIPPING(_a) \
2676  ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR)
2677 
2679 {
2680  return IOSM_SKIPPING(action);
2681 }
2682 
2683 /*@observer@*/ const char * iosmFileActionString(iosmFileAction a)
2684 {
2685  switch (a) {
2686  case FA_UNKNOWN: return "unknown";
2687  case FA_CREATE: return "create";
2688  case FA_COPYOUT: return "copyout";
2689  case FA_COPYIN: return "copyin";
2690  case FA_BACKUP: return "backup";
2691  case FA_SAVE: return "save";
2692  case FA_SKIP: return "skip";
2693  case FA_ALTNAME: return "altname";
2694  case FA_ERASE: return "erase";
2695  case FA_SKIPNSTATE: return "skipnstate";
2696  case FA_SKIPNETSHARED: return "skipnetshared";
2697  case FA_SKIPCOLOR: return "skipcolor";
2698  default: return "???";
2699  }
2700  /*@notreached@*/
2701 }
2702 
2703 /*@observer@*/ const char * iosmFileStageString(iosmFileStage a) {
2704  switch(a) {
2705  case IOSM_UNKNOWN: return "unknown";
2706 
2707  case IOSM_PKGINSTALL:return "INSTALL";
2708  case IOSM_PKGERASE: return "ERASE";
2709  case IOSM_PKGBUILD: return "BUILD";
2710  case IOSM_PKGCOMMIT: return "COMMIT";
2711  case IOSM_PKGUNDO: return "UNDO";
2712 
2713  case IOSM_CREATE: return "create";
2714  case IOSM_INIT: return "init";
2715  case IOSM_MAP: return "map";
2716  case IOSM_MKDIRS: return "mkdirs";
2717  case IOSM_RMDIRS: return "rmdirs";
2718  case IOSM_PRE: return "pre";
2719  case IOSM_PROCESS: return "process";
2720  case IOSM_POST: return "post";
2721  case IOSM_MKLINKS: return "mklinks";
2722  case IOSM_NOTIFY: return "notify";
2723  case IOSM_UNDO: return "undo";
2724  case IOSM_FINI: return "fini";
2725  case IOSM_COMMIT: return "commit";
2726  case IOSM_DESTROY: return "destroy";
2727  case IOSM_VERIFY: return "verify";
2728 
2729  case IOSM_UNLINK: return "Unlink";
2730  case IOSM_RENAME: return "Rename";
2731  case IOSM_MKDIR: return "Mkdir";
2732  case IOSM_RMDIR: return "Rmdir";
2733  case IOSM_LSETFCON: return "lsetfcon";
2734  case IOSM_CHOWN: return "Chown";
2735  case IOSM_LCHOWN: return "Lchown";
2736  case IOSM_CHMOD: return "Chmod";
2737  case IOSM_UTIME: return "Utime";
2738  case IOSM_SYMLINK: return "Symlink";
2739  case IOSM_LINK: return "Link";
2740  case IOSM_MKFIFO: return "Mkfifo";
2741  case IOSM_MKNOD: return "Mknod";
2742  case IOSM_LSTAT: return "Lstat";
2743  case IOSM_STAT: return "Stat";
2744  case IOSM_READLINK: return "Readlink";
2745  case IOSM_CHROOT: return "Chroot";
2746 
2747  case IOSM_NEXT: return "next";
2748  case IOSM_EAT: return "eat";
2749  case IOSM_POS: return "pos";
2750  case IOSM_PAD: return "pad";
2751  case IOSM_TRAILER: return "trailer";
2752  case IOSM_HREAD: return "hread";
2753  case IOSM_HWRITE: return "hwrite";
2754  case IOSM_DREAD: return "Fread";
2755  case IOSM_DWRITE: return "Fwrite";
2756 
2757  case IOSM_ROPEN: return "Fopen";
2758  case IOSM_READ: return "Fread";
2759  case IOSM_RCLOSE: return "Fclose";
2760  case IOSM_WOPEN: return "Fopen";
2761  case IOSM_WRITE: return "Fwrite";
2762  case IOSM_WCLOSE: return "Fclose";
2763 
2764  default: return "???";
2765  }
2766  /*@noteached@*/
2767 }
2768 
2769 char * iosmStrerror(int rc)
2770 {
2771  char msg[256];
2772  char *s;
2773  int l, myerrno = errno;
2774 
2775  strcpy(msg, "cpio: ");
2776  switch (rc) {
2777  default:
2778  s = msg + strlen(msg);
2779  sprintf(s, _("(error 0x%x)"), (unsigned)rc);
2780  s = NULL;
2781  break;
2782  case IOSMERR_BAD_MAGIC: s = _("Bad magic"); break;
2783  case IOSMERR_BAD_HEADER: s = _("Bad/unreadable header"); break;
2784 
2785  case IOSMERR_OPEN_FAILED: s = "open"; break;
2786  case IOSMERR_CHMOD_FAILED: s = "chmod"; break;
2787  case IOSMERR_CHOWN_FAILED: s = "chown"; break;
2788  case IOSMERR_WRITE_FAILED: s = "write"; break;
2789  case IOSMERR_UTIME_FAILED: s = "utime"; break;
2790  case IOSMERR_UNLINK_FAILED: s = "unlink"; break;
2791  case IOSMERR_RENAME_FAILED: s = "rename"; break;
2792  case IOSMERR_SYMLINK_FAILED: s = "symlink"; break;
2793  case IOSMERR_STAT_FAILED: s = "stat"; break;
2794  case IOSMERR_LSTAT_FAILED: s = "lstat"; break;
2795  case IOSMERR_MKDIR_FAILED: s = "mkdir"; break;
2796  case IOSMERR_RMDIR_FAILED: s = "rmdir"; break;
2797  case IOSMERR_MKNOD_FAILED: s = "mknod"; break;
2798  case IOSMERR_MKFIFO_FAILED: s = "mkfifo"; break;
2799  case IOSMERR_LINK_FAILED: s = "link"; break;
2800  case IOSMERR_READLINK_FAILED: s = "readlink"; break;
2801  case IOSMERR_READ_FAILED: s = "read"; break;
2802  case IOSMERR_COPY_FAILED: s = "copy"; break;
2803  case IOSMERR_LSETFCON_FAILED: s = "lsetfilecon"; break;
2804 
2805  case IOSMERR_HDR_SIZE: s = _("Header size too big"); break;
2806  case IOSMERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
2807  case IOSMERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break;
2808  case IOSMERR_DIGEST_MISMATCH: s = _("File digest mismatch"); break;
2809  case IOSMERR_INTERNAL: s = _("Internal error"); break;
2810  case IOSMERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
2811  case IOSMERR_ENOENT: s = strerror(ENOENT); break;
2812  case IOSMERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break;
2813  }
2814 
2815  l = sizeof(msg) - strlen(msg) - 1;
2816  if (s != NULL) {
2817  if (l > 0) strncat(msg, s, l);
2818  l -= strlen(s);
2819  }
2820  if ((rc & IOSMERR_CHECK_ERRNO) && myerrno) {
2821  s = _(" failed - ");
2822  if (l > 0) strncat(msg, s, l);
2823  l -= strlen(s);
2824  if (l > 0) strncat(msg, strerror(myerrno), l);
2825  }
2826  return xstrdup(msg);
2827 }