rpm 5.3.7
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio_internal.h> /* XXX urlPath, fdGetCpioPos */ 00009 #include <rpmcb.h> /* XXX fnpyKey */ 00010 #include "rpmsq.h" 00011 #include <rpmsx.h> 00012 #if defined(SUPPORT_AR_PAYLOADS) 00013 #include "ar.h" 00014 #endif 00015 #include "cpio.h" 00016 #include "tar.h" 00017 #include "ugid.h" /* XXX unameToUid() and gnameToGid() */ 00018 00019 #include <rpmtag.h> 00020 #include <rpmtypes.h> 00021 #define _RPMDB_INTERNAL 00022 #include <rpmdb.h> 00023 00024 #define _RPMFI_INTERNAL 00025 #include "rpmfi.h" 00026 00027 #define _IOSM_INTERNAL 00028 #include <fsm.h> 00029 #define fsmUNSAFE fsmStage 00030 00031 #define _USE_RPMTE 00032 #if defined(_USE_RPMTE) 00033 #include "rpmte.h" 00034 #endif 00035 #include "rpmts.h" 00036 00037 #include "debug.h" 00038 00039 /*@access FD_t @*/ /* XXX void ptr args */ 00040 /*@access FSMI_t @*/ 00041 /*@access IOSM_t @*/ 00042 /*@access IOSMI_t @*/ 00043 00044 /*@access rpmfi @*/ 00045 00046 /*@access rpmsx @*/ /* XXX cast */ 00047 /*@access rpmte @*/ /* XXX cast */ 00048 /*@access rpmts @*/ /* XXX cast */ 00049 00050 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s)) 00051 00052 #define _FSM_DEBUG 0 00053 /*@unchecked@*/ 00054 int _fsm_debug = _FSM_DEBUG; 00055 00056 /*@-exportheadervar@*/ 00057 /*@unchecked@*/ 00058 int _fsm_threads = 0; 00059 /*@=exportheadervar@*/ 00060 00066 static rpmts fsmGetTs(const IOSM_t fsm) 00067 /*@*/ 00068 { 00069 const FSMI_t iter = fsm->iter; 00070 /*@-compdef -refcounttrans -retexpose -usereleased @*/ 00071 return (iter ? iter->ts : NULL); 00072 /*@=compdef =refcounttrans =retexpose =usereleased @*/ 00073 } 00074 00080 static rpmfi fsmGetFi(const IOSM_t fsm) 00081 /*@*/ 00082 { 00083 const FSMI_t iter = fsm->iter; 00084 /*@-compdef -refcounttrans -retexpose -usereleased @*/ 00085 return (iter ? iter->fi : NULL); 00086 /*@=compdef =refcounttrans =retexpose =usereleased @*/ 00087 } 00088 00089 #define SUFFIX_RPMORIG ".rpmorig" 00090 #define SUFFIX_RPMSAVE ".rpmsave" 00091 #define SUFFIX_RPMNEW ".rpmnew" 00092 00101 static /*@only@*//*@null@*/ 00102 const char * fsmFsPath(/*@special@*/ /*@null@*/ const IOSM_t fsm, 00103 /*@null@*/ const struct stat * st, 00104 /*@null@*/ const char * subdir, 00105 /*@null@*/ const char * suffix) 00106 /*@uses fsm->dirName, fsm->baseName */ 00107 /*@*/ 00108 { 00109 const char * s = NULL; 00110 00111 if (fsm) { 00112 char * t; 00113 int nb; 00114 nb = strlen(fsm->dirName) + 00115 (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) + 00116 (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) + 00117 strlen(fsm->baseName) + 1; 00118 s = t = xmalloc(nb); 00119 t = stpcpy(t, fsm->dirName); 00120 if (st && !S_ISDIR(st->st_mode)) 00121 if (subdir) t = stpcpy(t, subdir); 00122 t = stpcpy(t, fsm->baseName); 00123 if (st && !S_ISDIR(st->st_mode)) 00124 if (suffix) t = stpcpy(t, suffix); 00125 } 00126 return s; 00127 } 00128 00134 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p) 00135 /*@globals fileSystem @*/ 00136 /*@modifies fileSystem @*/ 00137 { 00138 FSMI_t iter = p; 00139 if (iter) { 00140 iter->fi = rpmfiUnlink(iter->fi, "mapIterator"); 00141 /*@-internalglobs@*/ /* XXX rpmswExit() */ 00142 (void)rpmtsFree(iter->ts); 00143 iter->ts = NULL; 00144 /*@=internalglobs@*/ 00145 } 00146 return _free(p); 00147 } 00148 00155 static void * 00156 mapInitIterator(rpmfi fi, int reverse) 00157 /*@modifies fi @*/ 00158 { 00159 FSMI_t iter = NULL; 00160 00161 iter = xcalloc(1, sizeof(*iter)); 00162 /*@-assignexpose -castexpose @*/ 00163 iter->fi = rpmfiLink(fi, "mapIterator"); 00164 /*@=assignexpose =castexpose @*/ 00165 iter->reverse = reverse; 00166 iter->i = (iter->reverse ? (fi->fc - 1) : 0); 00167 iter->isave = iter->i; 00168 return iter; 00169 } 00170 00176 static int mapNextIterator(/*@null@*/ void * a) 00177 /*@*/ 00178 { 00179 FSMI_t iter = a; 00180 int i = -1; 00181 00182 if (iter) { 00183 /*@-onlytrans@*/ 00184 const rpmfi fi = iter->fi; 00185 /*@=onlytrans@*/ 00186 if (iter->reverse) { 00187 if (iter->i >= 0) i = iter->i--; 00188 } else { 00189 if (iter->i < (int)fi->fc) i = iter->i++; 00190 } 00191 iter->isave = i; 00192 } 00193 return i; 00194 } 00195 00198 static int cpioStrCmp(const void * a, const void * b) 00199 /*@*/ 00200 { 00201 const char * aurl = *(const char **)a; 00202 const char * burl = *(const char **)b; 00203 const char * afn = NULL; 00204 const char * bfn = NULL; 00205 00206 (void) urlPath(aurl, &afn); 00207 (void) urlPath(burl, &bfn); 00208 00209 #ifdef VERY_OLD_BUGGY_RPM_PACKAGES 00210 /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */ 00211 if (strchr(afn, '/') == NULL) 00212 bfn = strrchr(bfn, '/') + 1; 00213 #endif 00214 00215 /* Match rpm-4.0 payloads with ./ prefixes. */ 00216 if (afn[0] == '.' && afn[1] == '/') afn += 2; 00217 if (bfn[0] == '.' && bfn[1] == '/') bfn += 2; 00218 00219 /* If either path is absolute, make it relative to '/'. */ 00220 if (afn[0] == '/') afn += 1; 00221 if (bfn[0] == '/') bfn += 1; 00222 00223 return strcmp(afn, bfn); 00224 } 00225 00232 static int mapFind(/*@null@*/ FSMI_t iter, const char * fsmPath) 00233 /*@modifies iter @*/ 00234 { 00235 int ix = -1; 00236 00237 if (iter) { 00238 /*@-onlytrans@*/ 00239 const rpmfi fi = iter->fi; 00240 /*@=onlytrans@*/ 00241 size_t fc = rpmfiFC(fi); 00242 if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) { 00243 const char ** p = NULL; 00244 00245 if (fi->apath != NULL) 00246 p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath), 00247 cpioStrCmp); 00248 if (p) { 00249 iter->i = p - fi->apath; 00250 ix = mapNextIterator(iter); 00251 } 00252 } 00253 } 00254 return ix; 00255 } 00256 00260 typedef struct dnli_s { 00261 rpmfi fi; 00262 /*@only@*/ /*@null@*/ 00263 char * active; 00264 int reverse; 00265 int isave; 00266 int i; 00267 } * DNLI_t; 00268 00274 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a) 00275 /*@modifies a @*/ 00276 { 00277 if (a) { 00278 DNLI_t dnli = (void *)a; 00279 if (dnli->active) free(dnli->active); 00280 } 00281 return _free(a); 00282 } 00283 00286 static inline int dnlCount(/*@null@*/ const DNLI_t dnli) 00287 /*@*/ 00288 { 00289 return (int) (dnli ? dnli->fi->dc : 0); 00290 } 00291 00294 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli) 00295 /*@*/ 00296 { 00297 return (dnli ? dnli->isave : -1); 00298 } 00299 00306 /*@-usereleased@*/ 00307 static /*@only@*/ /*@null@*/ 00308 void * dnlInitIterator(/*@special@*/ const IOSM_t fsm, 00309 int reverse) 00310 /*@uses fsm->iter @*/ 00311 /*@*/ 00312 { 00313 rpmfi fi = fsmGetFi(fsm); 00314 const char * dnl; 00315 DNLI_t dnli; 00316 int i, j; 00317 00318 if (fi == NULL) 00319 return NULL; 00320 dnli = xcalloc(1, sizeof(*dnli)); 00321 dnli->fi = fi; 00322 dnli->reverse = reverse; 00323 dnli->i = (int) (reverse ? fi->dc : 0); 00324 00325 if (fi->dc) { 00326 dnli->active = xcalloc(fi->dc, sizeof(*dnli->active)); 00327 00328 /* Identify parent directories not skipped. */ 00329 if ((fi = rpmfiInit(fi, 0)) != NULL) 00330 while ((i = rpmfiNext(fi)) >= 0) { 00331 if (!iosmFileActionSkipped(fi->actions[i])) dnli->active[fi->dil[i]] = 1; 00332 } 00333 00334 /* Exclude parent directories that are explicitly included. */ 00335 if ((fi = rpmfiInit(fi, 0)) != NULL) 00336 while ((i = rpmfiNext(fi)) >= 0) { 00337 rpmuint32_t dil; 00338 size_t dnlen, bnlen; 00339 00340 if (!S_ISDIR(fi->fmodes[i])) 00341 continue; 00342 00343 dil = fi->dil[i]; 00344 dnlen = strlen(fi->dnl[dil]); 00345 bnlen = strlen(fi->bnl[i]); 00346 00347 for (j = 0; j < (int)fi->dc; j++) { 00348 size_t jlen; 00349 00350 if (!dnli->active[j] || j == (int)dil) 00351 /*@innercontinue@*/ continue; 00352 (void) urlPath(fi->dnl[j], &dnl); 00353 jlen = strlen(dnl); 00354 if (jlen != (dnlen+bnlen+1)) 00355 /*@innercontinue@*/ continue; 00356 if (strncmp(dnl, fi->dnl[dil], dnlen)) 00357 /*@innercontinue@*/ continue; 00358 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) 00359 /*@innercontinue@*/ continue; 00360 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') 00361 /*@innercontinue@*/ continue; 00362 /* This directory is included in the package. */ 00363 dnli->active[j] = 0; 00364 /*@innerbreak@*/ break; 00365 } 00366 } 00367 00368 /* Print only once per package. */ 00369 if (!reverse) { 00370 j = 0; 00371 for (i = 0; i < (int)fi->dc; i++) { 00372 if (!dnli->active[i]) continue; 00373 if (j == 0) { 00374 j = 1; 00375 rpmlog(RPMLOG_DEBUG, 00376 D_("========== Directories not explicitly included in package:\n")); 00377 } 00378 (void) urlPath(fi->dnl[i], &dnl); 00379 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl); 00380 } 00381 if (j) 00382 rpmlog(RPMLOG_DEBUG, "==========\n"); 00383 } 00384 } 00385 return dnli; 00386 } 00387 /*@=usereleased@*/ 00388 00394 static /*@observer@*/ /*@null@*/ 00395 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli) 00396 /*@modifies dnli @*/ 00397 { 00398 const char * dn = NULL; 00399 00400 if (dnli) { 00401 rpmfi fi = dnli->fi; 00402 int i = -1; 00403 00404 if (dnli->active) 00405 do { 00406 i = (!dnli->reverse ? dnli->i++ : --dnli->i); 00407 } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]); 00408 00409 if (i >= 0 && i < (int)fi->dc) 00410 dn = fi->dnl[i]; 00411 else 00412 i = -1; 00413 dnli->isave = i; 00414 } 00415 return dn; 00416 } 00417 00418 #if defined(WITH_PTHREADS) 00419 static void * fsmThread(void * arg) 00420 /*@globals h_errno, fileSystem, internalState @*/ 00421 /*@modifies arg, fileSystem, internalState @*/ 00422 { 00423 IOSM_t fsm = arg; 00424 /*@-unqualifiedtrans@*/ 00425 return ((void *) ((long)fsmStage(fsm, fsm->nstage))); 00426 /*@=unqualifiedtrans@*/ 00427 } 00428 #endif 00429 00430 int fsmNext(IOSM_t fsm, iosmFileStage nstage) 00431 /*@globals h_errno, fileSystem, internalState @*/ 00432 /*@modifies fsm, fileSystem, internalState @*/ 00433 { 00434 fsm->nstage = nstage; 00435 #if defined(WITH_PTHREADS) 00436 if (fsm->multithreaded) 00437 return rpmsqJoin( rpmsqThread(fsmThread, fsm) ); 00438 #endif 00439 return fsmStage(fsm, fsm->nstage); 00440 } 00441 00447 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t fsm) 00448 /*@uses fsm->links, fsm->ix, fsm->sb, fsm->goal, fsm->nsuffix @*/ 00449 /*@defines fsm->li @*/ 00450 /*@releases fsm->path @*/ 00451 /*@globals h_errno, fileSystem, internalState @*/ 00452 /*@modifies fsm, fileSystem, internalState @*/ 00453 { 00454 struct stat * st = &fsm->sb; 00455 int rc = 0; 00456 int ix = -1; 00457 int j; 00458 00459 /* Find hard link set. */ 00460 for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) { 00461 if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev) 00462 break; 00463 } 00464 00465 /* New hard link encountered, add new link to set. */ 00466 if (fsm->li == NULL) { 00467 fsm->li = xcalloc(1, sizeof(*fsm->li)); 00468 fsm->li->next = NULL; 00469 fsm->li->sb = *st; /* structure assignment */ 00470 fsm->li->nlink = (int) st->st_nlink; 00471 fsm->li->linkIndex = fsm->ix; 00472 fsm->li->createdPath = -1; 00473 00474 fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0])); 00475 memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0]))); 00476 fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix)); 00477 00478 if (fsm->goal == IOSM_PKGBUILD) 00479 fsm->li->linksLeft = (int) st->st_nlink; 00480 if (fsm->goal == IOSM_PKGINSTALL) 00481 fsm->li->linksLeft = 0; 00482 00483 /*@-kepttrans@*/ 00484 fsm->li->next = fsm->links; 00485 /*@=kepttrans@*/ 00486 fsm->links = fsm->li; 00487 } 00488 00489 if (fsm->goal == IOSM_PKGBUILD) --fsm->li->linksLeft; 00490 fsm->li->filex[fsm->li->linksLeft] = fsm->ix; 00491 /*@-observertrans -dependenttrans@*/ 00492 fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix; 00493 /*@=observertrans =dependenttrans@*/ 00494 if (fsm->goal == IOSM_PKGINSTALL) fsm->li->linksLeft++; 00495 00496 if (fsm->goal == IOSM_PKGBUILD) 00497 return (fsm->li->linksLeft > 0); 00498 00499 if (fsm->goal != IOSM_PKGINSTALL) 00500 return 0; 00501 00502 if (!(st->st_size || fsm->li->linksLeft == (int) st->st_nlink)) 00503 return 1; 00504 00505 /* Here come the bits, time to choose a non-skipped file name. */ 00506 { rpmfi fi = fsmGetFi(fsm); 00507 00508 for (j = fsm->li->linksLeft - 1; j >= 0; j--) { 00509 ix = fsm->li->filex[j]; 00510 if (ix < 0 || iosmFileActionSkipped(fi->actions[ix])) 00511 continue; 00512 break; 00513 } 00514 } 00515 00516 /* Are all links skipped or not encountered yet? */ 00517 if (ix < 0 || j < 0) 00518 return 1; /* XXX W2DO? */ 00519 00520 /* Save the non-skipped file name and map index. */ 00521 fsm->li->linkIndex = j; 00522 fsm->path = _free(fsm->path); 00523 fsm->ix = ix; 00524 rc = fsmNext(fsm, IOSM_MAP); 00525 return rc; 00526 } 00527 00533 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li) 00534 /*@modifies li @*/ 00535 { 00536 if (li) { 00537 li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */ 00538 li->filex = _free(li->filex); 00539 } 00540 return _free(li); 00541 } 00542 00543 IOSM_t newFSM(void) 00544 { 00545 IOSM_t fsm = xcalloc(1, sizeof(*fsm)); 00546 return fsm; 00547 } 00548 00549 IOSM_t freeFSM(IOSM_t fsm) 00550 { 00551 if (fsm) { 00552 fsm->path = _free(fsm->path); 00553 while ((fsm->li = fsm->links) != NULL) { 00554 fsm->links = fsm->li->next; 00555 fsm->li->next = NULL; 00556 fsm->li = freeHardLink(fsm->li); 00557 } 00558 fsm->dnlx = _free(fsm->dnlx); 00559 fsm->ldn = _free(fsm->ldn); 00560 fsm->iter = mapFreeIterator(fsm->iter); 00561 } 00562 return _free(fsm); 00563 } 00564 00565 #if defined(SUPPORT_AR_PAYLOADS) 00566 static int arSetup(IOSM_t fsm, rpmfi fi) 00567 /*@modifies fsm @*/ 00568 { 00569 const char * path; 00570 char * t; 00571 size_t lmtablen = 0; 00572 size_t nb; 00573 00574 /* Calculate size of ar(1) long member table. */ 00575 if ((fi = rpmfiInit(fi, 0)) != NULL) 00576 while (rpmfiNext(fi) >= 0) { 00577 #ifdef NOTYET 00578 if (fi->apath) { 00579 const char * apath = NULL; 00580 (void) urlPath(fi->apath[ix], &apath); 00581 path = apath + fi->striplen; 00582 } else 00583 #endif 00584 path = rpmfiBN(fi); 00585 if ((nb = strlen(path)) < 15) 00586 continue; 00587 lmtablen += nb + 1; /* trailing \n */ 00588 } 00589 00590 /* Anything to do? */ 00591 if (lmtablen == 0) 00592 return 0; 00593 00594 /* Create and load ar(1) long member table. */ 00595 fsm->lmtab = t = xmalloc(lmtablen + 1); /* trailing \0 */ 00596 fsm->lmtablen = lmtablen; 00597 fsm->lmtaboff = 0; 00598 if ((fi = rpmfiInit(fi, 0)) != NULL) 00599 while (rpmfiNext(fi) >= 0) { 00600 #ifdef NOTYET 00601 if (fi->apath) { 00602 const char * apath = NULL; 00603 (void) urlPath(fi->apath[ix], &apath); 00604 path = apath + fi->striplen; 00605 } else 00606 #endif 00607 path = rpmfiBN(fi); 00608 if ((nb = strlen(path)) < 15) 00609 continue; 00610 t = stpcpy(t, path); 00611 *t++ = '\n'; 00612 } 00613 *t = '\0'; 00614 00615 return 0; 00616 } 00617 #endif 00618 00619 int fsmSetup(void * _fsm, iosmFileStage goal, const char * afmt, 00620 const void * _ts, const void * _fi, FD_t cfd, 00621 unsigned int * archiveSize, const char ** failedFile) 00622 { 00623 IOSM_t fsm = _fsm; 00624 /*@-castexpose@*/ 00625 const rpmts ts = (const rpmts) _ts; 00626 const rpmfi fi = (const rpmfi) _fi; 00627 /*@=castexpose@*/ 00628 #if defined(_USE_RPMTE) 00629 int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT); 00630 int adding = (rpmteType(fi->te) == TR_ADDED); 00631 #else 00632 int reverse = 0; /* XXX HACK: devise alternative means */ 00633 int adding = 1; /* XXX HACK: devise alternative means */ 00634 #endif 00635 size_t pos = 0; 00636 int rc, ec = 0; 00637 00638 fsm->debug = _fsm_debug; 00639 fsm->multithreaded = _fsm_threads; 00640 fsm->adding = adding; 00641 00642 /*@+voidabstract -nullpass@*/ 00643 if (fsm->debug < 0) 00644 fprintf(stderr, "--> fsmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", fsm, goal, afmt, (void *)ts, fi, cfd, archiveSize, failedFile); 00645 /*@=voidabstract =nullpass@*/ 00646 00647 _iosmNext = &fsmNext; 00648 if (fsm->headerRead == NULL) { 00649 if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) { 00650 if (fsm->debug < 0) 00651 fprintf(stderr, "\ttar vectors set\n"); 00652 fsm->headerRead = &tarHeaderRead; 00653 fsm->headerWrite = &tarHeaderWrite; 00654 fsm->trailerWrite = &tarTrailerWrite; 00655 fsm->blksize = TAR_BLOCK_SIZE; 00656 } else 00657 #if defined(SUPPORT_AR_PAYLOADS) 00658 if (afmt != NULL && !strcmp(afmt, "ar")) { 00659 if (fsm->debug < 0) 00660 fprintf(stderr, "\tar vectors set\n"); 00661 fsm->headerRead = &arHeaderRead; 00662 fsm->headerWrite = &arHeaderWrite; 00663 fsm->trailerWrite = &arTrailerWrite; 00664 fsm->blksize = 2; 00665 if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE) 00666 (void) arSetup(fsm, fi); 00667 } else 00668 #endif 00669 { 00670 if (fsm->debug < 0) 00671 fprintf(stderr, "\tcpio vectors set\n"); 00672 fsm->headerRead = &cpioHeaderRead; 00673 fsm->headerWrite = &cpioHeaderWrite; 00674 fsm->trailerWrite = &cpioTrailerWrite; 00675 fsm->blksize = 4; 00676 } 00677 } 00678 00679 fsm->goal = goal; 00680 if (cfd != NULL) { 00681 /*@-assignexpose -castexpose @*/ 00682 fsm->cfd = fdLink(cfd, "persist (fsm)"); 00683 /*@=assignexpose =castexpose @*/ 00684 pos = fdGetCpioPos(fsm->cfd); 00685 fdSetCpioPos(fsm->cfd, 0); 00686 } 00687 /*@-mods@*/ /* LCL: avoid void * _ts/_fi annotations for now. */ 00688 fsm->iter = mapInitIterator(fi, reverse); 00689 /*@-assignexpose -castexpose @*/ 00690 fsm->iter->ts = rpmtsLink(ts, "mapIterator"); 00691 /*@=assignexpose =castexpose @*/ 00692 fsm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS); 00693 /*@=mods@*/ 00694 fsm->nofdigests = 00695 (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS)) 00696 ? 0 : 1; 00697 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT) 00698 fsm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) && 00699 fsm->goal != IOSM_PKGCOMMIT) ? 0 : 1); 00700 #undef _tsmask 00701 00702 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 00703 void * ptr; 00704 fi->archivePos = 0; 00705 ptr = rpmtsNotify(ts, fi->te, 00706 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize); 00707 } 00708 00709 /*@-assignexpose@*/ 00710 fsm->archiveSize = archiveSize; 00711 if (fsm->archiveSize) 00712 *fsm->archiveSize = 0; 00713 fsm->failedFile = failedFile; 00714 if (fsm->failedFile) 00715 *fsm->failedFile = NULL; 00716 /*@=assignexpose@*/ 00717 00718 memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf)); 00719 if (fsm->goal == IOSM_PKGINSTALL) { 00720 if (ts && rpmtsGetTid(ts) != (rpmuint32_t)-1) 00721 sprintf(fsm->sufbuf, ";%08x", (unsigned)rpmtsGetTid(ts)); 00722 } 00723 00724 ec = fsm->rc = 0; 00725 /*@-mods@*/ /* LCL: avoid void * _fsm annotation for now. */ 00726 rc = fsmUNSAFE(fsm, IOSM_CREATE); 00727 /*@=mods@*/ 00728 if (rc && !ec) ec = rc; 00729 00730 /*@-mods@*/ /* LCL: avoid void * _fsm annotation for now. */ 00731 rc = fsmUNSAFE(fsm, fsm->goal); 00732 /*@=mods@*/ 00733 if (rc && !ec) ec = rc; 00734 00735 if (fsm->archiveSize && ec == 0) 00736 *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos); 00737 00738 /*@-nullstate@*/ /* FIX: *fsm->failedFile may be NULL */ 00739 return ec; 00740 /*@=nullstate@*/ 00741 } 00742 00743 int fsmTeardown(void * _fsm) 00744 { 00745 IOSM_t fsm = _fsm; 00746 int rc = fsm->rc; 00747 00748 if (fsm->debug < 0) 00749 fprintf(stderr, "--> fsmTeardown(%p)\n", fsm); 00750 if (!rc) 00751 rc = fsmUNSAFE(fsm, IOSM_DESTROY); 00752 00753 (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST), 00754 &fsm->op_digest); 00755 00756 fsm->lmtab = _free(fsm->lmtab); 00757 (void)rpmtsFree(fsm->iter->ts); 00758 fsm->iter->ts = NULL; 00759 fsm->iter = mapFreeIterator(fsm->iter); 00760 if (fsm->cfd != NULL) { 00761 /*@-refcounttrans@*/ /* FIX: XfdFree annotation */ 00762 fsm->cfd = fdFree(fsm->cfd, "persist (fsm)"); 00763 /*@=refcounttrans@*/ 00764 fsm->cfd = NULL; 00765 } 00766 fsm->failedFile = NULL; 00767 return rc; 00768 } 00769 00770 /* 00771 * Set file security context (if not disabled). 00772 * @param fsm file state machine data 00773 * @return 0 always 00774 */ 00775 static int fsmMapFContext(IOSM_t fsm) 00776 /*@modifies fsm @*/ 00777 { 00778 fsm->fcontext = NULL; 00779 if (!fsm->nofcontexts) { 00780 fsm->fcontext = rpmsxMatch(NULL, fsm->path, fsm->sb.st_mode); 00781 #ifdef DYING /* XXX SELinux file contexts not set from package content. */ 00782 { rpmfi fi = fsmGetFi(fsm); 00783 int i = fsm->ix; 00784 00785 /* Get file security context from package. */ 00786 if (fi && i >= 0 && i < (int)fi->fc) 00787 fsm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL); 00788 } 00789 #endif 00790 } 00791 return 0; 00792 } 00793 00794 int fsmMapPath(IOSM_t fsm) 00795 { 00796 rpmfi fi = fsmGetFi(fsm); /* XXX const except for fstates */ 00797 int teAdding = fsm->adding; 00798 int rc = 0; 00799 int i = fsm->ix; 00800 00801 fsm->osuffix = NULL; 00802 fsm->nsuffix = NULL; 00803 fsm->astriplen = 0; 00804 fsm->action = FA_UNKNOWN; 00805 fsm->mapFlags = fi->mapflags; 00806 00807 if (fi && i >= 0 && i < (int)fi->fc) { 00808 00809 fsm->astriplen = fi->astriplen; 00810 fsm->action = (fi->actions ? fi->actions[i] : fi->action); 00811 fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags); 00812 fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags); 00813 00814 /* src rpms have simple base name in payload. */ 00815 fsm->dirName = fi->dnl[fi->dil[i]]; 00816 fsm->baseName = fi->bnl[i]; 00817 00818 switch (fsm->action) { 00819 case FA_SKIP: 00820 break; 00821 case FA_UNKNOWN: 00822 break; 00823 00824 case FA_COPYOUT: 00825 break; 00826 case FA_COPYIN: 00827 case FA_CREATE: 00828 assert(teAdding); 00829 break; 00830 00831 case FA_SKIPNSTATE: 00832 if (fi->fstates && teAdding) 00833 fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED; 00834 break; 00835 00836 case FA_SKIPNETSHARED: 00837 if (fi->fstates && teAdding) 00838 fi->fstates[i] = RPMFILE_STATE_NETSHARED; 00839 break; 00840 00841 case FA_SKIPCOLOR: 00842 if (fi->fstates && teAdding) 00843 fi->fstates[i] = RPMFILE_STATE_WRONGCOLOR; 00844 break; 00845 00846 case FA_BACKUP: 00847 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00848 fsm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE); 00849 break; 00850 00851 case FA_ALTNAME: 00852 assert(teAdding); 00853 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00854 fsm->nsuffix = SUFFIX_RPMNEW; 00855 break; 00856 00857 case FA_SAVE: 00858 assert(teAdding); 00859 if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */ 00860 fsm->osuffix = SUFFIX_RPMSAVE; 00861 break; 00862 case FA_ERASE: 00863 #if 0 /* XXX is this a genhdlist fix? */ 00864 assert(rpmteType(fi->te) == TR_REMOVED); 00865 #endif 00866 /* 00867 * XXX TODO: %ghost probably shouldn't be removed, but that changes 00868 * legacy rpm behavior. 00869 */ 00870 break; 00871 default: 00872 break; 00873 } 00874 00875 if ((fsm->mapFlags & IOSM_MAP_PATH) || fsm->nsuffix) { 00876 const struct stat * st = &fsm->sb; 00877 fsm->path = _free(fsm->path); 00878 fsm->path = fsmFsPath(fsm, st, fsm->subdir, 00879 (fsm->suffix ? fsm->suffix : fsm->nsuffix)); 00880 } 00881 } 00882 return rc; 00883 } 00884 00885 int fsmMapAttrs(IOSM_t fsm) 00886 { 00887 struct stat * st = &fsm->sb; 00888 rpmfi fi = fsmGetFi(fsm); 00889 int i = fsm->ix; 00890 00891 if (fi && i >= 0 && i < (int) fi->fc) { 00892 mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms); 00893 mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms); 00894 dev_t finalRdev = (dev_t)(fi->frdevs ? fi->frdevs[i] : 0); 00895 rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0); 00896 uid_t uid = fi->uid; 00897 gid_t gid = fi->gid; 00898 00899 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00900 /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during 00901 installation of _source_ RPMs. Instead, let it use the current 00902 run-time owner/group, because most of the time the owner/group in 00903 the source RPM (which is the owner/group of the files as staying on 00904 the package author system) is not existing on the target system, of 00905 course. */ 00906 #endif 00907 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) { 00908 #if defined(RPM_VENDOR_OPENPKG) ||defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00909 if (!fi->isSource) { 00910 #endif 00911 if (fsm->goal == IOSM_PKGINSTALL) 00912 rpmlog(RPMLOG_WARNING, 00913 _("user %s does not exist - using root\n"), fi->fuser[i]); 00914 uid = 0; 00915 finalMode &= ~S_ISUID; /* turn off suid bit */ 00916 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00917 } 00918 #endif 00919 } 00920 00921 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) { 00922 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00923 if (!fi->isSource) { 00924 #endif 00925 if (fsm->goal == IOSM_PKGINSTALL) 00926 rpmlog(RPMLOG_WARNING, 00927 _("group %s does not exist - using root\n"), fi->fgroup[i]); 00928 gid = 0; 00929 finalMode &= ~S_ISGID; /* turn off sgid bit */ 00930 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */ 00931 } 00932 #endif 00933 } 00934 00935 if (fsm->mapFlags & IOSM_MAP_MODE) 00936 st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT); 00937 if (fsm->mapFlags & IOSM_MAP_TYPE) { 00938 st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT); 00939 if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) 00940 && st->st_nlink == 0) 00941 st->st_nlink = 1; 00942 st->st_rdev = finalRdev; 00943 st->st_mtime = finalMtime; 00944 } 00945 if (fsm->mapFlags & IOSM_MAP_UID) 00946 st->st_uid = uid; 00947 if (fsm->mapFlags & IOSM_MAP_GID) 00948 st->st_gid = gid; 00949 00950 /* 00951 * Set file digest (if not disabled). 00952 */ 00953 if (!fsm->nofdigests) { 00954 fsm->fdigestalgo = fi->digestalgo; 00955 fsm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL); 00956 fsm->digestlen = fi->digestlen; 00957 fsm->digest = (fi->digests ? (fi->digests + (fsm->digestlen * i)) : NULL); 00958 } else { 00959 fsm->fdigestalgo = 0; 00960 fsm->fdigest = NULL; 00961 fsm->digestlen = 0; 00962 fsm->digest = NULL; 00963 } 00964 } 00965 return 0; 00966 } 00967 00973 /*@-compdef@*/ 00974 static int extractRegular(/*@special@*/ IOSM_t fsm) 00975 /*@uses fsm->fdigest, fsm->digest, fsm->sb, fsm->wfd @*/ 00976 /*@globals h_errno, fileSystem, internalState @*/ 00977 /*@modifies fsm, fileSystem, internalState @*/ 00978 { 00979 const struct stat * st = &fsm->sb; 00980 size_t left = (size_t) st->st_size; 00981 int rc = 0; 00982 int xx; 00983 00984 { const char * fn = fsm->path; 00985 mode_t mode = st->st_mode; 00986 uint8_t * b = (uint8_t *)""; 00987 size_t blen = 1; 00988 const uint8_t * d = fsm->digest; 00989 size_t dlen = fsm->digestlen; 00990 uint32_t dalgo = fsm->fdigestalgo; 00991 00992 xx = rpmlioCreat(rpmtsGetRdb(fsmGetTs(fsm)), fn, mode, b, blen, d, dlen, dalgo); 00993 } 00994 00995 rc = fsmNext(fsm, IOSM_WOPEN); 00996 if (rc) 00997 goto exit; 00998 00999 if (st->st_size > 0 && (fsm->fdigest != NULL || fsm->digest != NULL)) 01000 fdInitDigest(fsm->wfd, fsm->fdigestalgo, 0); 01001 01002 while (left) { 01003 01004 fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left); 01005 rc = fsmNext(fsm, IOSM_DREAD); 01006 if (rc) 01007 goto exit; 01008 01009 rc = fsmNext(fsm, IOSM_WRITE); 01010 if (rc) 01011 goto exit; 01012 01013 left -= fsm->wrnb; 01014 01015 /* Notify iff progress, completion is done elsewhere */ 01016 if (!rc && left) 01017 (void) fsmNext(fsm, IOSM_NOTIFY); 01018 } 01019 01020 xx = fsync(Fileno(fsm->wfd)); 01021 01022 if (st->st_size > 0 && (fsm->fdigest || fsm->digest)) { 01023 void * digest = NULL; 01024 int asAscii = (fsm->digest == NULL ? 1 : 0); 01025 01026 (void) Fflush(fsm->wfd); 01027 fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii); 01028 01029 if (digest == NULL) { 01030 rc = IOSMERR_DIGEST_MISMATCH; 01031 goto exit; 01032 } 01033 01034 if (fsm->digest != NULL) { 01035 if (memcmp(digest, fsm->digest, fsm->digestlen)) 01036 rc = IOSMERR_DIGEST_MISMATCH; 01037 } else { 01038 if (strcmp(digest, fsm->fdigest)) 01039 rc = IOSMERR_DIGEST_MISMATCH; 01040 } 01041 digest = _free(digest); 01042 } 01043 01044 exit: 01045 (void) fsmNext(fsm, IOSM_WCLOSE); 01046 01047 return rc; 01048 } 01049 /*@=compdef@*/ 01050 01057 /*@-compdef -compmempass@*/ 01058 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t fsm, int writeData) 01059 /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/ 01060 /*@globals h_errno, fileSystem, internalState @*/ 01061 /*@modifies fsm, fileSystem, internalState @*/ 01062 { 01063 const char * path = fsm->path; 01064 const char * opath = fsm->opath; 01065 struct stat * st = &fsm->sb; 01066 struct stat * ost = &fsm->osb; 01067 size_t left; 01068 int xx; 01069 int rc; 01070 01071 st->st_size = (writeData ? ost->st_size : 0); 01072 01073 if (S_ISDIR(st->st_mode)) { 01074 st->st_size = 0; 01075 } else if (S_ISLNK(st->st_mode)) { 01076 /* 01077 * While linux puts the size of a symlink in the st_size field, 01078 * I don't think that's a specified standard. 01079 */ 01080 /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */ 01081 rc = fsmUNSAFE(fsm, IOSM_READLINK); 01082 if (rc) goto exit; 01083 st->st_size = fsm->rdnb; 01084 fsm->lpath = xstrdup(fsm->rdbuf); /* XXX save readlink return. */ 01085 } 01086 01087 if (fsm->mapFlags & IOSM_MAP_ABSOLUTE) { 01088 size_t nb= strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof("."); 01089 char * t = alloca(nb); 01090 *t = '\0'; 01091 fsm->path = t; 01092 if (fsm->mapFlags & IOSM_MAP_ADDDOT) 01093 *t++ = '.'; 01094 t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName); 01095 } else if (fsm->mapFlags & IOSM_MAP_PATH) { 01096 rpmfi fi = fsmGetFi(fsm); 01097 if (fi->apath) { 01098 const char * apath = NULL; 01099 (void) urlPath(fi->apath[fsm->ix], &apath); 01100 fsm->path = apath + fi->striplen; 01101 } else 01102 fsm->path = fi->bnl[fsm->ix]; 01103 } 01104 01105 rc = fsmNext(fsm, IOSM_HWRITE); 01106 fsm->path = path; 01107 if (rc) goto exit; 01108 01109 if (writeData && S_ISREG(st->st_mode)) { 01110 #if defined(HAVE_MMAP) 01111 char * rdbuf = NULL; 01112 void * mapped = (void *)-1; 01113 size_t nmapped = 0; 01114 /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */ 01115 int use_mmap = (st->st_size <= 0x07ffffff); 01116 #endif 01117 01118 rc = fsmNext(fsm, IOSM_ROPEN); 01119 if (rc) goto exit; 01120 01121 /* XXX unbuffered mmap generates *lots* of fdio debugging */ 01122 #if defined(HAVE_MMAP) 01123 if (use_mmap) { 01124 mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0); 01125 if (mapped != (void *)-1) { 01126 rdbuf = fsm->rdbuf; 01127 fsm->rdbuf = (char *) mapped; 01128 fsm->rdlen = nmapped = st->st_size; 01129 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) 01130 xx = madvise(mapped, nmapped, MADV_DONTNEED); 01131 #endif 01132 } 01133 } 01134 #endif 01135 01136 left = st->st_size; 01137 01138 while (left) { 01139 #if defined(HAVE_MMAP) 01140 if (mapped != (void *)-1) { 01141 fsm->rdnb = nmapped; 01142 } else 01143 #endif 01144 { 01145 fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left), 01146 rc = fsmNext(fsm, IOSM_READ); 01147 if (rc) goto exit; 01148 } 01149 01150 /* XXX DWRITE uses rdnb for I/O length. */ 01151 rc = fsmNext(fsm, IOSM_DWRITE); 01152 if (rc) goto exit; 01153 01154 left -= fsm->wrnb; 01155 } 01156 01157 #if defined(HAVE_MMAP) 01158 if (mapped != (void *)-1) { 01159 /* XXX splint misses size_t 2nd arg. */ 01160 /*@i@*/ xx = msync(mapped, nmapped, MS_ASYNC); 01161 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) 01162 xx = madvise(mapped, nmapped, MADV_DONTNEED); 01163 #endif 01164 xx = munmap(mapped, nmapped); 01165 fsm->rdbuf = rdbuf; 01166 } else 01167 #endif 01168 xx = fsync(Fileno(fsm->rfd)); 01169 01170 } 01171 01172 rc = fsmNext(fsm, IOSM_PAD); 01173 if (rc) goto exit; 01174 01175 rc = 0; 01176 01177 exit: 01178 if (fsm->rfd != NULL) 01179 (void) fsmNext(fsm, IOSM_RCLOSE); 01180 /*@-dependenttrans@*/ 01181 fsm->opath = opath; 01182 fsm->path = path; 01183 /*@=dependenttrans@*/ 01184 return rc; 01185 } 01186 /*@=compdef =compmempass@*/ 01187 01193 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01194 /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/ 01195 /*@globals h_errno, fileSystem, internalState @*/ 01196 /*@modifies fsm, fileSystem, internalState @*/ 01197 { 01198 const char * path = fsm->path; 01199 const char * lpath = fsm->lpath; 01200 const char * nsuffix = fsm->nsuffix; 01201 int iterIndex = fsm->ix; 01202 int ec = 0; 01203 int rc; 01204 int i; 01205 const char * linkpath = NULL; 01206 int firstfile = 1; 01207 01208 fsm->path = NULL; 01209 fsm->lpath = NULL; 01210 fsm->nsuffix = NULL; 01211 fsm->ix = -1; 01212 01213 for (i = fsm->li->nlink - 1; i >= 0; i--) { 01214 01215 if (fsm->li->filex[i] < 0) continue; 01216 01217 fsm->ix = fsm->li->filex[i]; 01218 /*@-compdef@*/ 01219 rc = fsmNext(fsm, IOSM_MAP); 01220 /*@=compdef@*/ 01221 01222 /* XXX tar and cpio have to do things differently. */ 01223 if (fsm->headerWrite == tarHeaderWrite) { 01224 if (firstfile) { 01225 const char * apath = NULL; 01226 char *t; 01227 (void) urlPath(fsm->path, &apath); 01228 /* Remove the buildroot prefix. */ 01229 t = xmalloc(sizeof(".") + strlen(apath + fsm->astriplen)); 01230 (void) stpcpy( stpcpy(t, "."), apath + fsm->astriplen); 01231 linkpath = t; 01232 firstfile = 0; 01233 } else 01234 fsm->lpath = linkpath; 01235 01236 /* Write data after first link for tar. */ 01237 rc = writeFile(fsm, (fsm->lpath == NULL)); 01238 } else { 01239 /* Write data after last link for cpio. */ 01240 rc = writeFile(fsm, (i == 0)); 01241 } 01242 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { 01243 ec = rc; 01244 *fsm->failedFile = xstrdup(fsm->path); 01245 } 01246 01247 fsm->path = _free(fsm->path); 01248 fsm->li->filex[i] = -1; 01249 } 01250 01251 /*@-dependenttrans@*/ 01252 linkpath = _free(linkpath); 01253 /*@=dependenttrans@*/ 01254 fsm->ix = iterIndex; 01255 fsm->nsuffix = nsuffix; 01256 fsm->lpath = lpath; 01257 fsm->path = path; 01258 return ec; 01259 } 01260 01266 /*@-compdef@*/ 01267 static int fsmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01268 /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/ 01269 /*@globals h_errno, fileSystem, internalState @*/ 01270 /*@modifies fsm, fileSystem, internalState @*/ 01271 { 01272 const char * path = fsm->path; 01273 const char * opath = fsm->opath; 01274 const char * nsuffix = fsm->nsuffix; 01275 int iterIndex = fsm->ix; 01276 int ec = 0; 01277 int rc; 01278 int i; 01279 01280 fsm->path = NULL; 01281 fsm->opath = NULL; 01282 fsm->nsuffix = NULL; 01283 fsm->ix = -1; 01284 01285 fsm->ix = fsm->li->filex[fsm->li->createdPath]; 01286 rc = fsmNext(fsm, IOSM_MAP); 01287 fsm->opath = fsm->path; 01288 fsm->path = NULL; 01289 for (i = 0; i < fsm->li->nlink; i++) { 01290 if (fsm->li->filex[i] < 0) continue; 01291 if (fsm->li->createdPath == i) continue; 01292 01293 fsm->ix = fsm->li->filex[i]; 01294 fsm->path = _free(fsm->path); 01295 rc = fsmNext(fsm, IOSM_MAP); 01296 if (iosmFileActionSkipped(fsm->action)) continue; 01297 01298 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01299 if (!rc) continue; 01300 if (!(rc == IOSMERR_ENOENT)) break; 01301 01302 /* XXX link(fsm->opath, fsm->path) */ 01303 rc = fsmNext(fsm, IOSM_LINK); 01304 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { 01305 ec = rc; 01306 *fsm->failedFile = xstrdup(fsm->path); 01307 } 01308 01309 fsm->li->linksLeft--; 01310 } 01311 fsm->path = _free(fsm->path); 01312 fsm->opath = _free(fsm->opath); 01313 01314 fsm->ix = iterIndex; 01315 fsm->nsuffix = nsuffix; 01316 fsm->path = path; 01317 fsm->opath = opath; 01318 return ec; 01319 } 01320 /*@=compdef@*/ 01321 01327 /*@-compdef@*/ 01328 static int fsmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01329 /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb, 01330 fsm->li, fsm->links @*/ 01331 /*@globals h_errno, fileSystem, internalState @*/ 01332 /*@modifies fsm, fileSystem, internalState @*/ 01333 { 01334 const char * path = fsm->path; 01335 const char * nsuffix = fsm->nsuffix; 01336 int iterIndex = fsm->ix; 01337 struct stat * st = &fsm->sb; 01338 int rc = 0; 01339 int i; 01340 01341 fsm->path = NULL; 01342 fsm->nsuffix = NULL; 01343 fsm->ix = -1; 01344 01345 for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) { 01346 if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev) 01347 break; 01348 } 01349 01350 for (i = 0; i < fsm->li->nlink; i++) { 01351 if (fsm->li->filex[i] < 0) continue; 01352 fsm->ix = fsm->li->filex[i]; 01353 rc = fsmNext(fsm, IOSM_MAP); 01354 if (!iosmFileActionSkipped(fsm->action)) 01355 rc = fsmNext(fsm, IOSM_COMMIT); 01356 fsm->path = _free(fsm->path); 01357 fsm->li->filex[i] = -1; 01358 } 01359 01360 fsm->ix = iterIndex; 01361 fsm->nsuffix = nsuffix; 01362 fsm->path = path; 01363 return rc; 01364 } 01365 /*@=compdef@*/ 01366 01372 static int fsmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01373 /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/ 01374 /*@globals h_errno, fileSystem, internalState @*/ 01375 /*@modifies fsm, fileSystem, internalState @*/ 01376 { 01377 const char * path = fsm->path; 01378 void * dnli = dnlInitIterator(fsm, 1); 01379 char * dn = fsm->rdbuf; 01380 int dc = dnlCount(dnli); 01381 int rc = 0; 01382 01383 fsm->path = NULL; 01384 dn[0] = '\0'; 01385 /*@-observertrans -dependenttrans@*/ 01386 if (fsm->ldn != NULL && fsm->dnlx != NULL) 01387 while ((fsm->path = dnlNextIterator(dnli)) != NULL) { 01388 size_t dnlen = strlen(fsm->path); 01389 char * te; 01390 01391 dc = dnlIndex(dnli); 01392 if (fsm->dnlx[dc] < 1 || (size_t)fsm->dnlx[dc] >= dnlen) 01393 continue; 01394 01395 /* Copy to avoid const on fsm->path. */ 01396 te = stpcpy(dn, fsm->path) - 1; 01397 fsm->path = dn; 01398 01399 /* Remove generated directories. */ 01400 /*@-usereleased@*/ /* LCL: te used after release? */ 01401 do { 01402 if (*te == '/') { 01403 *te = '\0'; 01404 /*@-compdef@*/ 01405 rc = fsmNext(fsm, IOSM_RMDIR); 01406 /*@=compdef@*/ 01407 *te = '/'; 01408 } 01409 if (rc) 01410 /*@innerbreak@*/ break; 01411 te--; 01412 } while ((te - fsm->path) > fsm->dnlx[dc]); 01413 /*@=usereleased@*/ 01414 } 01415 dnli = dnlFreeIterator(dnli); 01416 /*@=observertrans =dependenttrans@*/ 01417 01418 fsm->path = path; 01419 return rc; 01420 } 01421 01427 static int fsmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01428 /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter, 01429 fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/ 01430 /*@defines fsm->dnlx, fsm->ldn @*/ 01431 /*@globals h_errno, fileSystem, internalState @*/ 01432 /*@modifies fsm, fileSystem, internalState @*/ 01433 { 01434 struct stat * st = &fsm->sb; 01435 struct stat * ost = &fsm->osb; 01436 const char * path = fsm->path; 01437 mode_t st_mode = st->st_mode; 01438 void * dnli = dnlInitIterator(fsm, 0); 01439 char * dn = fsm->rdbuf; 01440 int dc = dnlCount(dnli); 01441 int rc = 0; 01442 size_t i; 01443 01444 fsm->path = NULL; 01445 01446 dn[0] = '\0'; 01447 fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL); 01448 /*@-observertrans -dependenttrans@*/ 01449 if (fsm->dnlx != NULL) 01450 while ((fsm->path = dnlNextIterator(dnli)) != NULL) { 01451 size_t dnlen = strlen(fsm->path); 01452 char * te; 01453 01454 dc = dnlIndex(dnli); 01455 if (dc < 0) continue; 01456 fsm->dnlx[dc] = (unsigned short) dnlen; 01457 if (dnlen <= 1) 01458 continue; 01459 01460 /*@-compdef -nullpass@*/ /* FIX: fsm->ldn not defined ??? */ 01461 if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn)) 01462 continue; 01463 /*@=compdef =nullpass@*/ 01464 01465 /* Copy to avoid const on fsm->path. */ 01466 (void) stpcpy(dn, fsm->path); 01467 fsm->path = dn; 01468 01469 /* Assume '/' directory exists, "mkdir -p" for others if non-existent */ 01470 (void) urlPath(dn, (const char **)&te); 01471 for (i = 1, te++; *te != '\0'; te++, i++) { 01472 if (*te != '/') 01473 /*@innercontinue@*/ continue; 01474 01475 *te = '\0'; 01476 01477 /* Already validated? */ 01478 /*@-usedef -compdef -nullpass -nullderef@*/ 01479 if (i < fsm->ldnlen && 01480 (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') && 01481 !strncmp(fsm->path, fsm->ldn, i)) 01482 { 01483 *te = '/'; 01484 /* Move pre-existing path marker forward. */ 01485 fsm->dnlx[dc] = (te - dn); 01486 /*@innercontinue@*/ continue; 01487 } 01488 /*@=usedef =compdef =nullpass =nullderef@*/ 01489 01490 /* Validate next component of path. */ 01491 rc = fsmUNSAFE(fsm, IOSM_LSTAT); 01492 *te = '/'; 01493 01494 /* Directory already exists? */ 01495 if (rc == 0 && S_ISDIR(ost->st_mode)) { 01496 /* Move pre-existing path marker forward. */ 01497 fsm->dnlx[dc] = (te - dn); 01498 } else if (rc == IOSMERR_ENOENT) { 01499 rpmfi fi = fsmGetFi(fsm); 01500 *te = '\0'; 01501 st->st_mode = S_IFDIR | (fi->dperms & 07777); 01502 rc = fsmNext(fsm, IOSM_MKDIR); 01503 if (!rc) { 01504 /* XXX FIXME? only new dir will have context set. */ 01505 /* Get file security context from patterns. */ 01506 if (!fsm->nofcontexts) { 01507 fsm->fcontext = 01508 rpmsxMatch(NULL, fsm->path, st->st_mode); 01509 if (fsm->fcontext != NULL) 01510 rc = fsmNext(fsm, IOSM_LSETFCON); 01511 } else 01512 fsm->fcontext = NULL; 01513 rpmlog(RPMLOG_DEBUG, 01514 D_("%s directory created with perms %04o, context %s.\n"), 01515 fsm->path, (unsigned)(st->st_mode & 07777), 01516 (fsm->fcontext ? fsm->fcontext : "(no context)")); 01517 fsm->fcontext = _free(fsm->fcontext); 01518 } 01519 *te = '/'; 01520 } 01521 if (rc) 01522 /*@innerbreak@*/ break; 01523 } 01524 if (rc) break; 01525 01526 /* Save last validated path. */ 01527 /*@-compdef@*/ /* FIX: ldn/path annotations ? */ 01528 if (fsm->ldnalloc < (dnlen + 1)) { 01529 fsm->ldnalloc = dnlen + 100; 01530 fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc); 01531 } 01532 if (fsm->ldn != NULL) { /* XXX can't happen */ 01533 strcpy(fsm->ldn, fsm->path); 01534 fsm->ldnlen = dnlen; 01535 } 01536 /*@=compdef@*/ 01537 } 01538 dnli = dnlFreeIterator(dnli); 01539 /*@=observertrans =dependenttrans@*/ 01540 01541 fsm->path = path; 01542 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01543 /*@-compdef@*/ /* FIX: ldn/path annotations ? */ 01544 return rc; 01545 /*@=compdef@*/ 01546 } 01547 01548 #ifdef NOTYET 01549 01554 static int fsmStat(/*@special@*/ /*@partial@*/ IOSM_t fsm) 01555 /*@globals fileSystem, internalState @*/ 01556 /*@modifies fsm, fileSystem, internalState @*/ 01557 { 01558 int rc = 0; 01559 01560 if (fsm->path != NULL) { 01561 int saveernno = errno; 01562 rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS) 01563 ? IOSM_LSTAT : IOSM_STAT)); 01564 if (rc == IOSMERR_ENOENT) { 01565 errno = saveerrno; 01566 rc = 0; 01567 fsm->exists = 0; 01568 } else if (rc == 0) { 01569 fsm->exists = 1; 01570 } 01571 } else { 01572 /* Skip %ghost files on build. */ 01573 fsm->exists = 0; 01574 } 01575 return rc; 01576 } 01577 #endif 01578 01579 #define IS_DEV_LOG(_x) \ 01580 ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \ 01581 !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \ 01582 ((_x)[sizeof("/dev/log")-1] == '\0' || \ 01583 (_x)[sizeof("/dev/log")-1] == ';')) 01584 01585 /*@-compmempass@*/ 01586 int fsmStage(IOSM_t fsm, iosmFileStage stage) 01587 { 01588 #ifdef NOTUSED 01589 iosmFileStage prevStage = fsm->stage; 01590 const char * const prev = iosmFileStageString(prevStage); 01591 #endif 01592 const char * const cur = iosmFileStageString(stage); 01593 struct stat * st = &fsm->sb; 01594 struct stat * ost = &fsm->osb; 01595 int saveerrno = errno; 01596 int rc = fsm->rc; 01597 int i; 01598 01599 #define _fafilter(_a) \ 01600 (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \ 01601 ? iosmFileActionString(_a) : "") 01602 01603 if (stage & IOSM_DEAD) { 01604 /* do nothing */ 01605 } else if (stage & IOSM_INTERNAL) { 01606 if (fsm->debug && !(stage & IOSM_SYSCALL)) 01607 rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n", 01608 cur, 01609 (unsigned)st->st_mode, (int)st->st_nlink, 01610 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 01611 (fsm->path ? fsm->path : ""), 01612 _fafilter(fsm->action)); 01613 } else { 01614 const char * apath = NULL; 01615 if (fsm->path) 01616 (void) urlPath(fsm->path, &apath); 01617 fsm->stage = stage; 01618 if (fsm->debug || !(stage & IOSM_VERBOSE)) 01619 rpmlog(RPMLOG_DEBUG, "%-8s %06o%3d (%4d,%4d)%12lu %s %s\n", 01620 cur, 01621 (unsigned)st->st_mode, (int)st->st_nlink, 01622 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 01623 (apath ? apath + fsm->astriplen : ""), 01624 _fafilter(fsm->action)); 01625 } 01626 #undef _fafilter 01627 01628 switch (stage) { 01629 case IOSM_UNKNOWN: 01630 break; 01631 case IOSM_PKGINSTALL: 01632 while (1) { 01633 /* Clean fsm, free'ing memory. Read next archive header. */ 01634 rc = fsmUNSAFE(fsm, IOSM_INIT); 01635 01636 /* Exit on end-of-payload. */ 01637 if (rc == IOSMERR_HDR_TRAILER) { 01638 rc = 0; 01639 /*@loopbreak@*/ break; 01640 } 01641 01642 /* Exit on error. */ 01643 if (rc) { 01644 fsm->postpone = 1; 01645 (void) fsmNext(fsm, IOSM_UNDO); 01646 /*@loopbreak@*/ break; 01647 } 01648 01649 /* Extract file from archive. */ 01650 rc = fsmNext(fsm, IOSM_PROCESS); 01651 if (rc) { 01652 (void) fsmNext(fsm, IOSM_UNDO); 01653 /*@loopbreak@*/ break; 01654 } 01655 01656 /* Notify on success. */ 01657 (void) fsmNext(fsm, IOSM_NOTIFY); 01658 01659 rc = fsmNext(fsm, IOSM_FINI); 01660 if (rc) { 01661 /*@loopbreak@*/ break; 01662 } 01663 } 01664 break; 01665 case IOSM_PKGERASE: 01666 case IOSM_PKGCOMMIT: 01667 while (1) { 01668 /* Clean fsm, free'ing memory. */ 01669 rc = fsmUNSAFE(fsm, IOSM_INIT); 01670 01671 /* Exit on end-of-payload. */ 01672 if (rc == IOSMERR_HDR_TRAILER) { 01673 rc = 0; 01674 /*@loopbreak@*/ break; 01675 } 01676 01677 /* Rename/erase next item. */ 01678 if (fsmNext(fsm, IOSM_FINI)) 01679 /*@loopbreak@*/ break; 01680 } 01681 break; 01682 case IOSM_PKGBUILD: 01683 while (1) { 01684 01685 rc = fsmUNSAFE(fsm, IOSM_INIT); 01686 01687 /* Exit on end-of-payload. */ 01688 if (rc == IOSMERR_HDR_TRAILER) { 01689 rc = 0; 01690 /*@loopbreak@*/ break; 01691 } 01692 01693 /* Exit on error. */ 01694 if (rc) { 01695 fsm->postpone = 1; 01696 (void) fsmNext(fsm, IOSM_UNDO); 01697 /*@loopbreak@*/ break; 01698 } 01699 01700 /* Copy file into archive. */ 01701 rc = fsmNext(fsm, IOSM_PROCESS); 01702 if (rc) { 01703 (void) fsmNext(fsm, IOSM_UNDO); 01704 /*@loopbreak@*/ break; 01705 } 01706 01707 /* Notify on success. */ 01708 (void) fsmNext(fsm, IOSM_NOTIFY); 01709 01710 if (fsmNext(fsm, IOSM_FINI)) 01711 /*@loopbreak@*/ break; 01712 } 01713 01714 /* Flush partial sets of hard linked files. */ 01715 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) { 01716 int nlink, j; 01717 while ((fsm->li = fsm->links) != NULL) { 01718 fsm->links = fsm->li->next; 01719 fsm->li->next = NULL; 01720 01721 /* Re-calculate link count for archive header. */ 01722 for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) { 01723 if (fsm->li->filex[i] < 0) 01724 /*@innercontinue@*/ continue; 01725 nlink++; 01726 if (j == -1) j = i; 01727 } 01728 /* XXX force the contents out as well. */ 01729 if (j != 0) { 01730 fsm->li->filex[0] = fsm->li->filex[j]; 01731 fsm->li->filex[j] = -1; 01732 } 01733 fsm->li->sb.st_nlink = nlink; 01734 01735 fsm->sb = fsm->li->sb; /* structure assignment */ 01736 fsm->osb = fsm->sb; /* structure assignment */ 01737 01738 if (!rc) rc = writeLinkedFile(fsm); 01739 01740 fsm->li = freeHardLink(fsm->li); 01741 } 01742 } 01743 01744 if (!rc) 01745 rc = fsmNext(fsm, IOSM_TRAILER); 01746 01747 break; 01748 case IOSM_CREATE: 01749 fsm->path = _free(fsm->path); 01750 fsm->lpath = _free(fsm->lpath); 01751 fsm->opath = _free(fsm->opath); 01752 fsm->dnlx = _free(fsm->dnlx); 01753 01754 fsm->ldn = _free(fsm->ldn); 01755 fsm->ldnalloc = fsm->ldnlen = 0; 01756 01757 fsm->rdsize = fsm->wrsize = 0; 01758 fsm->rdbuf = fsm->rdb = _free(fsm->rdb); 01759 fsm->wrbuf = fsm->wrb = _free(fsm->wrb); 01760 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 01761 fsm->rdsize = 16 * BUFSIZ; 01762 fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize); 01763 fsm->wrsize = 16 * BUFSIZ; 01764 fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize); 01765 } 01766 01767 fsm->mkdirsdone = 0; 01768 fsm->ix = -1; 01769 fsm->links = NULL; 01770 fsm->li = NULL; 01771 errno = 0; /* XXX get rid of EBADF */ 01772 01773 /* Detect and create directories not explicitly in package. */ 01774 if (fsm->goal == IOSM_PKGINSTALL) { 01775 /*@-compdef@*/ 01776 rc = fsmNext(fsm, IOSM_MKDIRS); 01777 /*@=compdef@*/ 01778 if (!rc) fsm->mkdirsdone = 1; 01779 } 01780 01781 break; 01782 case IOSM_INIT: 01783 fsm->path = _free(fsm->path); 01784 fsm->lpath = _free(fsm->lpath); 01785 fsm->postpone = 0; 01786 fsm->diskchecked = fsm->exists = 0; 01787 fsm->subdir = NULL; 01788 fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL); 01789 fsm->action = FA_UNKNOWN; 01790 fsm->osuffix = NULL; 01791 fsm->nsuffix = NULL; 01792 01793 if (fsm->goal == IOSM_PKGINSTALL) { 01794 /* Read next header from payload, checking for end-of-payload. */ 01795 rc = fsmUNSAFE(fsm, IOSM_NEXT); 01796 } 01797 if (rc) break; 01798 01799 /* Identify mapping index. */ 01800 fsm->ix = ((fsm->goal == IOSM_PKGINSTALL) 01801 ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter)); 01802 01803 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST)) { 01804 /* Detect end-of-loop and/or mapping error. */ 01805 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) { 01806 if (fsm->ix < 0) { 01807 if (fsm->goal == IOSM_PKGINSTALL) { 01808 #if 0 01809 rpmlog(RPMLOG_WARNING, 01810 _("archive file %s was not found in header file list\n"), 01811 fsm->path); 01812 #endif 01813 if (fsm->failedFile && *fsm->failedFile == NULL) 01814 *fsm->failedFile = xstrdup(fsm->path); 01815 rc = IOSMERR_UNMAPPED_FILE; 01816 } else { 01817 rc = IOSMERR_HDR_TRAILER; 01818 } 01819 break; 01820 } 01821 } 01822 01823 /* On non-install, mode must be known so that dirs don't get suffix. */ 01824 if (fsm->goal != IOSM_PKGINSTALL) { 01825 rpmfi fi = fsmGetFi(fsm); 01826 st->st_mode = fi->fmodes[fsm->ix]; 01827 } 01828 } 01829 01830 /* Generate file path. */ 01831 rc = fsmNext(fsm, IOSM_MAP); 01832 if (rc) break; 01833 01834 /* Perform lstat/stat for disk file. */ 01835 #ifdef NOTYET 01836 rc = fsmStat(fsm); 01837 #else 01838 if (fsm->path != NULL && 01839 !(fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))) 01840 { 01841 rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS) 01842 ? IOSM_LSTAT : IOSM_STAT)); 01843 if (rc == IOSMERR_ENOENT) { 01844 errno = saveerrno; 01845 rc = 0; 01846 fsm->exists = 0; 01847 } else if (rc == 0) { 01848 fsm->exists = 1; 01849 } 01850 } else { 01851 /* Skip %ghost files on build. */ 01852 fsm->exists = 0; 01853 } 01854 #endif 01855 fsm->diskchecked = 1; 01856 if (rc) break; 01857 01858 /* On non-install, the disk file stat is what's remapped. */ 01859 if (fsm->goal != IOSM_PKGINSTALL) 01860 *st = *ost; /* structure assignment */ 01861 01862 /* Remap file perms, owner, and group. */ 01863 rc = fsmMapAttrs(fsm); 01864 if (rc) break; 01865 01866 fsm->postpone = iosmFileActionSkipped(fsm->action); 01867 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 01868 /*@-evalorder@*/ /* FIX: saveHardLink can modify fsm */ 01869 if (S_ISREG(st->st_mode) && st->st_nlink > 1) 01870 fsm->postpone = saveHardLink(fsm); 01871 /*@=evalorder@*/ 01872 } 01873 if (fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST) fsm->postpone = 1; 01874 break; 01875 case IOSM_PRE: 01876 break; 01877 case IOSM_MAP: 01878 rc = fsmMapPath(fsm); 01879 break; 01880 case IOSM_MKDIRS: 01881 rc = fsmMkdirs(fsm); 01882 break; 01883 case IOSM_RMDIRS: 01884 if (fsm->dnlx) 01885 rc = fsmRmdirs(fsm); 01886 break; 01887 case IOSM_PROCESS: 01888 if (fsm->postpone) { 01889 if (fsm->goal == IOSM_PKGINSTALL) { 01890 /* XXX Skip over file body, archive headers already done. */ 01891 if (S_ISREG(st->st_mode)) 01892 rc = fsmNext(fsm, IOSM_EAT); 01893 } 01894 break; 01895 } 01896 01897 if (fsm->goal == IOSM_PKGBUILD) { 01898 if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */ 01899 break; 01900 if (S_ISREG(st->st_mode) && st->st_nlink > 1) { 01901 struct hardLink_s * li, * prev; 01902 01903 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) break; 01904 rc = writeLinkedFile(fsm); 01905 if (rc) break; /* W2DO? */ 01906 01907 for (li = fsm->links, prev = NULL; li; prev = li, li = li->next) 01908 if (li == fsm->li) 01909 /*@loopbreak@*/ break; 01910 01911 if (prev == NULL) 01912 fsm->links = fsm->li->next; 01913 else 01914 prev->next = fsm->li->next; 01915 fsm->li->next = NULL; 01916 fsm->li = freeHardLink(fsm->li); 01917 } else { 01918 rc = writeFile(fsm, 1); 01919 } 01920 break; 01921 } 01922 01923 if (fsm->goal != IOSM_PKGINSTALL) 01924 break; 01925 01926 if (S_ISREG(st->st_mode) && fsm->lpath != NULL) { 01927 const char * opath = fsm->opath; 01928 char * t = xmalloc(strlen(fsm->lpath+1) + strlen(fsm->suffix) + 1); 01929 (void) stpcpy(t, fsm->lpath+1); 01930 fsm->opath = t; 01931 /* XXX link(fsm->opath, fsm->path) */ 01932 rc = fsmNext(fsm, IOSM_LINK); 01933 if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) { 01934 *fsm->failedFile = xstrdup(fsm->path); 01935 } 01936 fsm->opath = _free(fsm->opath); 01937 fsm->opath = opath; 01938 break; /* XXX so that delayed hard links get skipped. */ 01939 } 01940 if (S_ISREG(st->st_mode)) { 01941 const char * path = fsm->path; 01942 if (fsm->osuffix) 01943 fsm->path = fsmFsPath(fsm, st, NULL, NULL); 01944 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01945 01946 if (rc == 0 && fsm->osuffix) { 01947 const char * opath = fsm->opath; 01948 fsm->opath = fsm->path; 01949 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix); 01950 rc = fsmNext(fsm, IOSM_RENAME); 01951 if (!rc) 01952 rpmlog(RPMLOG_WARNING, 01953 _("%s saved as %s\n"), 01954 (fsm->opath ? fsm->opath : ""), 01955 (fsm->path ? fsm->path : "")); 01956 fsm->path = _free(fsm->path); 01957 fsm->opath = opath; 01958 } 01959 01960 /*@-dependenttrans@*/ 01961 fsm->path = path; 01962 /*@=dependenttrans@*/ 01963 if (!(rc == IOSMERR_ENOENT)) return rc; 01964 rc = extractRegular(fsm); 01965 } else if (S_ISDIR(st->st_mode)) { 01966 mode_t st_mode = st->st_mode; 01967 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01968 if (rc == IOSMERR_ENOENT) { 01969 st->st_mode &= ~07777; /* XXX abuse st->st_mode */ 01970 st->st_mode |= 00700; 01971 rc = fsmNext(fsm, IOSM_MKDIR); 01972 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01973 } 01974 } else if (S_ISLNK(st->st_mode)) { 01975 assert(fsm->lpath != NULL); 01976 /*@=dependenttrans@*/ 01977 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01978 if (rc == IOSMERR_ENOENT) 01979 rc = fsmNext(fsm, IOSM_SYMLINK); 01980 } else if (S_ISFIFO(st->st_mode)) { 01981 mode_t st_mode = st->st_mode; 01982 /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */ 01983 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01984 if (rc == IOSMERR_ENOENT) { 01985 st->st_mode = 0000; /* XXX abuse st->st_mode */ 01986 rc = fsmNext(fsm, IOSM_MKFIFO); 01987 st->st_mode = st_mode; /* XXX restore st->st_mode */ 01988 } 01989 } else if (S_ISCHR(st->st_mode) || 01990 S_ISBLK(st->st_mode) || 01991 /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/) 01992 { 01993 rc = fsmUNSAFE(fsm, IOSM_VERIFY); 01994 if (rc == IOSMERR_ENOENT) 01995 rc = fsmNext(fsm, IOSM_MKNOD); 01996 } else { 01997 /* XXX Repackaged payloads may be missing files. */ 01998 if (fsm->repackaged) 01999 break; 02000 02001 /* XXX Special case /dev/log, which shouldn't be packaged anyways */ 02002 if (!IS_DEV_LOG(fsm->path)) 02003 rc = IOSMERR_UNKNOWN_FILETYPE; 02004 } 02005 if (S_ISREG(st->st_mode) && st->st_nlink > 1) { 02006 fsm->li->createdPath = fsm->li->linkIndex; 02007 rc = fsmMakeLinks(fsm); 02008 } 02009 break; 02010 case IOSM_POST: 02011 break; 02012 case IOSM_MKLINKS: 02013 rc = fsmMakeLinks(fsm); 02014 break; 02015 case IOSM_NOTIFY: /* XXX move from fsm to psm -> tsm */ 02016 if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) { 02017 rpmts ts = fsmGetTs(fsm); 02018 rpmfi fi = fsmGetFi(fsm); 02019 void * ptr; 02020 rpmuint64_t archivePos = fdGetCpioPos(fsm->cfd); 02021 if (archivePos > fi->archivePos) { 02022 fi->archivePos = (unsigned long long) archivePos; 02023 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 02024 fi->archivePos, fi->archiveSize); 02025 } 02026 } 02027 break; 02028 case IOSM_UNDO: 02029 if (fsm->postpone) 02030 break; 02031 if (fsm->goal == IOSM_PKGINSTALL) { 02032 /* XXX only erase if temp fn w suffix is in use */ 02033 if (fsm->sufbuf[0] != '\0') 02034 (void) fsmNext(fsm, 02035 (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK)); 02036 02037 #ifdef NOTYET /* XXX remove only dirs just created, not all. */ 02038 if (fsm->dnlx) 02039 (void) fsmNext(fsm, IOSM_RMDIRS); 02040 #endif 02041 errno = saveerrno; 02042 } 02043 if (fsm->failedFile && *fsm->failedFile == NULL) 02044 *fsm->failedFile = xstrdup(fsm->path); 02045 break; 02046 case IOSM_FINI: 02047 if (!fsm->postpone && fsm->commit) { 02048 if (fsm->goal == IOSM_PKGINSTALL) 02049 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1) 02050 ? fsmCommitLinks(fsm) : fsmNext(fsm, IOSM_COMMIT)); 02051 if (fsm->goal == IOSM_PKGCOMMIT) 02052 rc = fsmNext(fsm, IOSM_COMMIT); 02053 if (fsm->goal == IOSM_PKGERASE) 02054 rc = fsmNext(fsm, IOSM_COMMIT); 02055 } 02056 fsm->path = _free(fsm->path); 02057 fsm->lpath = _free(fsm->lpath); 02058 fsm->opath = _free(fsm->opath); 02059 memset(st, 0, sizeof(*st)); 02060 memset(ost, 0, sizeof(*ost)); 02061 break; 02062 case IOSM_COMMIT: 02063 /* Rename pre-existing modified or unmanaged file. */ 02064 if (fsm->osuffix && fsm->diskchecked && 02065 (fsm->exists || (fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))) 02066 { 02067 const char * opath = fsm->opath; 02068 const char * path = fsm->path; 02069 fsm->opath = fsmFsPath(fsm, st, NULL, NULL); 02070 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix); 02071 rc = fsmNext(fsm, IOSM_RENAME); 02072 if (!rc) { 02073 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), 02074 (fsm->opath ? fsm->opath : ""), 02075 (fsm->path ? fsm->path : "")); 02076 } 02077 fsm->path = _free(fsm->path); 02078 fsm->path = path; 02079 fsm->opath = _free(fsm->opath); 02080 fsm->opath = opath; 02081 } 02082 02083 /* Remove erased files. */ 02084 if (fsm->goal == IOSM_PKGERASE) { 02085 if (fsm->action == FA_ERASE) { 02086 rpmfi fi = fsmGetFi(fsm); 02087 if (S_ISDIR(st->st_mode)) { 02088 rc = fsmNext(fsm, IOSM_RMDIR); 02089 if (!rc) break; 02090 switch (rc) { 02091 case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */ 02092 case IOSMERR_ENOTEMPTY: 02093 /* XXX make sure that build side permits %missingok on directories. */ 02094 if (fsm->fflags & RPMFILE_MISSINGOK) 02095 /*@innerbreak@*/ break; 02096 02097 /* XXX common error message. */ 02098 rpmlog( 02099 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02100 _("%s rmdir of %s failed: Directory not empty\n"), 02101 rpmfiTypeString(fi), fsm->path); 02102 /*@innerbreak@*/ break; 02103 default: 02104 rpmlog( 02105 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02106 _("%s rmdir of %s failed: %s\n"), 02107 rpmfiTypeString(fi), fsm->path, strerror(errno)); 02108 /*@innerbreak@*/ break; 02109 } 02110 } else { 02111 rc = fsmNext(fsm, IOSM_UNLINK); 02112 if (!rc) break; 02113 switch (rc) { 02114 case IOSMERR_ENOENT: 02115 if (fsm->fflags & RPMFILE_MISSINGOK) 02116 /*@innerbreak@*/ break; 02117 /*@fallthrough@*/ 02118 default: 02119 rpmlog( 02120 (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG), 02121 _(" %s: unlink of %s failed: %s\n"), 02122 rpmfiTypeString(fi), fsm->path, strerror(errno)); 02123 /*@innerbreak@*/ break; 02124 } 02125 } 02126 } 02127 /* XXX Failure to remove is not (yet) cause for failure. */ 02128 if (!fsm->strict_erasures) rc = 0; 02129 break; 02130 } 02131 02132 /* XXX Special case /dev/log, which shouldn't be packaged anyways */ 02133 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) { 02134 if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) { 02135 /* Rename temporary to final file name. */ 02136 if (!S_ISDIR(st->st_mode) && 02137 (fsm->subdir || fsm->suffix || fsm->nsuffix)) 02138 { 02139 fsm->opath = fsm->path; 02140 fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix); 02141 rc = fsmNext(fsm, IOSM_RENAME); 02142 if (rc) 02143 (void) Unlink(fsm->opath); 02144 else if (fsm->nsuffix) { 02145 const char * opath = fsmFsPath(fsm, st, NULL, NULL); 02146 rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), 02147 (opath ? opath : ""), 02148 (fsm->path ? fsm->path : "")); 02149 opath = _free(opath); 02150 } 02151 fsm->opath = _free(fsm->opath); 02152 } 02153 /* 02154 * Set file security context (if not disabled). 02155 */ 02156 if (!rc && !getuid()) { 02157 rc = fsmMapFContext(fsm); 02158 if (!rc) 02159 rc = fsmNext(fsm, IOSM_LSETFCON); 02160 /*@-dependenttrans -observertrans @*/ /* FIX: use the SELinux free wrapper */ 02161 fsm->fcontext = _free(fsm->fcontext); 02162 /*@=dependenttrans =observertrans @*/ 02163 } 02164 if (S_ISLNK(st->st_mode)) { 02165 if (!rc && !getuid()) 02166 rc = fsmNext(fsm, IOSM_LCHOWN); 02167 } else { 02168 if (!rc && !getuid()) 02169 rc = fsmNext(fsm, IOSM_CHOWN); 02170 if (!rc) 02171 rc = fsmNext(fsm, IOSM_CHMOD); 02172 if (!rc) { 02173 time_t mtime = st->st_mtime; 02174 rpmfi fi = fsmGetFi(fsm); 02175 if (fi->fmtimes) 02176 st->st_mtime = fi->fmtimes[fsm->ix]; 02177 rc = fsmNext(fsm, IOSM_UTIME); 02178 st->st_mtime = mtime; 02179 } 02180 } 02181 } 02182 } 02183 02184 /* Notify on success. */ 02185 if (!rc) rc = fsmNext(fsm, IOSM_NOTIFY); 02186 else if (fsm->failedFile && *fsm->failedFile == NULL) { 02187 *fsm->failedFile = fsm->path; 02188 fsm->path = NULL; 02189 } 02190 break; 02191 case IOSM_DESTROY: 02192 fsm->path = _free(fsm->path); 02193 02194 /* Check for hard links missing from payload. */ 02195 while ((fsm->li = fsm->links) != NULL) { 02196 fsm->links = fsm->li->next; 02197 fsm->li->next = NULL; 02198 if (fsm->goal == IOSM_PKGINSTALL && 02199 fsm->commit && fsm->li->linksLeft) 02200 { 02201 for (i = 0 ; i < fsm->li->linksLeft; i++) { 02202 if (fsm->li->filex[i] < 0) 02203 /*@innercontinue@*/ continue; 02204 rc = IOSMERR_MISSING_HARDLINK; 02205 if (fsm->failedFile && *fsm->failedFile == NULL) { 02206 fsm->ix = fsm->li->filex[i]; 02207 if (!fsmNext(fsm, IOSM_MAP)) { 02208 *fsm->failedFile = fsm->path; 02209 fsm->path = NULL; 02210 } 02211 } 02212 /*@loopbreak@*/ break; 02213 } 02214 } 02215 if (fsm->goal == IOSM_PKGBUILD && 02216 (fsm->mapFlags & IOSM_ALL_HARDLINKS)) 02217 { 02218 rc = IOSMERR_MISSING_HARDLINK; 02219 } 02220 fsm->li = freeHardLink(fsm->li); 02221 } 02222 fsm->ldn = _free(fsm->ldn); 02223 fsm->ldnalloc = fsm->ldnlen = 0; 02224 fsm->rdbuf = fsm->rdb = _free(fsm->rdb); 02225 fsm->wrbuf = fsm->wrb = _free(fsm->wrb); 02226 break; 02227 case IOSM_VERIFY: 02228 if (fsm->diskchecked && !fsm->exists) { 02229 rc = IOSMERR_ENOENT; 02230 break; 02231 } 02232 if (S_ISREG(st->st_mode)) { 02233 char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE")); 02234 (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE"); 02235 /* 02236 * XXX HP-UX (and other os'es) don't permit unlink on busy 02237 * XXX files. 02238 */ 02239 fsm->opath = fsm->path; 02240 fsm->path = path; 02241 rc = fsmNext(fsm, IOSM_RENAME); 02242 if (!rc) 02243 (void) fsmNext(fsm, IOSM_UNLINK); 02244 else 02245 rc = IOSMERR_UNLINK_FAILED; 02246 fsm->path = fsm->opath; 02247 fsm->opath = NULL; 02248 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */ 02249 /*@notreached@*/ break; 02250 } else if (S_ISDIR(st->st_mode)) { 02251 if (S_ISDIR(ost->st_mode)) return 0; 02252 if (S_ISLNK(ost->st_mode)) { 02253 rc = fsmUNSAFE(fsm, IOSM_STAT); 02254 if (rc == IOSMERR_ENOENT) rc = 0; 02255 if (rc) break; 02256 errno = saveerrno; 02257 if (S_ISDIR(ost->st_mode)) return 0; 02258 } 02259 } else if (S_ISLNK(st->st_mode)) { 02260 if (S_ISLNK(ost->st_mode)) { 02261 /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */ 02262 rc = fsmUNSAFE(fsm, IOSM_READLINK); 02263 errno = saveerrno; 02264 if (rc) break; 02265 if (!strcmp(fsm->lpath, fsm->rdbuf)) return 0; 02266 } 02267 } else if (S_ISFIFO(st->st_mode)) { 02268 if (S_ISFIFO(ost->st_mode)) return 0; 02269 } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { 02270 if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) && 02271 (ost->st_rdev == st->st_rdev)) return 0; 02272 } else if (S_ISSOCK(st->st_mode)) { 02273 if (S_ISSOCK(ost->st_mode)) return 0; 02274 } 02275 /* XXX shouldn't do this with commit/undo. */ 02276 rc = 0; 02277 if (fsm->stage == IOSM_PROCESS) rc = fsmNext(fsm, IOSM_UNLINK); 02278 if (rc == 0) rc = IOSMERR_ENOENT; 02279 return (rc ? rc : IOSMERR_ENOENT); /* XXX HACK */ 02280 /*@notreached@*/ break; 02281 02282 case IOSM_UNLINK: 02283 { const char * fn = fsm->path; 02284 uint8_t * b = (uint8_t *)""; 02285 size_t blen = 0; 02286 uint8_t * d = NULL; 02287 size_t dlen = 0; 02288 uint32_t dalgo = 0; 02289 FD_t fd = NULL; 02290 struct stat sb; 02291 mode_t mode; 02292 sb.st_mode = 0; 02293 if (!Lstat(fn, &sb) && S_ISREG(sb.st_mode)) { 02294 fd = Fopen(fn, "r.fdio"); 02295 blen = sb.st_size; 02296 b = mmap(NULL, blen, PROT_READ, MAP_SHARED, Fileno(fd), 0); 02297 } 02298 mode = sb.st_mode; 02299 rc = rpmlioUnlink(rpmtsGetRdb(fsmGetTs(fsm)), fn, mode, b, blen, d, dlen, dalgo); 02300 if (fd != NULL) { 02301 /*@-observertrans@*/ /* FIX: b should be initialized to NULL, not "" */ 02302 (void)munmap(b, blen); 02303 /*@=observertrans@*/ 02304 (void) Fclose(fd); 02305 fd = NULL; 02306 } 02307 } goto iosmcall; 02308 case IOSM_RENAME: 02309 { const char * ofn = fsm->opath; 02310 const char * fn = fsm->path; 02311 uint8_t * b = NULL; 02312 size_t blen = 0; 02313 uint8_t * d = NULL; 02314 size_t dlen = 0; 02315 uint32_t dalgo = 0; 02316 FD_t fd = NULL; 02317 struct stat sb; 02318 mode_t mode; 02319 sb.st_mode = 0; 02320 if (!Lstat(fn, &sb) && S_ISREG(sb.st_mode)) { 02321 fd = Fopen(fn, "r.fdio"); 02322 blen = sb.st_size; 02323 b = mmap(NULL, blen, PROT_READ, MAP_SHARED, Fileno(fd), 0); 02324 } 02325 mode = sb.st_mode; 02326 rc = rpmlioRename(rpmtsGetRdb(fsmGetTs(fsm)), ofn, fn, mode, b, blen, d, dlen, dalgo); 02327 if (fd != NULL) { 02328 (void)munmap(b, blen); 02329 (void) Fclose(fd); 02330 fd = NULL; 02331 } 02332 } goto iosmcall; 02333 case IOSM_MKDIR: 02334 rc = rpmlioMkdir(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_mode); 02335 goto iosmcall; 02336 case IOSM_RMDIR: 02337 rc = rpmlioRmdir(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_mode); 02338 goto iosmcall; 02339 case IOSM_LSETFCON: 02340 /* Log iff lsetfilecon() will actually be called. */ 02341 if (fsm->fcontext && *fsm->fcontext 02342 && strcmp(fsm->fcontext, "<<none>>")) 02343 rc = rpmlioLsetfilecon(rpmtsGetRdb(fsmGetTs(fsm)), 02344 fsm->path, fsm->fcontext); 02345 goto iosmcall; 02346 case IOSM_CHOWN: 02347 rc = rpmlioChown(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_uid, st->st_gid); 02348 goto iosmcall; 02349 case IOSM_LCHOWN: 02350 rc = rpmlioLchown(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_uid, st->st_gid); 02351 goto iosmcall; 02352 case IOSM_CHMOD: 02353 rc = rpmlioChmod(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_mode); 02354 goto iosmcall; 02355 case IOSM_UTIME: 02356 rc = rpmlioUtime(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_mtime, st->st_mtime); 02357 goto iosmcall; 02358 case IOSM_SYMLINK: 02359 rc = rpmlioSymlink(rpmtsGetRdb(fsmGetTs(fsm)), fsm->lpath, fsm->path); 02360 goto iosmcall; 02361 case IOSM_LINK: 02362 rc = rpmlioLink(rpmtsGetRdb(fsmGetTs(fsm)), fsm->opath, fsm->path); 02363 goto iosmcall; 02364 case IOSM_MKFIFO: 02365 rc = rpmlioMkfifo(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_mode); 02366 goto iosmcall; 02367 case IOSM_MKNOD: 02368 rc = rpmlioMknod(rpmtsGetRdb(fsmGetTs(fsm)), fsm->path, st->st_mode, st->st_rdev); 02369 goto iosmcall; 02370 case IOSM_LSTAT: 02371 case IOSM_STAT: 02372 case IOSM_READLINK: 02373 case IOSM_CHROOT: 02374 iosmcall: 02375 rc = iosmStage(fsm, stage); 02376 break; 02377 02378 case IOSM_NEXT: 02379 case IOSM_EAT: 02380 case IOSM_POS: 02381 case IOSM_PAD: 02382 case IOSM_TRAILER: 02383 case IOSM_HREAD: 02384 case IOSM_HWRITE: 02385 case IOSM_DREAD: 02386 case IOSM_DWRITE: 02387 rc = iosmStage(fsm, stage); 02388 break; 02389 02390 case IOSM_ROPEN: 02391 case IOSM_READ: 02392 case IOSM_RCLOSE: 02393 rc = iosmStage(fsm, stage); 02394 break; 02395 case IOSM_WOPEN: 02396 case IOSM_WRITE: 02397 case IOSM_WCLOSE: 02398 rc = iosmStage(fsm, stage); 02399 break; 02400 02401 default: 02402 break; 02403 } 02404 02405 if (!(stage & IOSM_INTERNAL)) { 02406 fsm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc); 02407 } 02408 return rc; 02409 } 02410 /*@=compmempass@*/