rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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
28 typedef iosmMapFlags cpioMapFlags;
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@*/
67 int _iosm_debug = _IOSM_DEBUG;
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 *
163 mapInitIterator(rpmfi fi, int reverse)
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;
397 rpmlog(RPMLOG_DEBUG,
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
565 IOSM_t newIOSM(void)
566 {
567 IOSM_t iosm = xcalloc(1, sizeof(*iosm));
568 return iosm;
569 }
570
571 IOSM_t freeIOSM(IOSM_t iosm)
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
793 int iosmTeardown(IOSM_t iosm)
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
855 int iosmMapPath(IOSM_t iosm)
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
946 int iosmMapAttrs(IOSM_t iosm)
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)
973 rpmlog(RPMLOG_WARNING,
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)
987 rpmlog(RPMLOG_WARNING,
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)
1567 rpmlog(RPMLOG_DEBUG,
1568 D_("%s directory created with perms %04o, no context.\n"),
1569 iosm->path, (unsigned)(st->st_mode & 07777));
1570 else {
1571 rpmlog(RPMLOG_DEBUG,
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@*/
1648 int iosmStage(IOSM_t iosm, iosmFileStage stage)
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
1873 rpmlog(RPMLOG_WARNING,
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)
2018 rpmlog(RPMLOG_WARNING,
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
2678 int iosmFileActionSkipped(iosmFileAction action)
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 }