rpm 5.3.12
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio_internal.h> /* XXX urlPath, fdGetCpioPos */ 00009 #include <rpmcb.h> /* XXX fnpyKey */ 00010 #include <ugid.h> /* XXX unameToUid() and gnameToGid() */ 00011 00012 #include <rpmsq.h> /* XXX rpmsqJoin()/rpmsqThread() */ 00013 #include <rpmsw.h> /* XXX rpmswAdd() */ 00014 #include <rpmsx.h> 00015 00016 #include "../rpmdb/rpmtag.h" 00017 00018 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmts_s * rpmts; 00019 typedef /*@abstract@*/ struct rpmte_s * rpmte; 00020 00021 #define _IOSM_INTERNAL 00022 #include <iosm.h> 00023 #define iosmUNSAFE iosmStage 00024 00025 #include "cpio.h" 00026 #include "tar.h" 00027 #include "ar.h" 00028 00029 typedef iosmMapFlags cpioMapFlags; 00030 #define _RPMFI_INTERNAL 00031 #define _RPMFI_NOMETHODS 00032 #include "../lib/rpmfi.h" 00033 00034 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmds_s * rpmds; 00035 typedef struct rpmRelocation_s * rpmRelocation; 00036 #undef _USE_RPMTE 00037 #if defined(_USE_RPMTE) 00038 typedef /*@abstract@*/ void * alKey; 00039 #include "rpmte.h" 00040 #endif 00041 00042 #undef _USE_RPMSX 00043 #if defined(_USE_RPMSX) 00044 #include "../lib/rpmsx.h" /* XXX rpmsx rpmsxFContext rpmsxFree */ 00045 #endif 00046 00047 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmdb_s * rpmdb; 00048 typedef /*@abstract@*/ struct rpmmi_s * rpmmi; 00049 typedef struct rpmPRCO_s * rpmPRCO; 00050 typedef struct Spec_s * Spec; 00051 #undef _USE_RPMTS 00052 #if defined(_USE_RPMTS) 00053 #include "rpmts.h" 00054 #endif 00055 00056 #include "debug.h" 00057 00058 /*@access FD_t @*/ /* XXX void ptr args */ 00059 /*@access IOSMI_t @*/ 00060 /*@access IOSM_t @*/ 00061 00062 /*@access rpmfi @*/ 00063 00064 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) 00065 00066 #define _IOSM_DEBUG 0 00067 /*@unchecked@*/ 00068 int _iosm_debug = _IOSM_DEBUG; 00069 00070 /*@-exportheadervar@*/ 00071 /*@unchecked@*/ 00072 int _iosm_threads = 0; 00073 /*@=exportheadervar@*/ 00074 00075 /*@-redecl@*/ 00076 int (*_iosmNext) (IOSM_t iosm, iosmFileStage nstage) 00077 /*@modifies iosm @*/ = &iosmNext; 00078 /*@=redecl@*/ 00079 00080 #if defined(_USE_RPMTS) 00081 void * iosmGetTs(const IOSM_t iosm) 00082 { 00083 const IOSMI_t iter = iosm->iter; 00084 /*@-compdef -refcounttrans -retexpose -usereleased @*/ 00085 return (iter ? iter->ts : NULL); 00086 /*@=compdef =refcounttrans =retexpose =usereleased @*/ 00087 } 00088 #endif 00089 00090 void * iosmGetFi(const IOSM_t iosm) 00091 { 00092 const IOSMI_t iter = iosm->iter; 00093 /*@-compdef -refcounttrans -retexpose -usereleased @*/ 00094 return (iter ? iter->fi : NULL); 00095 /*@=compdef =refcounttrans =retexpose =usereleased @*/ 00096 } 00097 00098 #define SUFFIX_RPMORIG ".rpmorig" 00099 #define SUFFIX_RPMSAVE ".rpmsave" 00100 #define SUFFIX_RPMNEW ".rpmnew" 00101 00110 static /*@only@*//*@null@*/ 00111 const char * iosmFsPath(/*@special@*/ /*@null@*/ const IOSM_t iosm, 00112 /*@null@*/ const struct stat * st, 00113 /*@null@*/ const char * subdir, 00114 /*@null@*/ const char * suffix) 00115 /*@uses iosm->dirName, iosm->baseName */ 00116 /*@*/ 00117 { 00118 const char * s = NULL; 00119 00120 if (iosm) { 00121 char * t; 00122 int nb; 00123 nb = strlen(iosm->dirName) + 00124 (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) + 00125 (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) + 00126 strlen(iosm->baseName) + 1; 00127 s = t = xmalloc(nb); 00128 t = stpcpy(t, iosm->dirName); 00129 if (st && !S_ISDIR(st->st_mode)) 00130 if (subdir) t = stpcpy(t, subdir); 00131 t = stpcpy(t, iosm->baseName); 00132 if (st && !S_ISDIR(st->st_mode)) 00133 if (suffix) t = stpcpy(t, suffix); 00134 } 00135 return s; 00136 } 00137 00143 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p) 00144 /*@modifies p @*/ 00145 { 00146 IOSMI_t iter = p; 00147 if (iter) { 00148 #if !defined(_RPMFI_NOMETHODS) 00149 iter->fi = rpmfiUnlink(iter->fi, "mapIterator"); 00150 #endif 00151 iter->fi = NULL; 00152 } 00153 return _free(p); 00154 } 00155 00162 /*@-mustmod@*/ 00163 static void * 00164 mapInitIterator(rpmfi fi, int reverse) 00165 /*@modifies fi @*/ 00166 { 00167 IOSMI_t iter = NULL; 00168 00169 iter = xcalloc(1, sizeof(*iter)); 00170 #if !defined(_RPMFI_NOMETHODS) 00171 iter->fi = rpmfiLink(fi, "mapIterator"); 00172 #else 00173 /*@i@*/ iter->fi = fi; 00174 #endif 00175 iter->reverse = reverse; 00176 iter->i = (iter->reverse ? (fi->fc - 1) : 0); 00177 iter->isave = iter->i; 00178 return iter; 00179 } 00180 /*@=mustmod@*/ 00181 00187 static int mapNextIterator(/*@null@*/ void * a) 00188 /*@*/ 00189 { 00190 IOSMI_t iter = a; 00191 int i = -1; 00192 00193 if (iter) { 00194 if (iter->reverse) { 00195 if (iter->i >= 0) i = iter->i--; 00196 } else { 00197 if (iter->i < (int) ((rpmfi)iter->fi)->fc) i = iter->i++; 00198 } 00199 iter->isave = i; 00200 } 00201 return i; 00202 } 00203 00206 static int iosmStrCmp(const void * a, const void * b) 00207 /*@*/ 00208 { 00209 const char * aurl = *(const char **)a; 00210 const char * burl = *(const char **)b; 00211 const char * afn = NULL; 00212 const char * bfn = NULL; 00213 00214 (void) urlPath(aurl, &afn); 00215 (void) urlPath(burl, &bfn); 00216 00217 #ifdef VERY_OLD_BUGGY_RPM_PACKAGES 00218 /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */ 00219 if (strchr(afn, '/') == NULL) 00220 bfn = strrchr(bfn, '/') + 1; 00221 #endif 00222 00223 /* Match rpm-4.0 payloads with ./ prefixes. */ 00224 if (afn[0] == '.' && afn[1] == '/') afn += 2; 00225 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2; 00226 00227 /* If either path is absolute, make it relative to '/'. */ 00228 if (afn[0] == '/') afn += 1; 00229 if (bfn[0] == '/') bfn += 1; 00230 00231 return strcmp(afn, bfn); 00232 } 00233 00240 static int mapFind(/*@null@*/ IOSMI_t iter, const char * iosmPath) 00241 /*@modifies iter @*/ 00242 { 00243 int ix = -1; 00244 00245 if (iter) { 00246 /*@-onlytrans@*/ 00247 const rpmfi fi = iter->fi; 00248 /*@=onlytrans@*/ 00249 #if !defined(_RPMFI_NOMETHODS) 00250 size_t fc = rpmfiFC(fi); 00251 #else 00252 size_t fc = (fi ? fi->fc : 0); 00253 #endif 00254 if (fi && fc > 0 && fi->apath && iosmPath && *iosmPath) { 00255 const char ** p = NULL; 00256 00257 if (fi->apath != NULL) 00258 p = bsearch(&iosmPath, fi->apath, fc, sizeof(iosmPath), 00259 iosmStrCmp); 00260 if (p) { 00261 iter->i = p - fi->apath; 00262 ix = mapNextIterator(iter); 00263 } 00264 } 00265 } 00266 return ix; 00267 } 00268 00272 typedef struct dnli_s { 00273 rpmfi fi; 00274 /*@only@*/ /*@null@*/ 00275 char * active; 00276 int reverse; 00277 int isave; 00278 int i; 00279 } * DNLI_t; 00280 00286 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a) 00287 /*@modifies a @*/ 00288 { 00289 if (a) { 00290 DNLI_t dnli = (void *)a; 00291 if (dnli->active) free(dnli->active); 00292 } 00293 return _free(a); 00294 } 00295 00298 static inline int dnlCount(/*@null@*/ const DNLI_t dnli) 00299 /*@*/ 00300 { 00301 return (int) (dnli ? dnli->fi->dc : 0); 00302 } 00303 00306 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli) 00307 /*@*/ 00308 { 00309 return (dnli ? dnli->isave : -1); 00310 } 00311 00318 /*@-usereleased@*/ 00319 static /*@only@*/ /*@null@*/ 00320 void * dnlInitIterator(/*@special@*/ const IOSM_t iosm, 00321 int reverse) 00322 /*@uses iosm->iter @*/ 00323 /*@*/ 00324 { 00325 rpmfi fi = iosmGetFi(iosm); 00326 const char * dnl; 00327 DNLI_t dnli; 00328 int i, j; 00329 00330 if (fi == NULL) 00331 return NULL; 00332 dnli = xcalloc(1, sizeof(*dnli)); 00333 dnli->fi = fi; 00334 dnli->reverse = reverse; 00335 dnli->i = (int) (reverse ? fi->dc : 0); 00336 00337 if (fi->dc) { 00338 dnli->active = xcalloc(fi->dc, sizeof(*dnli->active)); 00339 00340 /* Identify parent directories not skipped. */ 00341 #if !defined(_RPMFI_NOMETHODS) 00342 if ((fi = rpmfiInit(fi, 0)) != NULL) 00343 while ((i = rpmfiNext(fi)) >= 0) 00344 #else 00345 for (i = 0; i < (int)fi->fc; i++) 00346 #endif 00347 { 00348 if (!iosmFileActionSkipped(fi->actions[i])) 00349 dnli->active[fi->dil[i]] = (char)1; 00350 } 00351 00352 /* Exclude parent directories that are explicitly included. */ 00353 #if !defined(_RPMFI_NOMETHODS) 00354 if ((fi = rpmfiInit(fi, 0)) != NULL) 00355 while ((i = rpmfiNext(fi)) >= 0) 00356 #else 00357 for (i = 0; i < (int)fi->fc; i++) 00358 #endif 00359 { 00360 rpmuint32_t dil; 00361 size_t dnlen, bnlen; 00362 00363 if (!S_ISDIR(fi->fmodes[i])) 00364 continue; 00365 00366 dil = fi->dil[i]; 00367 dnlen = strlen(fi->dnl[dil]); 00368 bnlen = strlen(fi->bnl[i]); 00369 00370 for (j = 0; j < (int)fi->dc; j++) { 00371 size_t jlen; 00372 00373 if (!dnli->active[j] || j == (int)dil) 00374 /*@innercontinue@*/ continue; 00375 (void) urlPath(fi->dnl[j], &dnl); 00376 jlen = strlen(dnl); 00377 if (jlen != (dnlen+bnlen+1)) 00378 /*@innercontinue@*/ continue; 00379 if (strncmp(dnl, fi->dnl[dil], dnlen)) 00380 /*@innercontinue@*/ continue; 00381 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) 00382 /*@innercontinue@*/ continue; 00383 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') 00384 /*@innercontinue@*/ continue; 00385 /* This directory is included in the package. */ 00386 dnli->active[j] = (char)0; 00387 /*@innerbreak@*/ break; 00388 } 00389 } 00390 00391 /* Print only once per package. */ 00392 if (!reverse) { 00393 j = 0; 00394 for (i = 0; i < (int)fi->dc; i++) { 00395 if (!dnli->active[i]) continue; 00396 if (j == 0) { 00397 j = 1; 00398 rpmlog(RPMLOG_DEBUG, 00399 D_("========== Directories not explicitly included in package:\n")); 00400 } 00401 (void) urlPath(fi->dnl[i], &dnl); 00402 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl); 00403 } 00404 if (j) 00405 rpmlog(RPMLOG_DEBUG, "==========\n"); 00406 } 00407 } 00408 return dnli; 00409 } 00410 /*@=usereleased@*/ 00411 00417 static /*@observer@*/ /*@null@*/ 00418 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli) 00419 /*@modifies dnli @*/ 00420 { 00421 const char * dn = NULL; 00422 00423 if (dnli) { 00424 rpmfi fi = dnli->fi; 00425 int i = -1; 00426 00427 if (dnli->active) 00428 do { 00429 i = (!dnli->reverse ? dnli->i++ : --dnli->i); 00430 } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]); 00431 00432 if (i >= 0 && i < (int)fi->dc) 00433 dn = fi->dnl[i]; 00434 else 00435 i = -1; 00436 dnli->isave = i; 00437 } 00438 return dn; 00439 } 00440 00441 #if defined(WITH_PTHREADS) 00442 static void * iosmThread(void * arg) 00443 /*@globals h_errno, fileSystem, internalState @*/ 00444 /*@modifies arg, fileSystem, internalState @*/ 00445 { 00446 IOSM_t iosm = arg; 00447 /*@-unqualifiedtrans@*/ 00448 return ((void *) ((long)iosmStage(iosm, iosm->nstage))); 00449 /*@=unqualifiedtrans@*/ 00450 } 00451 #endif 00452 00453 int iosmNext(IOSM_t iosm, iosmFileStage nstage) 00454 /*@globals h_errno, fileSystem, internalState @*/ 00455 /*@modifies iosm, fileSystem, internalState @*/ 00456 { 00457 iosm->nstage = nstage; 00458 #if defined(WITH_PTHREADS) 00459 if (iosm->multithreaded) 00460 return rpmsqJoin( rpmsqThread(iosmThread, iosm) ); 00461 #endif 00462 return iosmStage(iosm, iosm->nstage); 00463 } 00464 00470 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t iosm) 00471 /*@uses iosm->links, iosm->ix, iosm->sb, iosm->goal, iosm->nsuffix @*/ 00472 /*@defines iosm->li @*/ 00473 /*@releases iosm->path @*/ 00474 /*@globals h_errno, fileSystem, internalState @*/ 00475 /*@modifies iosm, fileSystem, internalState @*/ 00476 { 00477 struct stat * st = &iosm->sb; 00478 int rc = 0; 00479 int ix = -1; 00480 int j; 00481 00482 /* Find hard link set. */ 00483 for (iosm->li = iosm->links; iosm->li; iosm->li = iosm->li->next) { 00484 if (iosm->li->sb.st_ino == st->st_ino && iosm->li->sb.st_dev == st->st_dev) 00485 break; 00486 } 00487 00488 /* New hard link encountered, add new link to set. */ 00489 if (iosm->li == NULL) { 00490 iosm->li = xcalloc(1, sizeof(*iosm->li)); 00491 iosm->li->next = NULL; 00492 iosm->li->sb = *st; /* structure assignment */ 00493 iosm->li->nlink = (int) st->st_nlink; 00494 iosm->li->linkIndex = iosm->ix; 00495 iosm->li->createdPath = -1; 00496 00497 iosm->li->filex = xcalloc(st->st_nlink, sizeof(iosm->li->filex[0])); 00498 memset(iosm->li->filex, -1, (st->st_nlink * sizeof(iosm->li->filex[0]))); 00499 iosm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*iosm->li->nsuffix)); 00500 00501 if (iosm->goal == IOSM_PKGBUILD) 00502 iosm->li->linksLeft = (int) st->st_nlink; 00503 if (iosm->goal == IOSM_PKGINSTALL) 00504 iosm->li->linksLeft = 0; 00505 00506 /*@-kepttrans@*/ 00507 iosm->li->next = iosm->links; 00508 /*@=kepttrans@*/ 00509 iosm->links = iosm->li; 00510 } 00511 00512 if (iosm->goal == IOSM_PKGBUILD) --iosm->li->linksLeft; 00513 iosm->li->filex[iosm->li->linksLeft] = iosm->ix; 00514 /*@-observertrans -dependenttrans@*/ 00515 iosm->li->nsuffix[iosm->li->linksLeft] = iosm->nsuffix; 00516 /*@=observertrans =dependenttrans@*/ 00517 if (iosm->goal == IOSM_PKGINSTALL) iosm->li->linksLeft++; 00518 00519 if (iosm->goal == IOSM_PKGBUILD) 00520 return (iosm->li->linksLeft > 0); 00521 00522 if (iosm->goal != IOSM_PKGINSTALL) 00523 return 0; 00524 00525 if (!(st->st_size || iosm->li->linksLeft == (int) st->st_nlink)) 00526 return 1; 00527 00528 /* Here come the bits, time to choose a non-skipped file name. */ 00529 { rpmfi fi = iosmGetFi(iosm); 00530 00531 for (j = iosm->li->linksLeft - 1; j >= 0; j--) { 00532 ix = iosm->li->filex[j]; 00533 if (ix < 0 || iosmFileActionSkipped(fi->actions[ix])) 00534 continue; 00535 break; 00536 } 00537 } 00538 00539 /* Are all links skipped or not encountered yet? */ 00540 if (ix < 0 || j < 0) 00541 return 1; /* XXX W2DO? */ 00542 00543 /* Save the non-skipped file name and map index. */ 00544 iosm->li->linkIndex = j; 00545 iosm->path = _free(iosm->path); 00546 iosm->ix = ix; 00547 rc = iosmNext(iosm, IOSM_MAP); 00548 return rc; 00549 } 00550 00556 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li) 00557 /*@modifies li @*/ 00558 { 00559 if (li) { 00560 li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */ 00561 li->filex = _free(li->filex); 00562 } 00563 return _free(li); 00564 } 00565 00566 IOSM_t newIOSM(void) 00567 { 00568 IOSM_t iosm = xcalloc(1, sizeof(*iosm)); 00569 return iosm; 00570 } 00571 00572 IOSM_t freeIOSM(IOSM_t iosm) 00573 { 00574 if (iosm) { 00575 iosm->path = _free(iosm->path); 00576 while ((iosm->li = iosm->links) != NULL) { 00577 iosm->links = iosm->li->next; 00578 iosm->li->next = NULL; 00579 iosm->li = freeHardLink(iosm->li); 00580 } 00581 iosm->dnlx = _free(iosm->dnlx); 00582 iosm->ldn = _free(iosm->ldn); 00583 iosm->iter = mapFreeIterator(iosm->iter); 00584 } 00585 return _free(iosm); 00586 } 00587 00588 static int arSetup(IOSM_t iosm, rpmfi fi) 00589 /*@modifies iosm @*/ 00590 { 00591 const char * path; 00592 char * t; 00593 size_t lmtablen = 0; 00594 size_t nb; 00595 00596 /* Calculate size of ar(1) long member table. */ 00597 #if !defined(_RPMFI_NOMETHODS) 00598 if ((fi = rpmfiInit(fi, 0)) != NULL) 00599 while (rpmfiNext(fi) >= 0) 00600 #else 00601 int i; 00602 if (fi != NULL) 00603 for (i = 0; i < (int)fi->fc; i++) 00604 #endif 00605 { 00606 #ifdef NOTYET 00607 if (fi->apath) { 00608 const char * apath = NULL; 00609 (void) urlPath(fi->apath[ix], &apath); 00610 path = apath + fi->striplen; 00611 } else 00612 #endif 00613 #if !defined(_RPMFI_NOMETHODS) 00614 path = rpmfiBN(fi); 00615 #else 00616 path = fi->bnl[i]; 00617 #endif 00618 if ((nb = strlen(path)) < 15) 00619 continue; 00620 lmtablen += nb + 1; /* trailing \n */ 00621 } 00622 00623 /* Anything to do? */ 00624 if (lmtablen == 0) 00625 return 0; 00626 00627 /* Create and load ar(1) long member table. */ 00628 iosm->lmtab = t = xmalloc(lmtablen + 1); /* trailing \0 */ 00629 iosm->lmtablen = lmtablen; 00630 iosm->lmtaboff = 0; 00631 #if !defined(_RPMFI_NOMETHODS) 00632 if ((fi = rpmfiInit(fi, 0)) != NULL) 00633 while (rpmfiNext(fi) >= 0) 00634 #else 00635 if (fi != NULL) 00636 for (i = 0; i < (int)fi->fc; i++) 00637 #endif 00638 { 00639 #ifdef NOTYET 00640 if (fi->apath) { 00641 const char * apath = NULL; 00642 (void) urlPath(fi->apath[ix], &apath); 00643 path = apath + fi->striplen; 00644 } else 00645 #endif 00646 #if !defined(_RPMFI_NOMETHODS) 00647 path = rpmfiBN(fi); 00648 #else 00649 path = fi->bnl[i]; 00650 #endif 00651 if ((nb = strlen(path)) < 15) 00652 continue; 00653 t = stpcpy(t, path); 00654 *t++ = '\n'; 00655 } 00656 *t = '\0'; 00657 00658 return 0; 00659 } 00660 00661 int iosmSetup(IOSM_t iosm, iosmFileStage goal, const char * afmt, 00662 const void * _ts, const void * _fi, FD_t cfd, 00663 unsigned int * archiveSize, const char ** failedFile) 00664 { 00665 #if defined(_USE_RPMTS) 00666 const rpmts ts = (const rpmts) _ts; 00667 #endif 00668 /*@i@*/ const rpmfi fi = (const rpmfi) _fi; 00669 #if defined(_USE_RPMTE) 00670 int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT); 00671 int adding = (rpmteType(fi->te) == TR_ADDED); 00672 #else 00673 int reverse = 0; /* XXX HACK: devise alternative means */ 00674 int adding = 1; /* XXX HACK: devise alternative means */ 00675 #endif 00676 size_t pos = 0; 00677 int rc, ec = 0; 00678 00679 iosm->debug = _iosm_debug; 00680 iosm->multithreaded = _iosm_threads; 00681 iosm->adding = adding; 00682 00683 /*@+voidabstract -nullpass@*/ 00684 if (iosm->debug < 0) 00685 fprintf(stderr, "--> iosmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", iosm, goal, afmt, (void *)_ts, _fi, cfd, archiveSize, failedFile); 00686 /*@=voidabstract =nullpass@*/ 00687 00688 _iosmNext = &iosmNext; 00689 if (iosm->headerRead == NULL) { 00690 if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) { 00691 if (iosm->debug < 0) 00692 fprintf(stderr, "\ttar vectors set\n"); 00693 iosm->headerRead = &tarHeaderRead; 00694 iosm->headerWrite = &tarHeaderWrite; 00695 iosm->trailerWrite = &tarTrailerWrite; 00696 iosm->blksize = TAR_BLOCK_SIZE; 00697 } else 00698 if (afmt != NULL && !strcmp(afmt, "ar")) { 00699 if (iosm->debug < 0) 00700 fprintf(stderr, "\tar vectors set\n"); 00701 iosm->headerRead = &arHeaderRead; 00702 iosm->headerWrite = &arHeaderWrite; 00703 iosm->trailerWrite = &arTrailerWrite; 00704 iosm->blksize = 2; 00705 if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE) 00706 (void) arSetup(iosm, fi); 00707 } else 00708 { 00709 if (iosm->debug < 0) 00710 fprintf(stderr, "\tcpio vectors set\n"); 00711 iosm->headerRead = &cpioHeaderRead; 00712 iosm->headerWrite = &cpioHeaderWrite; 00713 iosm->trailerWrite = &cpioTrailerWrite; 00714 iosm->blksize = 4; 00715 } 00716 } 00717 00718 iosm->goal = goal; 00719 if (cfd != NULL) { 00720 /*@-assignexpose@*/ 00721 iosm->cfd = fdLink(cfd, "persist (iosm)"); 00722 /*@=assignexpose@*/ 00723 pos = fdGetCpioPos(iosm->cfd); 00724 fdSetCpioPos(iosm->cfd, 0); 00725 } 00726 /*@-mods@*/ /* WTF? */ 00727 iosm->iter = mapInitIterator(fi, reverse); 00728 /*@=mods@*/ 00729 #if defined(_USE_RPMTS) 00730 iosm->iter->ts = rpmtsLink(ts, "mapIterator"); 00731 iosm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS); 00732 iosm->nofdigests = 00733 (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS)) 00734 ? 0 : 1; 00735 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT) 00736 iosm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) && 00737 iosm->goal != IOSM_PKGCOMMIT) ? 0 : 1); 00738 #undef _tsmask 00739 #else 00740 /*@-assignexpose -temptrans @*/ 00741 iosm->iter->ts = (void *)_ts; 00742 /*@=assignexpose =temptrans @*/ 00743 iosm->nofcontexts = 1; 00744 iosm->nofdigests = 1; 00745 iosm->commit = 1; 00746 #endif 00747 00748 #if defined(_USE_RPMTS) 00749 if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) { 00750 fi->archivePos = 0; 00751 (void) rpmtsNotify(ts, fi->te, 00752 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize); 00753 } 00754 #endif 00755 00756 /*@-assignexpose@*/ 00757 iosm->archiveSize = archiveSize; 00758 if (iosm->archiveSize) 00759 *iosm->archiveSize = 0; 00760 iosm->failedFile = failedFile; 00761 if (iosm->failedFile) 00762 *iosm->failedFile = NULL; 00763 /*@=assignexpose@*/ 00764 00765 memset(iosm->sufbuf, 0, sizeof(iosm->sufbuf)); 00766 if (iosm->goal == IOSM_PKGINSTALL) { 00767 rpmuint32_t tid; 00768 #if defined(_USE_RPMTS) 00769 tid = (ts != NULL ? rpmtsGetTid(ts) : 0); 00770 #else 00771 static time_t now = 0; 00772 if (now == 0) now = time(NULL); 00773 tid = (rpmuint32_t) now; 00774 #endif 00775 if (tid > 0 && tid < 0xffffffff) 00776 sprintf(iosm->sufbuf, ";%08x", (unsigned)tid); 00777 } 00778 00779 ec = iosm->rc = 0; 00780 rc = iosmUNSAFE(iosm, IOSM_CREATE); 00781 if (rc && !ec) ec = rc; 00782 00783 rc = iosmUNSAFE(iosm, iosm->goal); 00784 if (rc && !ec) ec = rc; 00785 00786 if (iosm->archiveSize && ec == 0) 00787 *iosm->archiveSize = (fdGetCpioPos(iosm->cfd) - pos); 00788 00789 /*@-nullstate@*/ /* FIX: *iosm->failedFile may be NULL */ 00790 return ec; 00791 /*@=nullstate@*/ 00792 } 00793 00794 int iosmTeardown(IOSM_t iosm) 00795 { 00796 int rc = iosm->rc; 00797 00798 if (iosm->debug < 0) 00799 fprintf(stderr, "--> iosmTeardown(%p)\n", iosm); 00800 if (!rc) 00801 rc = iosmUNSAFE(iosm, IOSM_DESTROY); 00802 00803 iosm->lmtab = _free(iosm->lmtab); 00804 00805 if (iosm->iter != NULL) { 00806 #if defined(_USE_RPMTS) 00807 (void) rpmswAdd(rpmtsOp(iosmGetTs(iosm), RPMTS_OP_DIGEST), 00808 &iosm->op_digest); 00809 (void)rpmtsFree(iosm->iter->ts); 00810 #endif 00811 iosm->iter->ts = NULL; 00812 iosm->iter = mapFreeIterator(iosm->iter); 00813 } 00814 if (iosm->cfd != NULL) { 00815 iosm->cfd = fdFree(iosm->cfd, "persist (iosm)"); 00816 iosm->cfd = NULL; 00817 } 00818 iosm->failedFile = NULL; 00819 return rc; 00820 } 00821 00822 /* 00823 * Set file security context (if not disabled). 00824 * @param iosm file state machine data 00825 * @return 0 always 00826 */ 00827 static int iosmMapFContext(IOSM_t iosm) 00828 /*@modifies iosm @*/ 00829 { 00830 /* 00831 * Find file security context (if not disabled). 00832 */ 00833 iosm->fcontext = NULL; 00834 if (!iosm->nofcontexts) { 00835 iosm->fcontext = rpmsxMatch(NULL, iosm->path, iosm->sb.st_mode); 00836 #ifdef DYING /* XXX SELinux file contexts not set from package content. */ 00837 { rpmfi fi = iosmGetFi(iosm); 00838 int i = iosm->ix; 00839 00840 /* Get file security context from package. */ 00841 if (fi && i >= 0 && i < (int)fi->fc) 00842 iosm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL); 00843 } 00844 #endif 00845 /*@=moduncon@*/ 00846 } 00847 return 0; 00848 } 00849 00850 int iosmMapPath(IOSM_t iosm) 00851 { 00852 rpmfi fi = iosmGetFi(iosm); /* XXX const except for fstates */ 00853 int teAdding = iosm->adding; 00854 int rc = 0; 00855 int i = iosm->ix; 00856 00857 iosm->osuffix = NULL; 00858 iosm->nsuffix = NULL; 00859 iosm->astriplen = 0; 00860 iosm->action = FA_UNKNOWN; 00861 iosm->mapFlags = (fi ? fi->mapflags : 0); 00862 00863 if (fi && i >= 0 && i < (int)fi->fc) { 00864 00865 iosm->astriplen = fi->astriplen; 00866 iosm->action = (fi->actions ? fi->actions[i] : fi->action); 00867 iosm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags); 00868 iosm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags); 00869 00870 /* src rpms have simple base name in payload. */ 00871 iosm->dirName = fi->dnl[fi->dil[i]]; 00872 iosm->baseName = fi->bnl[i]; 00873 00874 switch (iosm->action) { 00875 case FA_SKIP: 00876 break; 00877 case FA_UNKNOWN: 00878 break; 00879 00880 case FA_COPYOUT: 00881 break; 00882 case FA_COPYIN: 00883 case FA_CREATE: 00884 assert(teAdding); 00885 break; 00886 00887 case FA_SKIPNSTATE: 00888 if (fi->fstates && teAdding) 00889 fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_NOTINSTALLED; 00890 break; 00891 00892 case FA_SKIPNETSHARED: 00893 if (fi->fstates && teAdding) 00894 fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_NETSHARED; 00895 break; 00896 00897 case FA_SKIPCOLOR: 00898 if (fi->fstates && teAdding) 00899 fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_WRONGCOLOR; 00900 break; 00901 00902 case FA_BACKUP: 00903 if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00904 iosm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE); 00905 break; 00906 00907 case FA_ALTNAME: 00908 assert(teAdding); 00909 if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00910 iosm->nsuffix = SUFFIX_RPMNEW; 00911 break; 00912 00913 case FA_SAVE: 00914 assert(teAdding); 00915 if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00916 iosm->osuffix = SUFFIX_RPMSAVE; 00917 break; 00918 case FA_ERASE: 00919 #if 0 /* XXX is this a genhdlist fix? */ 00920 assert(rpmteType(fi->te) == TR_REMOVED); 00921 #endif 00922 /* 00923 * XXX TODO: %ghost probably shouldn't be removed, but that changes 00924 * legacy rpm behavior. 00925 */ 00926 break; 00927 default: 00928 break; 00929 } 00930 00931 if ((iosm->mapFlags & IOSM_MAP_PATH) || iosm->nsuffix) { 00932 const struct stat * st = &iosm->sb; 00933 iosm->path = _free(iosm->path); 00934 iosm->path = iosmFsPath(iosm, st, iosm->subdir, 00935 (iosm->suffix ? iosm->suffix : iosm->nsuffix)); 00936 } 00937 } 00938 return rc; 00939 } 00940 00941 int iosmMapAttrs(IOSM_t iosm) 00942 { 00943 struct stat * st = &iosm->sb; 00944 rpmfi fi = iosmGetFi(iosm); 00945 int i = iosm->ix; 00946 00947 if (fi && i >= 0 && i < (int)fi->fc) { 00948 mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms); 00949 mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms); 00950 dev_t finalRdev = (fi->frdevs ? fi->frdevs[i] : 0); 00951 rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0); 00952 uid_t uid = fi->uid; 00953 gid_t gid = fi->gid; 00954 00955 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00956 /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during 00957 installation of _source_ RPMs. Instead, let it use the current 00958 run-time owner/group, because most of the time the owner/group in 00959 the source RPM (which is the owner/group of the files as staying on 00960 the package author system) is not existing on the target system, of 00961 course. */ 00962 #endif 00963 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) { 00964 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00965 if (!fi->isSource) { 00966 #endif 00967 if (iosm->goal == IOSM_PKGINSTALL) 00968 rpmlog(RPMLOG_WARNING, 00969 _("user %s does not exist - using root\n"), fi->fuser[i]); 00970 uid = 0; 00971 finalMode &= ~S_ISUID; /* turn off suid bit */ 00972 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00973 } 00974 #endif 00975 } 00976 00977 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) { 00978 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00979 if (!fi->isSource) { 00980 #endif 00981 if (iosm->goal == IOSM_PKGINSTALL) 00982 rpmlog(RPMLOG_WARNING, 00983 _("group %s does not exist - using root\n"), fi->fgroup[i]); 00984 gid = 0; 00985 finalMode &= ~S_ISGID; /* turn off sgid bit */ 00986 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00987 } 00988 #endif 00989 } 00990 00991 if (iosm->mapFlags & IOSM_MAP_MODE) 00992 st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT); 00993 if (iosm->mapFlags & IOSM_MAP_TYPE) { 00994 st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT); 00995 if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) 00996 && st->st_nlink == 0) 00997 st->st_nlink = 1; 00998 st->st_rdev = finalRdev; 00999 st->st_mtime = finalMtime; 01000 } 01001 if (iosm->mapFlags & IOSM_MAP_UID) 01002 st->st_uid = uid; 01003 if (iosm->mapFlags & IOSM_MAP_GID) 01004 st->st_gid = gid; 01005 01006 /* 01007 * Set file digest (if not disabled). 01008 */ 01009 if (!iosm->nofdigests) { 01010 iosm->fdigestalgo = fi->digestalgo; 01011 iosm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL); 01012 iosm->digestlen = fi->digestlen; 01013 iosm->digest = (fi->digests ? (fi->digests + (iosm->digestlen * i)) : NULL); 01014 } else { 01015 iosm->fdigestalgo = 0; 01016 iosm->fdigest = NULL; 01017 iosm->digestlen = 0; 01018 iosm->digest = NULL; 01019 } 01020 } 01021 return 0; 01022 } 01023 01029 /*@-compdef@*/ 01030 static int extractRegular(/*@special@*/ IOSM_t iosm) 01031 /*@uses iosm->fdigest, iosm->digest, iosm->sb, iosm->wfd @*/ 01032 /*@globals h_errno, fileSystem, internalState @*/ 01033 /*@modifies iosm, fileSystem, internalState @*/ 01034 { 01035 const struct stat * st = &iosm->sb; 01036 size_t left = (size_t) st->st_size; 01037 int rc = 0; 01038 int xx; 01039 01040 rc = iosmNext(iosm, IOSM_WOPEN); 01041 if (rc) 01042 goto exit; 01043 01044 if (st->st_size > 0 && (iosm->fdigest != NULL || iosm->digest != NULL)) 01045 fdInitDigest(iosm->wfd, iosm->fdigestalgo, 0); 01046 01047 while (left) { 01048 01049 iosm->wrlen = (left > iosm->wrsize ? iosm->wrsize : left); 01050 rc = iosmNext(iosm, IOSM_DREAD); 01051 if (rc) 01052 goto exit; 01053 01054 rc = iosmNext(iosm, IOSM_WRITE); 01055 if (rc) 01056 goto exit; 01057 01058 left -= iosm->wrnb; 01059 01060 /* Notify iff progress, completion is done elsewhere */ 01061 if (!rc && left) 01062 (void) iosmNext(iosm, IOSM_NOTIFY); 01063 } 01064 01065 xx = fsync(Fileno(iosm->wfd)); 01066 01067 if (st->st_size > 0 && (iosm->fdigest || iosm->digest)) { 01068 void * digest = NULL; 01069 int asAscii = (iosm->digest == NULL ? 1 : 0); 01070 01071 (void) Fflush(iosm->wfd); 01072 fdFiniDigest(iosm->wfd, iosm->fdigestalgo, &digest, NULL, asAscii); 01073 01074 if (digest == NULL) { 01075 rc = IOSMERR_DIGEST_MISMATCH; 01076 goto exit; 01077 } 01078 01079 if (iosm->digest != NULL) { 01080 if (memcmp(digest, iosm->digest, iosm->digestlen)) 01081 rc = IOSMERR_DIGEST_MISMATCH; 01082 } else { 01083 if (strcmp(digest, iosm->fdigest)) 01084 rc = IOSMERR_DIGEST_MISMATCH; 01085 } 01086 digest = _free(digest); 01087 } 01088 01089 exit: 01090 (void) iosmNext(iosm, IOSM_WCLOSE); 01091 return rc; 01092 } 01093 /*@=compdef@*/ 01094 01101 /*@-compdef -compmempass@*/ 01102 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t iosm, int writeData) 01103 /*@uses iosm->path, iosm->opath, iosm->sb, iosm->osb, iosm->cfd @*/ 01104 /*@globals h_errno, fileSystem, internalState @*/ 01105 /*@modifies iosm, fileSystem, internalState @*/ 01106 { 01107 const char * path = iosm->path; 01108 const char * opath = iosm->opath; 01109 struct stat * st = &iosm->sb; 01110 struct stat * ost = &iosm->osb; 01111 size_t left; 01112 int xx; 01113 int rc; 01114 01115 st->st_size = (writeData ? ost->st_size : 0); 01116 01117 if (S_ISDIR(st->st_mode)) { 01118 st->st_size = 0; 01119 } else if (S_ISLNK(st->st_mode)) { 01120 /* 01121 * While linux puts the size of a symlink in the st_size field, 01122 * I don't think that's a specified standard. 01123 */ 01124 /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */ 01125 rc = iosmUNSAFE(iosm, IOSM_READLINK); 01126 if (rc) goto exit; 01127 st->st_size = iosm->rdnb; 01128 iosm->lpath = xstrdup(iosm->rdbuf); /* XXX save readlink return. */ 01129 } 01130 01131 if (iosm->mapFlags & IOSM_MAP_ABSOLUTE) { 01132 size_t nb=strlen(iosm->dirName) + strlen(iosm->baseName) + sizeof("."); 01133 char * t = alloca(nb); 01134 *t = '\0'; 01135 iosm->path = t; 01136 if (iosm->mapFlags & IOSM_MAP_ADDDOT) 01137 *t++ = '.'; 01138 t = stpcpy( stpcpy(t, iosm->dirName), iosm->baseName); 01139 } else if (iosm->mapFlags & IOSM_MAP_PATH) { 01140 rpmfi fi = iosmGetFi(iosm); 01141 if (fi->apath) { 01142 const char * apath = NULL; 01143 (void) urlPath(fi->apath[iosm->ix], &apath); 01144 iosm->path = apath + fi->striplen; 01145 } else 01146 iosm->path = fi->bnl[iosm->ix]; 01147 } 01148 01149 rc = iosmNext(iosm, IOSM_HWRITE); 01150 iosm->path = path; 01151 if (rc) goto exit; 01152 01153 if (writeData && S_ISREG(st->st_mode)) { 01154 #if defined(HAVE_MMAP) 01155 char * rdbuf = NULL; 01156 void * mapped = (void *)-1; 01157 size_t nmapped = 0; 01158 /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */ 01159 int use_mmap = (st->st_size <= 0x07ffffff); 01160 #endif 01161 01162 rc = iosmNext(iosm, IOSM_ROPEN); 01163 if (rc) goto exit; 01164 01165 /* XXX unbuffered mmap generates *lots* of fdio debugging */ 01166 #if defined(HAVE_MMAP) 01167 if (use_mmap) { 01168 mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(iosm->rfd), 0); 01169 if (mapped != (void *)-1) { 01170 rdbuf = iosm->rdbuf; 01171 iosm->rdbuf = (char *) mapped; 01172 iosm->rdlen = nmapped = st->st_size; 01173 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) 01174 xx = madvise(mapped, nmapped, MADV_DONTNEED); 01175 #endif 01176 } 01177 } 01178 #endif 01179 01180 left = st->st_size; 01181 01182 while (left) { 01183 #if defined(HAVE_MMAP) 01184 if (mapped != (void *)-1) { 01185 iosm->rdnb = nmapped; 01186 } else 01187 #endif 01188 { 01189 iosm->rdlen = (left > iosm->rdsize ? iosm->rdsize : left), 01190 rc = iosmNext(iosm, IOSM_READ); 01191 if (rc) goto exit; 01192 } 01193 01194 /* XXX DWRITE uses rdnb for I/O length. */ 01195 rc = iosmNext(iosm, IOSM_DWRITE); 01196 if (rc) goto exit; 01197 01198 left -= iosm->wrnb; 01199 } 01200 01201 #if defined(HAVE_MMAP) 01202 if (mapped != (void *)-1) { 01203 /* XXX splint misses size_t 2nd arg. */ 01204 /*@i@*/ xx = msync(mapped, nmapped, MS_ASYNC); 01205 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) 01206 xx = madvise(mapped, nmapped, MADV_DONTNEED); 01207 #endif 01208 xx = munmap(mapped, nmapped); 01209 iosm->rdbuf = rdbuf; 01210 } else 01211 #endif 01212 xx = fsync(Fileno(iosm->rfd)); 01213 01214 } 01215 01216 rc = iosmNext(iosm, IOSM_PAD); 01217 if (rc) goto exit; 01218 01219 rc = 0; 01220 01221 exit: 01222 if (iosm->rfd != NULL) 01223 (void) iosmNext(iosm, IOSM_RCLOSE); 01224 /*@-dependenttrans@*/ 01225 iosm->opath = opath; 01226 iosm->path = path; 01227 /*@=dependenttrans@*/ 01228 return rc; 01229 } 01230 /*@=compdef =compmempass@*/ 01231 01237 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t iosm) 01238 /*@uses iosm->path, iosm->nsuffix, iosm->ix, iosm->li, iosm->failedFile @*/ 01239 /*@globals h_errno, fileSystem, internalState @*/ 01240 /*@modifies iosm, fileSystem, internalState @*/ 01241 { 01242 const char * path = iosm->path; 01243 const char * lpath = iosm->lpath; 01244 const char * nsuffix = iosm->nsuffix; 01245 int iterIndex = iosm->ix; 01246 int ec = 0; 01247 int rc; 01248 int i; 01249 const char * linkpath = NULL; 01250 int firstfile = 1; 01251 01252 iosm->path = NULL; 01253 iosm->lpath = NULL; 01254 iosm->nsuffix = NULL; 01255 iosm->ix = -1; 01256 01257 for (i = iosm->li->nlink - 1; i >= 0; i--) { 01258 01259 if (iosm->li->filex[i] < 0) continue; 01260 01261 iosm->ix = iosm->li->filex[i]; 01262 /*@-compdef@*/ 01263 rc = iosmNext(iosm, IOSM_MAP); 01264 /*@=compdef@*/ 01265 01266 /* XXX tar and cpio have to do things differently. */ 01267 if (iosm->headerWrite == tarHeaderWrite) { 01268 if (firstfile) { 01269 const char * apath = NULL; 01270 char *t; 01271 (void) urlPath(iosm->path, &apath); 01272 /* Remove the buildroot prefix. */ 01273 t = xmalloc(sizeof(".") + strlen(apath + iosm->astriplen)); 01274 (void) stpcpy( stpcpy(t, "."), apath + iosm->astriplen); 01275 linkpath = t; 01276 firstfile = 0; 01277 } else 01278 iosm->lpath = linkpath; 01279 01280 /* Write data after first link for tar. */ 01281 rc = writeFile(iosm, (iosm->lpath == NULL)); 01282 } else { 01283 /* Write data after last link for cpio. */ 01284 rc = writeFile(iosm, (i == 0)); 01285 } 01286 if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) { 01287 ec = rc; 01288 *iosm->failedFile = xstrdup(iosm->path); 01289 } 01290 01291 iosm->path = _free(iosm->path); 01292 iosm->li->filex[i] = -1; 01293 } 01294 01295 /*@-dependenttrans@*/ 01296 linkpath = _free(linkpath); 01297 /*@=dependenttrans@*/ 01298 iosm->ix = iterIndex; 01299 iosm->nsuffix = nsuffix; 01300 iosm->lpath = lpath; 01301 iosm->path = path; 01302 return ec; 01303 } 01304 01310 /*@-compdef@*/ 01311 static int iosmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t iosm) 01312 /*@uses iosm->path, iosm->opath, iosm->nsuffix, iosm->ix, iosm->li @*/ 01313 /*@globals h_errno, fileSystem, internalState @*/ 01314 /*@modifies iosm, fileSystem, internalState @*/ 01315 { 01316 const char * path = iosm->path; 01317 const char * opath = iosm->opath; 01318 const char * nsuffix = iosm->nsuffix; 01319 int iterIndex = iosm->ix; 01320 int ec = 0; 01321 int rc; 01322 int i; 01323 01324 iosm->path = NULL; 01325 iosm->opath = NULL; 01326 iosm->nsuffix = NULL; 01327 iosm->ix = -1; 01328 01329 iosm->ix = iosm->li->filex[iosm->li->createdPath]; 01330 rc = iosmNext(iosm, IOSM_MAP); 01331 iosm->opath = iosm->path; 01332 iosm->path = NULL; 01333 for (i = 0; i < iosm->li->nlink; i++) { 01334 if (iosm->li->filex[i] < 0) continue; 01335 if (iosm->li->createdPath == i) continue; 01336 01337 iosm->ix = iosm->li->filex[i]; 01338 iosm->path = _free(iosm->path); 01339 rc = iosmNext(iosm, IOSM_MAP); 01340 if (iosmFileActionSkipped(iosm->action)) continue; 01341 01342 rc = iosmUNSAFE(iosm, IOSM_VERIFY); 01343 if (!rc) continue; 01344 if (!(rc == IOSMERR_ENOENT)) break; 01345 01346 /* XXX link(iosm->opath, iosm->path) */ 01347 rc = iosmNext(iosm, IOSM_LINK); 01348 if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) { 01349 ec = rc; 01350 *iosm->failedFile = xstrdup(iosm->path); 01351 } 01352 01353 iosm->li->linksLeft--; 01354 } 01355 iosm->path = _free(iosm->path); 01356 iosm->opath = _free(iosm->opath); 01357 01358 iosm->ix = iterIndex; 01359 iosm->nsuffix = nsuffix; 01360 iosm->path = path; 01361 iosm->opath = opath; 01362 return ec; 01363 } 01364 /*@=compdef@*/ 01365 01371 /*@-compdef@*/ 01372 static int iosmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t iosm) 01373 /*@uses iosm->path, iosm->nsuffix, iosm->ix, iosm->sb, 01374 iosm->li, iosm->links @*/ 01375 /*@globals h_errno, fileSystem, internalState @*/ 01376 /*@modifies iosm, fileSystem, internalState @*/ 01377 { 01378 const char * path = iosm->path; 01379 const char * nsuffix = iosm->nsuffix; 01380 int iterIndex = iosm->ix; 01381 struct stat * st = &iosm->sb; 01382 int rc = 0; 01383 int i; 01384 01385 iosm->path = NULL; 01386 iosm->nsuffix = NULL; 01387 iosm->ix = -1; 01388 01389 for (iosm->li = iosm->links; iosm->li; iosm->li = iosm->li->next) { 01390 if (iosm->li->sb.st_ino == st->st_ino && iosm->li->sb.st_dev == st->st_dev) 01391 break; 01392 } 01393 01394 for (i = 0; i < iosm->li->nlink; i++) { 01395 if (iosm->li->filex[i] < 0) continue; 01396 iosm->ix = iosm->li->filex[i]; 01397 rc = iosmNext(iosm, IOSM_MAP); 01398 if (!iosmFileActionSkipped(iosm->action)) 01399 rc = iosmNext(iosm, IOSM_COMMIT); 01400 iosm->path = _free(iosm->path); 01401 iosm->li->filex[i] = -1; 01402 } 01403 01404 iosm->ix = iterIndex; 01405 iosm->nsuffix = nsuffix; 01406 iosm->path = path; 01407 return rc; 01408 } 01409 /*@=compdef@*/ 01410 01416 static int iosmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t iosm) 01417 /*@uses iosm->path, iosm->dnlx, iosm->ldn, iosm->rdbuf, iosm->iter @*/ 01418 /*@globals h_errno, fileSystem, internalState @*/ 01419 /*@modifies iosm, fileSystem, internalState @*/ 01420 { 01421 const char * path = iosm->path; 01422 void * dnli = dnlInitIterator(iosm, 1); 01423 char * dn = iosm->rdbuf; 01424 int dc = dnlCount(dnli); 01425 int rc = 0; 01426 01427 iosm->path = NULL; 01428 dn[0] = '\0'; 01429 /*@-observertrans -dependenttrans@*/ 01430 if (iosm->ldn != NULL && iosm->dnlx != NULL) 01431 while ((iosm->path = dnlNextIterator(dnli)) != NULL) { 01432 size_t dnlen = strlen(iosm->path); 01433 char * te; 01434 01435 dc = dnlIndex(dnli); 01436 if (iosm->dnlx[dc] < 1 || (size_t)iosm->dnlx[dc] >= dnlen) 01437 continue; 01438 01439 /* Copy to avoid const on iosm->path. */ 01440 te = stpcpy(dn, iosm->path) - 1; 01441 iosm->path = dn; 01442 01443 /* Remove generated directories. */ 01444 /*@-usereleased@*/ /* LCL: te used after release? */ 01445 do { 01446 if (*te == '/') { 01447 *te = '\0'; 01448 /*@-compdef@*/ 01449 rc = iosmNext(iosm, IOSM_RMDIR); 01450 /*@=compdef@*/ 01451 *te = '/'; 01452 } 01453 if (rc) 01454 /*@innerbreak@*/ break; 01455 te--; 01456 } while ((te - iosm->path) > iosm->dnlx[dc]); 01457 /*@=usereleased@*/ 01458 } 01459 dnli = dnlFreeIterator(dnli); 01460 /*@=observertrans =dependenttrans@*/ 01461 01462 iosm->path = path; 01463 return rc; 01464 } 01465 01471 static int iosmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t iosm) 01472 /*@uses iosm->path, iosm->sb, iosm->osb, iosm->rdbuf, iosm->iter, 01473 iosm->ldn, iosm->ldnlen, iosm->ldnalloc @*/ 01474 /*@defines iosm->dnlx, iosm->ldn @*/ 01475 /*@globals h_errno, fileSystem, internalState @*/ 01476 /*@modifies iosm, fileSystem, internalState @*/ 01477 { 01478 struct stat * st = &iosm->sb; 01479 struct stat * ost = &iosm->osb; 01480 const char * path = iosm->path; 01481 mode_t st_mode = st->st_mode; 01482 void * dnli = dnlInitIterator(iosm, 0); 01483 char * dn = iosm->rdbuf; 01484 int dc = dnlCount(dnli); 01485 int rc = 0; 01486 size_t i; 01487 01488 iosm->path = NULL; 01489 01490 dn[0] = '\0'; 01491 iosm->dnlx = (dc ? xcalloc(dc, sizeof(*iosm->dnlx)) : NULL); 01492 /*@-observertrans -dependenttrans@*/ 01493 if (iosm->dnlx != NULL) 01494 while ((iosm->path = dnlNextIterator(dnli)) != NULL) { 01495 size_t dnlen = strlen(iosm->path); 01496 char * te; 01497 01498 dc = dnlIndex(dnli); 01499 if (dc < 0) continue; 01500 iosm->dnlx[dc] = (unsigned short) dnlen; 01501 if (dnlen <= 1) 01502 continue; 01503 01504 /*@-compdef -nullpass@*/ /* FIX: iosm->ldn not defined ??? */ 01505 if (dnlen <= iosm->ldnlen && !strcmp(iosm->path, iosm->ldn)) 01506 continue; 01507 /*@=compdef =nullpass@*/ 01508 01509 /* Copy to avoid const on iosm->path. */ 01510 (void) stpcpy(dn, iosm->path); 01511 iosm->path = dn; 01512 01513 /* Assume '/' directory exists, "mkdir -p" for others if non-existent */ 01514 (void) urlPath(dn, (const char **)&te); 01515 for (i = 1, te++; *te != '\0'; te++, i++) { 01516 if (*te != '/') 01517 /*@innercontinue@*/ continue; 01518 01519 *te = '\0'; 01520 01521 /* Already validated? */ 01522 /*@-usedef -compdef -nullpass -nullderef@*/ 01523 if (i < iosm->ldnlen && 01524 (iosm->ldn[i] == '/' || iosm->ldn[i] == '\0') && 01525 !strncmp(iosm->path, iosm->ldn, i)) 01526 { 01527 *te = '/'; 01528 /* Move pre-existing path marker forward. */ 01529 iosm->dnlx[dc] = (te - dn); 01530 /*@innercontinue@*/ continue; 01531 } 01532 /*@=usedef =compdef =nullpass =nullderef@*/ 01533 01534 /* Validate next component of path. */ 01535 rc = iosmUNSAFE(iosm, IOSM_LSTAT); 01536 *te = '/'; 01537 01538 /* Directory already exists? */ 01539 if (rc == 0 && S_ISDIR(ost->st_mode)) { 01540 /* Move pre-existing path marker forward. */ 01541 iosm->dnlx[dc] = (te - dn); 01542 } else if (rc == IOSMERR_ENOENT) { 01543 rpmfi fi = iosmGetFi(iosm); 01544 *te = '\0'; 01545 st->st_mode = S_IFDIR | (fi->dperms & 07777); 01546 rc = iosmNext(iosm, IOSM_MKDIR); 01547 if (!rc) { 01548 #if defined(_USE_RPMSX) 01549 /* XXX FIXME? only new dir will have context set. */ 01550 /* Get file security context from patterns. */ 01551 if (!fsm->nofcontexts) { 01552 iosm->fcontext = 01553 rpmsxMatch(NULL, iosm->path, st->st_mode); 01554 if (iosm->fcontext != NULL) 01555 rc = iosmNext(iosm, IOSM_LSETFCON); 01556 } else 01557 #endif 01558 iosm->fcontext = NULL; 01559 rpmlog(RPMLOG_DEBUG, 01560 D_("%s directory created with perms %04o, context %s.\n"), 01561 iosm->path, (unsigned)(st->st_mode & 07777), 01562 (iosm->fcontext ? iosm->fcontext : "(no context)")); 01563 #if defined(_USE_RPMSX) 01564 iosm->fcontext = _free(iosm->fcontext); 01565 #endif 01566 } 01567 *te = '/'; 01568 } 01569 if (rc) 01570 /*@innerbreak@*/ break; 01571 } 01572 if (rc) break; 01573 01574 /* Save last validated path. */ 01575 /*@-compdef@*/ /* FIX: ldn/path annotations ? */ 01576 if (iosm->ldnalloc < (dnlen + 1)) { 01577 iosm->ldnalloc = dnlen + 100; 01578 iosm->ldn = xrealloc(iosm->ldn, iosm->ldnalloc); 01579 } 01580 if (iosm->ldn != NULL) { /* XXX can't happen */ 01581 strcpy(iosm->ldn, iosm->path); 01582 iosm->ldnlen = dnlen; 01583 } 01584 /*@=compdef@*/ 01585 } 01586 dnli = dnlFreeIterator(dnli); 01587 /*@=observertrans =dependenttrans@*/ 01588 01589 iosm->path = path; 01590 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01591 /*@-compdef@*/ /* FIX: ldn/path annotations ? */ 01592 return rc; 01593 /*@=compdef@*/ 01594 } 01595 01596 #ifdef NOTYET 01597 01602 static int iosmStat(/*@special@*/ /*@partial@*/ IOSM_t iosm) 01603 /*@globals fileSystem, internalState @*/ 01604 /*@modifies iosm, fileSystem, internalState @*/ 01605 { 01606 int rc = 0; 01607 01608 if (iosm->path != NULL) { 01609 int saveernno = errno; 01610 rc = iosmUNSAFE(iosm, (!(iosm->mapFlags & IOSM_FOLLOW_SYMLINKS) 01611 ? IOSM_LSTAT : IOSM_STAT)); 01612 if (rc == IOSMERR_ENOENT) { 01613 errno = saveerrno; 01614 rc = 0; 01615 iosm->exists = 0; 01616 } else if (rc == 0) { 01617 iosm->exists = 1; 01618 } 01619 } else { 01620 /* Skip %ghost files on build. */ 01621 iosm->exists = 0; 01622 } 01623 return rc; 01624 } 01625 #endif 01626 01627 #define IS_DEV_LOG(_x) \ 01628 ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \ 01629 !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \ 01630 ((_x)[sizeof("/dev/log")-1] == '\0' || \ 01631 (_x)[sizeof("/dev/log")-1] == ';')) 01632 01633 /*@-compmempass@*/ 01634 int iosmStage(IOSM_t iosm, iosmFileStage stage) 01635 { 01636 #ifdef NOTUSED 01637 iosmFileStage prevStage = iosm->stage; 01638 const char * const prev = iosmFileStageString(prevStage); 01639 #endif 01640 const char * const cur = iosmFileStageString(stage); 01641 struct stat * st = &iosm->sb; 01642 struct stat * ost = &iosm->osb; 01643 int saveerrno = errno; 01644 int rc = iosm->rc; 01645 size_t left; 01646 int i; 01647 01648 #define _fafilter(_a) \ 01649 (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \ 01650 ? iosmFileActionString(_a) : "") 01651 01652 if (stage & IOSM_DEAD) { 01653 /* do nothing */ 01654 } else if (stage & IOSM_INTERNAL) { 01655 if (iosm->debug && !(stage & IOSM_SYSCALL)) 01656 rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n", 01657 cur, 01658 (unsigned)st->st_mode, (int)st->st_nlink, 01659 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 01660 (iosm->path ? iosm->path : ""), 01661 _fafilter(iosm->action)); 01662 } else { 01663 const char * apath = NULL; 01664 if (iosm->path) 01665 (void) urlPath(iosm->path, &apath); 01666 iosm->stage = stage; 01667 if (iosm->debug || !(stage & IOSM_VERBOSE)) 01668 rpmlog(RPMLOG_DEBUG, "%-8s %06o%3d (%4d,%4d)%12lu %s %s\n", 01669 cur, 01670 (unsigned)st->st_mode, (int)st->st_nlink, 01671 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 01672 (apath ? apath + iosm->astriplen : ""), 01673 _fafilter(iosm->action)); 01674 } 01675 #undef _fafilter 01676 01677 switch (stage) { 01678 case IOSM_UNKNOWN: 01679 break; 01680 case IOSM_PKGINSTALL: 01681 while (1) { 01682 /* Clean iosm, free'ing memory. Read next archive header. */ 01683 rc = iosmUNSAFE(iosm, IOSM_INIT); 01684 01685 /* Exit on end-of-payload. */ 01686 if (rc == IOSMERR_HDR_TRAILER) { 01687 rc = 0; 01688 /*@loopbreak@*/ break; 01689 } 01690 01691 /* Exit on error. */ 01692 if (rc) { 01693 iosm->postpone = 1; 01694 (void) iosmNext(iosm, IOSM_UNDO); 01695 /*@loopbreak@*/ break; 01696 } 01697 01698 /* Extract file from archive. */ 01699 rc = iosmNext(iosm, IOSM_PROCESS); 01700 if (rc) { 01701 (void) iosmNext(iosm, IOSM_UNDO); 01702 /*@loopbreak@*/ break; 01703 } 01704 01705 /* Notify on success. */ 01706 (void) iosmNext(iosm, IOSM_NOTIFY); 01707 01708 rc = iosmNext(iosm, IOSM_FINI); 01709 if (rc) { 01710 /*@loopbreak@*/ break; 01711 } 01712 } 01713 break; 01714 case IOSM_PKGERASE: 01715 case IOSM_PKGCOMMIT: 01716 while (1) { 01717 /* Clean iosm, free'ing memory. */ 01718 rc = iosmUNSAFE(iosm, IOSM_INIT); 01719 01720 /* Exit on end-of-payload. */ 01721 if (rc == IOSMERR_HDR_TRAILER) { 01722 rc = 0; 01723 /*@loopbreak@*/ break; 01724 } 01725 01726 /* Rename/erase next item. */ 01727 if (iosmNext(iosm, IOSM_FINI)) 01728 /*@loopbreak@*/ break; 01729 } 01730 break; 01731 case IOSM_PKGBUILD: 01732 while (1) { 01733 01734 rc = iosmUNSAFE(iosm, IOSM_INIT); 01735 01736 /* Exit on end-of-payload. */ 01737 if (rc == IOSMERR_HDR_TRAILER) { 01738 rc = 0; 01739 /*@loopbreak@*/ break; 01740 } 01741 01742 /* Exit on error. */ 01743 if (rc) { 01744 iosm->postpone = 1; 01745 (void) iosmNext(iosm, IOSM_UNDO); 01746 /*@loopbreak@*/ break; 01747 } 01748 01749 /* Copy file into archive. */ 01750 rc = iosmNext(iosm, IOSM_PROCESS); 01751 if (rc) { 01752 (void) iosmNext(iosm, IOSM_UNDO); 01753 /*@loopbreak@*/ break; 01754 } 01755 01756 /* Notify on success. */ 01757 (void) iosmNext(iosm, IOSM_NOTIFY); 01758 01759 if (iosmNext(iosm, IOSM_FINI)) 01760 /*@loopbreak@*/ break; 01761 } 01762 01763 /* Flush partial sets of hard linked files. */ 01764 if (!(iosm->mapFlags & IOSM_ALL_HARDLINKS)) { 01765 int nlink, j; 01766 while ((iosm->li = iosm->links) != NULL) { 01767 iosm->links = iosm->li->next; 01768 iosm->li->next = NULL; 01769 01770 /* Re-calculate link count for archive header. */ 01771 for (j = -1, nlink = 0, i = 0; i < iosm->li->nlink; i++) { 01772 if (iosm->li->filex[i] < 0) 01773 /*@innercontinue@*/ continue; 01774 nlink++; 01775 if (j == -1) j = i; 01776 } 01777 /* XXX force the contents out as well. */ 01778 if (j != 0) { 01779 iosm->li->filex[0] = iosm->li->filex[j]; 01780 iosm->li->filex[j] = -1; 01781 } 01782 iosm->li->sb.st_nlink = nlink; 01783 01784 iosm->sb = iosm->li->sb; /* structure assignment */ 01785 iosm->osb = iosm->sb; /* structure assignment */ 01786 01787 if (!rc) rc = writeLinkedFile(iosm); 01788 01789 iosm->li = freeHardLink(iosm->li); 01790 } 01791 } 01792 01793 if (!rc) 01794 rc = iosmNext(iosm, IOSM_TRAILER); 01795 01796 break; 01797 case IOSM_CREATE: 01798 iosm->path = _free(iosm->path); 01799 iosm->lpath = _free(iosm->lpath); 01800 iosm->opath = _free(iosm->opath); 01801 iosm->dnlx = _free(iosm->dnlx); 01802 01803 iosm->ldn = _free(iosm->ldn); 01804 iosm->ldnalloc = iosm->ldnlen = 0; 01805 01806 iosm->rdsize = iosm->wrsize = 0; 01807 iosm->rdbuf = iosm->rdb = _free(iosm->rdb); 01808 iosm->wrbuf = iosm->wrb = _free(iosm->wrb); 01809 if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) { 01810 iosm->rdsize = 16 * BUFSIZ; 01811 iosm->rdbuf = iosm->rdb = xmalloc(iosm->rdsize); 01812 iosm->wrsize = 16 * BUFSIZ; 01813 iosm->wrbuf = iosm->wrb = xmalloc(iosm->wrsize); 01814 } 01815 01816 iosm->mkdirsdone = 0; 01817 iosm->ix = -1; 01818 iosm->links = NULL; 01819 iosm->li = NULL; 01820 errno = 0; /* XXX get rid of EBADF */ 01821 01822 /* Detect and create directories not explicitly in package. */ 01823 if (iosm->goal == IOSM_PKGINSTALL) { 01824 /*@-compdef@*/ 01825 rc = iosmNext(iosm, IOSM_MKDIRS); 01826 /*@=compdef@*/ 01827 if (!rc) iosm->mkdirsdone = 1; 01828 } 01829 01830 break; 01831 case IOSM_INIT: 01832 iosm->path = _free(iosm->path); 01833 iosm->lpath = _free(iosm->lpath); 01834 iosm->postpone = 0; 01835 iosm->diskchecked = iosm->exists = 0; 01836 iosm->subdir = NULL; 01837 iosm->suffix = (iosm->sufbuf[0] != '\0' ? iosm->sufbuf : NULL); 01838 iosm->action = FA_UNKNOWN; 01839 iosm->osuffix = NULL; 01840 iosm->nsuffix = NULL; 01841 01842 if (iosm->goal == IOSM_PKGINSTALL) { 01843 /* Read next header from payload, checking for end-of-payload. */ 01844 rc = iosmUNSAFE(iosm, IOSM_NEXT); 01845 } 01846 if (rc) break; 01847 01848 /* Identify mapping index. */ 01849 iosm->ix = ((iosm->goal == IOSM_PKGINSTALL) 01850 ? mapFind(iosm->iter, iosm->path) : mapNextIterator(iosm->iter)); 01851 01852 { rpmfi fi = iosmGetFi(iosm); 01853 if (fi != NULL && !(fi->mapflags & IOSM_PAYLOAD_LIST)) { 01854 /* Detect end-of-loop and/or mapping error. */ 01855 if (!(fi->mapflags & IOSM_PAYLOAD_EXTRACT)) { 01856 if (iosm->ix < 0) { 01857 if (iosm->goal == IOSM_PKGINSTALL) { 01858 #if 0 01859 rpmlog(RPMLOG_WARNING, 01860 _("archive file %s was not found in header\n"), 01861 iosm->path); 01862 #endif 01863 if (iosm->failedFile && *iosm->failedFile == NULL) 01864 *iosm->failedFile = xstrdup(iosm->path); 01865 rc = IOSMERR_UNMAPPED_FILE; 01866 } else 01867 rc = IOSMERR_HDR_TRAILER; 01868 break; 01869 } 01870 } 01871 01872 /* On non-install, mode must be known so dirs don't get suffixed. */ 01873 if (iosm->goal != IOSM_PKGINSTALL) 01874 st->st_mode = fi->fmodes[iosm->ix]; 01875 } 01876 } 01877 01878 /* Generate file path. */ 01879 rc = iosmNext(iosm, IOSM_MAP); 01880 if (rc) break; 01881 01882 /* Perform lstat/stat for disk file. */ 01883 #ifdef NOTYET 01884 rc = iosmStat(iosm); 01885 #else 01886 if (iosm->path != NULL && 01887 !(iosm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))) 01888 { 01889 rc = iosmUNSAFE(iosm, (!(iosm->mapFlags & IOSM_FOLLOW_SYMLINKS) 01890 ? IOSM_LSTAT : IOSM_STAT)); 01891 if (rc == IOSMERR_ENOENT) { 01892 errno = saveerrno; 01893 rc = 0; 01894 iosm->exists = 0; 01895 } else if (rc == 0) { 01896 iosm->exists = 1; 01897 } 01898 } else { 01899 /* Skip %ghost files on build. */ 01900 iosm->exists = 0; 01901 } 01902 #endif 01903 iosm->diskchecked = 1; 01904 if (rc) break; 01905 01906 /* On non-install, the disk file stat is what's remapped. */ 01907 if (iosm->goal != IOSM_PKGINSTALL) 01908 *st = *ost; /* structure assignment */ 01909 01910 /* Remap file perms, owner, and group. */ 01911 rc = iosmMapAttrs(iosm); 01912 if (rc) break; 01913 01914 iosm->postpone = iosmFileActionSkipped(iosm->action); 01915 if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) { 01916 /*@-evalorder@*/ /* FIX: saveHardLink can modify iosm */ 01917 if (S_ISREG(st->st_mode) && st->st_nlink > 1) 01918 iosm->postpone = saveHardLink(iosm); 01919 /*@=evalorder@*/ 01920 } 01921 { rpmfi fi = iosmGetFi(iosm); 01922 if (fi != NULL && (fi->mapflags & IOSM_PAYLOAD_LIST)) 01923 iosm->postpone = 1; 01924 } 01925 break; 01926 case IOSM_PRE: 01927 break; 01928 case IOSM_MAP: 01929 rc = iosmMapPath(iosm); 01930 break; 01931 case IOSM_MKDIRS: 01932 rc = iosmMkdirs(iosm); 01933 break; 01934 case IOSM_RMDIRS: 01935 if (iosm->dnlx) 01936 rc = iosmRmdirs(iosm); 01937 break; 01938 case IOSM_PROCESS: 01939 if (iosm->postpone) { 01940 if (iosm->goal == IOSM_PKGINSTALL) { 01941 /* XXX Skip over file body, archive headers already done. */ 01942 if (S_ISREG(st->st_mode)) 01943 rc = iosmNext(iosm, IOSM_EAT); 01944 } 01945 break; 01946 } 01947 01948 if (iosm->goal == IOSM_PKGBUILD) { 01949 if (iosm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */ 01950 break; 01951 if (S_ISREG(st->st_mode) && st->st_nlink > 1) { 01952 struct hardLink_s * li, * prev; 01953 01954 if (!(iosm->mapFlags & IOSM_ALL_HARDLINKS)) break; 01955 rc = writeLinkedFile(iosm); 01956 if (rc) break; /* W2DO? */ 01957 01958 for (li = iosm->links, prev = NULL; li; prev = li, li = li->next) 01959 if (li == iosm->li) 01960 /*@loopbreak@*/ break; 01961 01962 if (prev == NULL) 01963 iosm->links = iosm->li->next; 01964 else 01965 prev->next = iosm->li->next; 01966 iosm->li->next = NULL; 01967 iosm->li = freeHardLink(iosm->li); 01968 } else { 01969 rc = writeFile(iosm, 1); 01970 } 01971 break; 01972 } 01973 01974 if (iosm->goal != IOSM_PKGINSTALL) 01975 break; 01976 01977 if (S_ISREG(st->st_mode) && iosm->lpath != NULL) { 01978 const char * opath = iosm->opath; 01979 char * t = xmalloc(strlen(iosm->lpath+1) + strlen(iosm->suffix) + 1); 01980 (void) stpcpy(t, iosm->lpath+1); 01981 iosm->opath = t; 01982 /* XXX link(iosm->opath, iosm->path) */ 01983 rc = iosmNext(iosm, IOSM_LINK); 01984 if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) { 01985 *iosm->failedFile = xstrdup(iosm->path); 01986 } 01987 iosm->opath = _free(iosm->opath); 01988 iosm->opath = opath; 01989 break; /* XXX so that delayed hard links get skipped. */ 01990 } 01991 if (S_ISREG(st->st_mode)) { 01992 const char * path = iosm->path; 01993 if (iosm->osuffix) 01994 iosm->path = iosmFsPath(iosm, st, NULL, NULL); 01995 rc = iosmUNSAFE(iosm, IOSM_VERIFY); 01996 01997 if (rc == 0 && iosm->osuffix) { 01998 const char * opath = iosm->opath; 01999 iosm->opath = iosm->path; 02000 iosm->path = iosmFsPath(iosm, st, NULL, iosm->osuffix); 02001 rc = iosmNext(iosm, IOSM_RENAME); 02002 if (!rc) 02003 rpmlog(RPMLOG_WARNING, 02004 _("%s saved as %s\n"), 02005 (iosm->opath ? iosm->opath : ""), 02006 (iosm->path ? iosm->path : "")); 02007 iosm->path = _free(iosm->path); 02008 iosm->opath = opath; 02009 } 02010 02011 /*@-dependenttrans@*/ 02012 iosm->path = path; 02013 /*@=dependenttrans@*/ 02014 if (!(rc == IOSMERR_ENOENT)) return rc; 02015 rc = extractRegular(iosm); 02016 } else if (S_ISDIR(st->st_mode)) { 02017 mode_t st_mode = st->st_mode; 02018 rc = iosmUNSAFE(iosm, IOSM_VERIFY); 02019 if (rc == IOSMERR_ENOENT) { 02020 st->st_mode &= ~07777; /* XXX abuse st->st_mode */ 02021 st->st_mode |= 00700; 02022 rc = iosmNext(iosm, IOSM_MKDIR); 02023 st->st_mode = st_mode; /* XXX restore st->st_mode */ 02024 } 02025 } else if (S_ISLNK(st->st_mode)) { 02026 assert(iosm->lpath != NULL); 02027 rc = iosmUNSAFE(iosm, IOSM_VERIFY); 02028 if (rc == IOSMERR_ENOENT) 02029 rc = iosmNext(iosm, IOSM_SYMLINK); 02030 } else if (S_ISFIFO(st->st_mode)) { 02031 mode_t st_mode = st->st_mode; 02032 /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */ 02033 rc = iosmUNSAFE(iosm, IOSM_VERIFY); 02034 if (rc == IOSMERR_ENOENT) { 02035 st->st_mode = 0000; /* XXX abuse st->st_mode */ 02036 rc = iosmNext(iosm, IOSM_MKFIFO); 02037 st->st_mode = st_mode; /* XXX restore st->st_mode */ 02038 } 02039 } else if (S_ISCHR(st->st_mode) || 02040 S_ISBLK(st->st_mode) || 02041 /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/) 02042 { 02043 rc = iosmUNSAFE(iosm, IOSM_VERIFY); 02044 if (rc == IOSMERR_ENOENT) 02045 rc = iosmNext(iosm, IOSM_MKNOD); 02046 } else { 02047 /* XXX Repackaged payloads may be missing files. */ 02048 if (iosm->repackaged) 02049 break; 02050 02051 /* XXX Special case /dev/log, which shouldn't be packaged anyways */ 02052 if (!IS_DEV_LOG(iosm->path)) 02053 rc = IOSMERR_UNKNOWN_FILETYPE; 02054 } 02055 if (S_ISREG(st->st_mode) && st->st_nlink > 1) { 02056 iosm->li->createdPath = iosm->li->linkIndex; 02057 rc = iosmMakeLinks(iosm); 02058 } 02059 break; 02060 case IOSM_POST: 02061 break; 02062 case IOSM_MKLINKS: 02063 rc = iosmMakeLinks(iosm); 02064 break; 02065 case IOSM_NOTIFY: /* XXX move from iosm to psm -> tsm */ 02066 #if defined(_USE_RPMTS) 02067 if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) { 02068 rpmfi fi = iosmGetFi(iosm); 02069 rpmuint64_t archivePos = fdGetCpioPos(iosm->cfd); 02070 if (archivePos > fi->archivePos) { 02071 fi->archivePos = (unsigned long long) archivePos; 02072 (void) rpmtsNotify(iosmGetTs(iosm), fi->te,RPMCALLBACK_INST_PROGRESS, 02073 fi->archivePos, fi->archiveSize); 02074 } 02075 } 02076 #endif 02077 break; 02078 case IOSM_UNDO: 02079 if (iosm->postpone) 02080 break; 02081 if (iosm->goal == IOSM_PKGINSTALL) { 02082 /* XXX only erase if temp fn w suffix is in use */ 02083 if (iosm->sufbuf[0] != '\0') 02084 (void) iosmNext(iosm, 02085 (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK)); 02086 02087 #ifdef NOTYET /* XXX remove only dirs just created, not all. */ 02088 if (iosm->dnlx) 02089 (void) iosmNext(iosm, IOSM_RMDIRS); 02090 #endif 02091 errno = saveerrno; 02092 } 02093 if (iosm->failedFile && *iosm->failedFile == NULL) 02094 *iosm->failedFile = xstrdup(iosm->path); 02095 break; 02096 case IOSM_FINI: 02097 if (!iosm->postpone && iosm->commit) { 02098 if (iosm->goal == IOSM_PKGINSTALL) 02099 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1) 02100 ? iosmCommitLinks(iosm) : iosmNext(iosm, IOSM_COMMIT)); 02101 if (iosm->goal == IOSM_PKGCOMMIT) 02102 rc = iosmNext(iosm, IOSM_COMMIT); 02103 if (iosm->goal == IOSM_PKGERASE) 02104 rc = iosmNext(iosm, IOSM_COMMIT); 02105 } 02106 iosm->path = _free(iosm->path); 02107 iosm->lpath = _free(iosm->lpath); 02108 iosm->opath = _free(iosm->opath); 02109 memset(st, 0, sizeof(*st)); 02110 memset(ost, 0, sizeof(*ost)); 02111 break; 02112 case IOSM_COMMIT: 02113 /* Rename pre-existing modified or unmanaged file. */ 02114 if (iosm->osuffix && iosm->diskchecked && 02115 (iosm->exists || (iosm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))) 02116 { 02117 const char * opath = iosm->opath; 02118 const char * path = iosm->path; 02119 iosm->opath = iosmFsPath(iosm, st, NULL, NULL); 02120 iosm->path = iosmFsPath(iosm, st, NULL, iosm->osuffix); 02121 rc = iosmNext(iosm, IOSM_RENAME); 02122 if (!rc) { 02123 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), 02124 (iosm->opath ? iosm->opath : ""), 02125 (iosm->path ? iosm->path : "")); 02126 } 02127 iosm->path = _free(iosm->path); 02128 iosm->path = path; 02129 iosm->opath = _free(iosm->opath); 02130 iosm->opath = opath; 02131 } 02132 02133 /* Remove erased files. */ 02134 if (iosm->goal == IOSM_PKGERASE) { 02135 if (iosm->action == FA_ERASE) { 02136 if (S_ISDIR(st->st_mode)) { 02137 rc = iosmNext(iosm, IOSM_RMDIR); 02138 if (!rc) break; 02139 switch (rc) { 02140 case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */ 02141 case IOSMERR_ENOTEMPTY: 02142 /* XXX make sure that build side permits %missingok on directories. */ 02143 if (iosm->fflags & RPMFILE_MISSINGOK) 02144 /*@innerbreak@*/ break; 02145 02146 /* XXX common error message. */ 02147 rpmlog( 02148 (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02149 _("rmdir of %s failed: Directory not empty\n"), 02150 iosm->path); 02151 /*@innerbreak@*/ break; 02152 default: 02153 rpmlog( 02154 (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02155 _("rmdir of %s failed: %s\n"), 02156 iosm->path, strerror(errno)); 02157 /*@innerbreak@*/ break; 02158 } 02159 } else { 02160 rc = iosmNext(iosm, IOSM_UNLINK); 02161 if (!rc) break; 02162 switch (rc) { 02163 case IOSMERR_ENOENT: 02164 if (iosm->fflags & RPMFILE_MISSINGOK) 02165 /*@innerbreak@*/ break; 02166 /*@fallthrough@*/ 02167 default: 02168 rpmlog( 02169 (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02170 _("unlink of %s failed: %s\n"), 02171 iosm->path, strerror(errno)); 02172 /*@innerbreak@*/ break; 02173 } 02174 } 02175 } 02176 /* XXX Failure to remove is not (yet) cause for failure. */ 02177 if (!iosm->strict_erasures) rc = 0; 02178 break; 02179 } 02180 02181 /* XXX Special case /dev/log, which shouldn't be packaged anyways */ 02182 { rpmfi fi = iosmGetFi(iosm); 02183 if (!(fi->mapflags & IOSM_PAYLOAD_EXTRACT)) { 02184 if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(iosm->path)) { 02185 /* Rename temporary to final file name. */ 02186 if (!S_ISDIR(st->st_mode) && 02187 (iosm->subdir || iosm->suffix || iosm->nsuffix)) 02188 { 02189 iosm->opath = iosm->path; 02190 iosm->path = iosmFsPath(iosm, st, NULL, iosm->nsuffix); 02191 rc = iosmNext(iosm, IOSM_RENAME); 02192 if (rc) 02193 (void) Unlink(iosm->opath); 02194 else if (iosm->nsuffix) { 02195 const char * opath = iosmFsPath(iosm, st, NULL, NULL); 02196 rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), 02197 (opath ? opath : ""), 02198 (iosm->path ? iosm->path : "")); 02199 opath = _free(opath); 02200 } 02201 iosm->opath = _free(iosm->opath); 02202 } 02203 /* 02204 * Set file security context (if not disabled). 02205 */ 02206 if (!rc && !getuid()) { 02207 rc = iosmMapFContext(iosm); 02208 if (!rc) 02209 rc = iosmNext(iosm, IOSM_LSETFCON); 02210 iosm->fcontext = NULL; 02211 } 02212 if (S_ISLNK(st->st_mode)) { 02213 if (!rc && !getuid()) 02214 rc = iosmNext(iosm, IOSM_LCHOWN); 02215 } else { 02216 if (!rc && !getuid()) 02217 rc = iosmNext(iosm, IOSM_CHOWN); 02218 if (!rc) 02219 rc = iosmNext(iosm, IOSM_CHMOD); 02220 if (!rc) { 02221 time_t mtime = st->st_mtime; 02222 if (fi->fmtimes) 02223 st->st_mtime = fi->fmtimes[iosm->ix]; 02224 rc = iosmNext(iosm, IOSM_UTIME); 02225 st->st_mtime = mtime; 02226 } 02227 } 02228 } 02229 } 02230 } 02231 02232 /* Notify on success. */ 02233 if (!rc) rc = iosmNext(iosm, IOSM_NOTIFY); 02234 else if (iosm->failedFile && *iosm->failedFile == NULL) { 02235 *iosm->failedFile = iosm->path; 02236 iosm->path = NULL; 02237 } 02238 break; 02239 case IOSM_DESTROY: 02240 iosm->path = _free(iosm->path); 02241 02242 /* Check for hard links missing from payload. */ 02243 while ((iosm->li = iosm->links) != NULL) { 02244 iosm->links = iosm->li->next; 02245 iosm->li->next = NULL; 02246 if (iosm->goal == IOSM_PKGINSTALL && 02247 iosm->commit && iosm->li->linksLeft) 02248 { 02249 for (i = 0 ; i < iosm->li->linksLeft; i++) { 02250 if (iosm->li->filex[i] < 0) 02251 /*@innercontinue@*/ continue; 02252 rc = IOSMERR_MISSING_HARDLINK; 02253 if (iosm->failedFile && *iosm->failedFile == NULL) { 02254 iosm->ix = iosm->li->filex[i]; 02255 if (!iosmNext(iosm, IOSM_MAP)) { 02256 *iosm->failedFile = iosm->path; 02257 iosm->path = NULL; 02258 } 02259 } 02260 /*@loopbreak@*/ break; 02261 } 02262 } 02263 if (iosm->goal == IOSM_PKGBUILD && 02264 (iosm->mapFlags & IOSM_ALL_HARDLINKS)) 02265 { 02266 rc = IOSMERR_MISSING_HARDLINK; 02267 } 02268 iosm->li = freeHardLink(iosm->li); 02269 } 02270 iosm->ldn = _free(iosm->ldn); 02271 iosm->ldnalloc = iosm->ldnlen = 0; 02272 iosm->rdbuf = iosm->rdb = _free(iosm->rdb); 02273 iosm->wrbuf = iosm->wrb = _free(iosm->wrb); 02274 break; 02275 case IOSM_VERIFY: 02276 if (iosm->diskchecked && !iosm->exists) { 02277 rc = IOSMERR_ENOENT; 02278 break; 02279 } 02280 if (S_ISREG(st->st_mode)) { 02281 char * path = alloca(strlen(iosm->path) + sizeof("-RPMDELETE")); 02282 (void) stpcpy( stpcpy(path, iosm->path), "-RPMDELETE"); 02283 /* 02284 * XXX HP-UX (and other os'es) don't permit unlink on busy 02285 * XXX files. 02286 */ 02287 iosm->opath = iosm->path; 02288 iosm->path = path; 02289 rc = iosmNext(iosm, IOSM_RENAME); 02290 if (!rc) 02291 (void) iosmNext(iosm, IOSM_UNLINK); 02292 else 02293 rc = IOSMERR_UNLINK_FAILED; 02294 iosm->path = iosm->opath; 02295 iosm->opath = NULL; 02296 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */ 02297 /*@notreached@*/ break; 02298 } else if (S_ISDIR(st->st_mode)) { 02299 if (S_ISDIR(ost->st_mode)) return 0; 02300 if (S_ISLNK(ost->st_mode)) { 02301 rc = iosmUNSAFE(iosm, IOSM_STAT); 02302 if (rc == IOSMERR_ENOENT) rc = 0; 02303 if (rc) break; 02304 errno = saveerrno; 02305 if (S_ISDIR(ost->st_mode)) return 0; 02306 } 02307 } else if (S_ISLNK(st->st_mode)) { 02308 if (S_ISLNK(ost->st_mode)) { 02309 /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */ 02310 rc = iosmUNSAFE(iosm, IOSM_READLINK); 02311 errno = saveerrno; 02312 if (rc) break; 02313 if (!strcmp(iosm->lpath, iosm->rdbuf)) return 0; 02314 } 02315 } else if (S_ISFIFO(st->st_mode)) { 02316 if (S_ISFIFO(ost->st_mode)) return 0; 02317 } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { 02318 if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) && 02319 (ost->st_rdev == st->st_rdev)) return 0; 02320 } else if (S_ISSOCK(st->st_mode)) { 02321 if (S_ISSOCK(ost->st_mode)) return 0; 02322 } 02323 /* XXX shouldn't do this with commit/undo. */ 02324 rc = 0; 02325 if (iosm->stage == IOSM_PROCESS) rc = iosmNext(iosm, IOSM_UNLINK); 02326 if (rc == 0) rc = IOSMERR_ENOENT; 02327 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */ 02328 /*@notreached@*/ break; 02329 02330 case IOSM_UNLINK: 02331 /* XXX Remove setuid/setgid bits on possibly hard linked files. */ 02332 if (iosm->mapFlags & IOSM_SBIT_CHECK) { 02333 struct stat stb; 02334 if (Lstat(iosm->path, &stb) == 0 02335 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) 02336 { 02337 /* XXX rc = iosmNext(iosm, IOSM_CHMOD); instead */ 02338 (void)Chmod(iosm->path, stb.st_mode & 0777); 02339 } 02340 } 02341 rc = Unlink(iosm->path); 02342 if (iosm->debug && (stage & IOSM_SYSCALL)) 02343 rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", cur, 02344 iosm->path, (rc < 0 ? strerror(errno) : "")); 02345 if (rc < 0) 02346 rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_UNLINK_FAILED); 02347 break; 02348 case IOSM_RENAME: 02349 /* XXX Remove setuid/setgid bits on possibly hard linked files. */ 02350 if (iosm->mapFlags & IOSM_SBIT_CHECK) { 02351 struct stat stb; 02352 if (Lstat(iosm->path, &stb) == 0 02353 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) 02354 { 02355 /* XXX rc = iosmNext(iosm, IOSM_CHMOD); instead */ 02356 (void)Chmod(iosm->path, stb.st_mode & 0777); 02357 } 02358 } 02359 rc = Rename(iosm->opath, iosm->path); 02360 /* XXX Repackaged payloads may be missing files. */ 02361 if (iosm->repackaged) 02362 rc = 0; 02363 #if defined(ETXTBSY) 02364 if (rc && errno == ETXTBSY) { 02365 char * path = alloca(strlen(iosm->path) + sizeof("-RPMDELETE")); 02366 (void) stpcpy( stpcpy(path, iosm->path), "-RPMDELETE"); 02367 /* 02368 * XXX HP-UX (and other os'es) don't permit rename to busy 02369 * XXX files. 02370 */ 02371 rc = Rename(iosm->path, path); 02372 if (!rc) rc = Rename(iosm->opath, iosm->path); 02373 } 02374 #endif 02375 if (iosm->debug && (stage & IOSM_SYSCALL)) 02376 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur, 02377 iosm->opath, iosm->path, (rc < 0 ? strerror(errno) : "")); 02378 if (rc < 0) rc = IOSMERR_RENAME_FAILED; 02379 break; 02380 case IOSM_MKDIR: 02381 rc = Mkdir(iosm->path, (st->st_mode & 07777)); 02382 if (iosm->debug && (stage & IOSM_SYSCALL)) 02383 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur, 02384 iosm->path, (unsigned)(st->st_mode & 07777), 02385 (rc < 0 ? strerror(errno) : "")); 02386 if (rc < 0) rc = IOSMERR_MKDIR_FAILED; 02387 break; 02388 case IOSM_RMDIR: 02389 rc = Rmdir(iosm->path); 02390 if (iosm->debug && (stage & IOSM_SYSCALL)) 02391 rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", cur, 02392 iosm->path, (rc < 0 ? strerror(errno) : "")); 02393 if (rc < 0) 02394 switch (errno) { 02395 case ENOENT: rc = IOSMERR_ENOENT; /*@switchbreak@*/ break; 02396 case ENOTEMPTY: rc = IOSMERR_ENOTEMPTY; /*@switchbreak@*/ break; 02397 default: rc = IOSMERR_RMDIR_FAILED; /*@switchbreak@*/ break; 02398 } 02399 break; 02400 case IOSM_LSETFCON: 02401 { const char * iosmpath = NULL; 02402 if (iosm->fcontext == NULL || *iosm->fcontext == '\0' 02403 || !strcmp(iosm->fcontext, "<<none>>")) 02404 break; 02405 (void) urlPath(iosm->path, &iosmpath); /* XXX iosm->path */ 02406 rc = rpmsxLsetfilecon(NULL, iosmpath, 0, iosm->fcontext); 02407 if (iosm->debug && (stage & IOSM_SYSCALL)) 02408 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur, 02409 iosm->path, iosm->fcontext, 02410 (rc < 0 ? strerror(errno) : "")); 02411 if (rc < 0) rc = (errno == EOPNOTSUPP ? 0 : IOSMERR_LSETFCON_FAILED); 02412 } break; 02413 case IOSM_CHOWN: 02414 rc = Chown(iosm->path, st->st_uid, st->st_gid); 02415 if (iosm->debug && (stage & IOSM_SYSCALL)) 02416 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", cur, 02417 iosm->path, (int)st->st_uid, (int)st->st_gid, 02418 (rc < 0 ? strerror(errno) : "")); 02419 if (rc < 0) rc = IOSMERR_CHOWN_FAILED; 02420 break; 02421 case IOSM_LCHOWN: 02422 #if ! CHOWN_FOLLOWS_SYMLINK 02423 rc = Lchown(iosm->path, st->st_uid, st->st_gid); 02424 if (iosm->debug && (stage & IOSM_SYSCALL)) 02425 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", cur, 02426 iosm->path, (int)st->st_uid, (int)st->st_gid, 02427 (rc < 0 ? strerror(errno) : "")); 02428 if (rc < 0) rc = IOSMERR_CHOWN_FAILED; 02429 #endif 02430 break; 02431 case IOSM_CHMOD: 02432 rc = Chmod(iosm->path, (st->st_mode & 07777)); 02433 if (iosm->debug && (stage & IOSM_SYSCALL)) 02434 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur, 02435 iosm->path, (unsigned)(st->st_mode & 07777), 02436 (rc < 0 ? strerror(errno) : "")); 02437 if (rc < 0) rc = IOSMERR_CHMOD_FAILED; 02438 break; 02439 case IOSM_UTIME: 02440 { struct utimbuf stamp; 02441 stamp.actime = st->st_mtime; 02442 stamp.modtime = st->st_mtime; 02443 rc = Utime(iosm->path, &stamp); 02444 if (iosm->debug && (stage & IOSM_SYSCALL)) 02445 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", cur, 02446 iosm->path, (unsigned)st->st_mtime, 02447 (rc < 0 ? strerror(errno) : "")); 02448 if (rc < 0) rc = IOSMERR_UTIME_FAILED; 02449 } 02450 break; 02451 case IOSM_SYMLINK: 02452 rc = Symlink(iosm->lpath, iosm->path); 02453 if (iosm->debug && (stage & IOSM_SYSCALL)) 02454 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur, 02455 iosm->lpath, iosm->path, (rc < 0 ? strerror(errno) : "")); 02456 if (rc < 0) rc = IOSMERR_SYMLINK_FAILED; 02457 break; 02458 case IOSM_LINK: 02459 rc = Link(iosm->opath, iosm->path); 02460 if (iosm->debug && (stage & IOSM_SYSCALL)) 02461 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur, 02462 iosm->opath, iosm->path, (rc < 0 ? strerror(errno) : "")); 02463 if (rc < 0) rc = IOSMERR_LINK_FAILED; 02464 break; 02465 case IOSM_MKFIFO: 02466 rc = Mkfifo(iosm->path, (st->st_mode & 07777)); 02467 if (iosm->debug && (stage & IOSM_SYSCALL)) 02468 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur, 02469 iosm->path, (unsigned)(st->st_mode & 07777), 02470 (rc < 0 ? strerror(errno) : "")); 02471 if (rc < 0) rc = IOSMERR_MKFIFO_FAILED; 02472 break; 02473 case IOSM_MKNOD: 02474 /*@-unrecog -portability @*/ /* FIX: check S_IFIFO or dev != 0 */ 02475 rc = Mknod(iosm->path, (st->st_mode & ~07777), st->st_rdev); 02476 /*@=unrecog =portability @*/ 02477 if (iosm->debug && (stage & IOSM_SYSCALL)) 02478 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur, 02479 iosm->path, (unsigned)(st->st_mode & ~07777), 02480 (unsigned)st->st_rdev, 02481 (rc < 0 ? strerror(errno) : "")); 02482 if (rc < 0) rc = IOSMERR_MKNOD_FAILED; 02483 break; 02484 case IOSM_LSTAT: 02485 rc = Lstat(iosm->path, ost); 02486 if (iosm->debug && (stage & IOSM_SYSCALL) && rc && errno != ENOENT) 02487 rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", cur, 02488 iosm->path, (rc < 0 ? strerror(errno) : "")); 02489 if (rc < 0) { 02490 rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_LSTAT_FAILED); 02491 memset(ost, 0, sizeof(*ost)); /* XXX s390x hackery */ 02492 } 02493 break; 02494 case IOSM_STAT: 02495 rc = Stat(iosm->path, ost); 02496 if (iosm->debug && (stage & IOSM_SYSCALL) && rc && errno != ENOENT) 02497 rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", cur, 02498 iosm->path, (rc < 0 ? strerror(errno) : "")); 02499 if (rc < 0) { 02500 rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_STAT_FAILED); 02501 memset(ost, 0, sizeof(*ost)); /* XXX s390x hackery */ 02502 } 02503 break; 02504 case IOSM_READLINK: 02505 /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */ 02506 rc = Readlink(iosm->path, iosm->rdbuf, iosm->rdsize - 1); 02507 if (iosm->debug && (stage & IOSM_SYSCALL)) 02508 rpmlog(RPMLOG_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur, 02509 iosm->path, (int)(iosm->rdsize -1), (rc < 0 ? strerror(errno) : "")); 02510 if (rc < 0) rc = IOSMERR_READLINK_FAILED; 02511 else { 02512 iosm->rdnb = rc; 02513 iosm->rdbuf[iosm->rdnb] = '\0'; 02514 rc = 0; 02515 } 02516 break; 02517 case IOSM_CHROOT: 02518 break; 02519 02520 case IOSM_NEXT: 02521 rc = iosmUNSAFE(iosm, IOSM_HREAD); 02522 if (rc) break; 02523 if (!strcmp(iosm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */ 02524 iosm->path = _free(iosm->path); 02525 rc = IOSMERR_HDR_TRAILER; 02526 } 02527 if (!rc) 02528 rc = iosmNext(iosm, IOSM_POS); 02529 break; 02530 case IOSM_EAT: 02531 for (left = st->st_size; left > 0; left -= iosm->rdnb) { 02532 iosm->wrlen = (left > iosm->wrsize ? iosm->wrsize : left); 02533 rc = iosmNext(iosm, IOSM_DREAD); 02534 if (rc) 02535 /*@loopbreak@*/ break; 02536 } 02537 break; 02538 case IOSM_POS: 02539 left = (iosm->blksize - (fdGetCpioPos(iosm->cfd) % iosm->blksize)) % iosm->blksize; 02540 if (left) { 02541 iosm->wrlen = left; 02542 (void) iosmNext(iosm, IOSM_DREAD); 02543 } 02544 break; 02545 case IOSM_PAD: 02546 left = (iosm->blksize - (fdGetCpioPos(iosm->cfd) % iosm->blksize)) % iosm->blksize; 02547 if (left) { 02548 if (iosm->blksize == 2) 02549 iosm->rdbuf[0] = '\n'; /* XXX ar(1) pads with '\n' */ 02550 else 02551 memset(iosm->rdbuf, 0, left); 02552 /* XXX DWRITE uses rdnb for I/O length. */ 02553 iosm->rdnb = left; 02554 (void) iosmNext(iosm, IOSM_DWRITE); 02555 } 02556 break; 02557 case IOSM_TRAILER: 02558 rc = (*iosm->trailerWrite) (iosm); /* Write payload trailer. */ 02559 break; 02560 case IOSM_HREAD: 02561 rc = iosmNext(iosm, IOSM_POS); 02562 if (!rc) 02563 rc = (*iosm->headerRead) (iosm, st);/* Read next payload header. */ 02564 break; 02565 case IOSM_HWRITE: 02566 rc = (*iosm->headerWrite) (iosm, st); /* Write next payload header. */ 02567 break; 02568 case IOSM_DREAD: 02569 iosm->rdnb = Fread(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->wrlen, iosm->cfd); 02570 if (iosm->debug && (stage & IOSM_SYSCALL)) 02571 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n", 02572 cur, (iosm->wrbuf == iosm->wrb ? "wrbuf" : "mmap"), 02573 (int)iosm->wrlen, (int)iosm->rdnb); 02574 if (iosm->rdnb != iosm->wrlen || Ferror(iosm->cfd)) 02575 rc = IOSMERR_READ_FAILED; 02576 if (iosm->rdnb > 0) 02577 fdSetCpioPos(iosm->cfd, fdGetCpioPos(iosm->cfd) + iosm->rdnb); 02578 break; 02579 case IOSM_DWRITE: 02580 iosm->wrnb = Fwrite(iosm->rdbuf, sizeof(*iosm->rdbuf), iosm->rdnb, iosm->cfd); 02581 if (iosm->debug && (stage & IOSM_SYSCALL)) 02582 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n", 02583 cur, (iosm->rdbuf == iosm->rdb ? "rdbuf" : "mmap"), 02584 (int)iosm->rdnb, (int)iosm->wrnb); 02585 if (iosm->rdnb != iosm->wrnb || Ferror(iosm->cfd)) 02586 rc = IOSMERR_WRITE_FAILED; 02587 if (iosm->wrnb > 0) 02588 fdSetCpioPos(iosm->cfd, fdGetCpioPos(iosm->cfd) + iosm->wrnb); 02589 break; 02590 02591 case IOSM_ROPEN: 02592 iosm->rfd = Fopen(iosm->path, "r.fdio"); 02593 if (iosm->rfd == NULL || Ferror(iosm->rfd)) { 02594 if (iosm->rfd != NULL) (void) iosmNext(iosm, IOSM_RCLOSE); 02595 iosm->rfd = NULL; 02596 rc = IOSMERR_OPEN_FAILED; 02597 break; 02598 } 02599 #if defined(POSIX_FADV_WILLNEED) 02600 (void) Fadvise(iosm->rfd, 0, 0, POSIX_FADV_WILLNEED); 02601 #endif 02602 if (iosm->debug && (stage & IOSM_SYSCALL)) 02603 rpmlog(RPMLOG_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur, 02604 iosm->path, iosm->rfd, iosm->rdbuf); 02605 break; 02606 case IOSM_READ: 02607 iosm->rdnb = Fread(iosm->rdbuf, sizeof(*iosm->rdbuf), iosm->rdlen, iosm->rfd); 02608 if (iosm->debug && (stage & IOSM_SYSCALL)) 02609 rpmlog(RPMLOG_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n", 02610 cur, (int)iosm->rdlen, (int)iosm->rdnb); 02611 if (iosm->rdnb != iosm->rdlen || Ferror(iosm->rfd)) 02612 rc = IOSMERR_READ_FAILED; 02613 break; 02614 case IOSM_RCLOSE: 02615 if (iosm->rfd != NULL) { 02616 if (iosm->debug && (stage & IOSM_SYSCALL)) 02617 rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->rfd); 02618 (void) rpmswAdd(&iosm->op_digest, 02619 fdstat_op(iosm->rfd, FDSTAT_DIGEST)); 02620 (void) Fclose(iosm->rfd); 02621 errno = saveerrno; 02622 } 02623 iosm->rfd = NULL; 02624 break; 02625 case IOSM_WOPEN: 02626 iosm->wfd = Fopen(iosm->path, "w.fdio"); 02627 if (iosm->wfd == NULL || Ferror(iosm->wfd)) { 02628 if (iosm->wfd != NULL) (void) iosmNext(iosm, IOSM_WCLOSE); 02629 iosm->wfd = NULL; 02630 rc = IOSMERR_OPEN_FAILED; 02631 } 02632 #if defined(POSIX_FADV_DONTNEED) 02633 else 02634 (void) Fadvise(iosm->wfd, 0, 0, POSIX_FADV_DONTNEED); 02635 #endif 02636 if (iosm->debug && (stage & IOSM_SYSCALL)) 02637 rpmlog(RPMLOG_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur, 02638 iosm->path, iosm->wfd, iosm->wrbuf); 02639 break; 02640 case IOSM_WRITE: 02641 iosm->wrnb = Fwrite(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->rdnb, iosm->wfd); 02642 if (iosm->debug && (stage & IOSM_SYSCALL)) 02643 rpmlog(RPMLOG_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n", 02644 cur, (int)iosm->rdnb, (int)iosm->wrnb); 02645 if (iosm->rdnb != iosm->wrnb || Ferror(iosm->wfd)) 02646 rc = IOSMERR_WRITE_FAILED; 02647 break; 02648 case IOSM_WCLOSE: 02649 if (iosm->wfd != NULL) { 02650 if (iosm->debug && (stage & IOSM_SYSCALL)) 02651 rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->wfd); 02652 (void) rpmswAdd(&iosm->op_digest, 02653 fdstat_op(iosm->wfd, FDSTAT_DIGEST)); 02654 (void) Fclose(iosm->wfd); 02655 errno = saveerrno; 02656 } 02657 iosm->wfd = NULL; 02658 break; 02659 02660 default: 02661 break; 02662 } 02663 02664 if (!(stage & IOSM_INTERNAL)) { 02665 iosm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc); 02666 } 02667 return rc; 02668 } 02669 /*@=compmempass@*/ 02670 02671 #define IOSM_SKIPPING(_a) \ 02672 ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) 02673 02674 int iosmFileActionSkipped(iosmFileAction action) 02675 { 02676 return IOSM_SKIPPING(action); 02677 } 02678 02679 /*@observer@*/ const char * iosmFileActionString(iosmFileAction a) 02680 { 02681 switch (a) { 02682 case FA_UNKNOWN: return "unknown"; 02683 case FA_CREATE: return "create"; 02684 case FA_COPYOUT: return "copyout"; 02685 case FA_COPYIN: return "copyin"; 02686 case FA_BACKUP: return "backup"; 02687 case FA_SAVE: return "save"; 02688 case FA_SKIP: return "skip"; 02689 case FA_ALTNAME: return "altname"; 02690 case FA_ERASE: return "erase"; 02691 case FA_SKIPNSTATE: return "skipnstate"; 02692 case FA_SKIPNETSHARED: return "skipnetshared"; 02693 case FA_SKIPCOLOR: return "skipcolor"; 02694 default: return "???"; 02695 } 02696 /*@notreached@*/ 02697 } 02698 02699 /*@observer@*/ const char * iosmFileStageString(iosmFileStage a) { 02700 switch(a) { 02701 case IOSM_UNKNOWN: return "unknown"; 02702 02703 case IOSM_PKGINSTALL:return "INSTALL"; 02704 case IOSM_PKGERASE: return "ERASE"; 02705 case IOSM_PKGBUILD: return "BUILD"; 02706 case IOSM_PKGCOMMIT: return "COMMIT"; 02707 case IOSM_PKGUNDO: return "UNDO"; 02708 02709 case IOSM_CREATE: return "create"; 02710 case IOSM_INIT: return "init"; 02711 case IOSM_MAP: return "map"; 02712 case IOSM_MKDIRS: return "mkdirs"; 02713 case IOSM_RMDIRS: return "rmdirs"; 02714 case IOSM_PRE: return "pre"; 02715 case IOSM_PROCESS: return "process"; 02716 case IOSM_POST: return "post"; 02717 case IOSM_MKLINKS: return "mklinks"; 02718 case IOSM_NOTIFY: return "notify"; 02719 case IOSM_UNDO: return "undo"; 02720 case IOSM_FINI: return "fini"; 02721 case IOSM_COMMIT: return "commit"; 02722 case IOSM_DESTROY: return "destroy"; 02723 case IOSM_VERIFY: return "verify"; 02724 02725 case IOSM_UNLINK: return "Unlink"; 02726 case IOSM_RENAME: return "Rename"; 02727 case IOSM_MKDIR: return "Mkdir"; 02728 case IOSM_RMDIR: return "Rmdir"; 02729 case IOSM_LSETFCON: return "lsetfcon"; 02730 case IOSM_CHOWN: return "Chown"; 02731 case IOSM_LCHOWN: return "Lchown"; 02732 case IOSM_CHMOD: return "Chmod"; 02733 case IOSM_UTIME: return "Utime"; 02734 case IOSM_SYMLINK: return "Symlink"; 02735 case IOSM_LINK: return "Link"; 02736 case IOSM_MKFIFO: return "Mkfifo"; 02737 case IOSM_MKNOD: return "Mknod"; 02738 case IOSM_LSTAT: return "Lstat"; 02739 case IOSM_STAT: return "Stat"; 02740 case IOSM_READLINK: return "Readlink"; 02741 case IOSM_CHROOT: return "Chroot"; 02742 02743 case IOSM_NEXT: return "next"; 02744 case IOSM_EAT: return "eat"; 02745 case IOSM_POS: return "pos"; 02746 case IOSM_PAD: return "pad"; 02747 case IOSM_TRAILER: return "trailer"; 02748 case IOSM_HREAD: return "hread"; 02749 case IOSM_HWRITE: return "hwrite"; 02750 case IOSM_DREAD: return "Fread"; 02751 case IOSM_DWRITE: return "Fwrite"; 02752 02753 case IOSM_ROPEN: return "Fopen"; 02754 case IOSM_READ: return "Fread"; 02755 case IOSM_RCLOSE: return "Fclose"; 02756 case IOSM_WOPEN: return "Fopen"; 02757 case IOSM_WRITE: return "Fwrite"; 02758 case IOSM_WCLOSE: return "Fclose"; 02759 02760 default: return "???"; 02761 } 02762 /*@noteached@*/ 02763 } 02764 02765 char * iosmStrerror(int rc) 02766 { 02767 char msg[256]; 02768 char *s; 02769 int l, myerrno = errno; 02770 02771 strcpy(msg, "cpio: "); 02772 switch (rc) { 02773 default: 02774 s = msg + strlen(msg); 02775 sprintf(s, _("(error 0x%x)"), (unsigned)rc); 02776 s = NULL; 02777 break; 02778 case IOSMERR_BAD_MAGIC: s = _("Bad magic"); break; 02779 case IOSMERR_BAD_HEADER: s = _("Bad/unreadable header"); break; 02780 02781 case IOSMERR_OPEN_FAILED: s = "open"; break; 02782 case IOSMERR_CHMOD_FAILED: s = "chmod"; break; 02783 case IOSMERR_CHOWN_FAILED: s = "chown"; break; 02784 case IOSMERR_WRITE_FAILED: s = "write"; break; 02785 case IOSMERR_UTIME_FAILED: s = "utime"; break; 02786 case IOSMERR_UNLINK_FAILED: s = "unlink"; break; 02787 case IOSMERR_RENAME_FAILED: s = "rename"; break; 02788 case IOSMERR_SYMLINK_FAILED: s = "symlink"; break; 02789 case IOSMERR_STAT_FAILED: s = "stat"; break; 02790 case IOSMERR_LSTAT_FAILED: s = "lstat"; break; 02791 case IOSMERR_MKDIR_FAILED: s = "mkdir"; break; 02792 case IOSMERR_RMDIR_FAILED: s = "rmdir"; break; 02793 case IOSMERR_MKNOD_FAILED: s = "mknod"; break; 02794 case IOSMERR_MKFIFO_FAILED: s = "mkfifo"; break; 02795 case IOSMERR_LINK_FAILED: s = "link"; break; 02796 case IOSMERR_READLINK_FAILED: s = "readlink"; break; 02797 case IOSMERR_READ_FAILED: s = "read"; break; 02798 case IOSMERR_COPY_FAILED: s = "copy"; break; 02799 case IOSMERR_LSETFCON_FAILED: s = "lsetfilecon"; break; 02800 02801 case IOSMERR_HDR_SIZE: s = _("Header size too big"); break; 02802 case IOSMERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break; 02803 case IOSMERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break; 02804 case IOSMERR_DIGEST_MISMATCH: s = _("File digest mismatch"); break; 02805 case IOSMERR_INTERNAL: s = _("Internal error"); break; 02806 case IOSMERR_UNMAPPED_FILE: s = _("Archive file not in header"); break; 02807 case IOSMERR_ENOENT: s = strerror(ENOENT); break; 02808 case IOSMERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break; 02809 } 02810 02811 l = sizeof(msg) - strlen(msg) - 1; 02812 if (s != NULL) { 02813 if (l > 0) strncat(msg, s, l); 02814 l -= strlen(s); 02815 } 02816 if ((rc & IOSMERR_CHECK_ERRNO) && myerrno) { 02817 s = _(" failed - "); 02818 if (l > 0) strncat(msg, s, l); 02819 l -= strlen(s); 02820 if (l > 0) strncat(msg, strerror(myerrno), l); 02821 } 02822 return xstrdup(msg); 02823 }