int rpmfiCompare(const rpmfi afi, const rpmfi bfi) { rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi)); rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi)); if ((rpmfiFFlags(afi) & RPMFILE_GHOST) || (rpmfiFFlags(bfi) & RPMFILE_GHOST)) return 0; if (awhat != bwhat) return 1; if (awhat == LINK) { const char * alink = rpmfiFLink(afi); const char * blink = rpmfiFLink(bfi); if (alink == blink) return 0; if (alink == NULL) return 1; if (blink == NULL) return -1; return strcmp(alink, blink); } else if (awhat == REG) { size_t adiglen, bdiglen; pgpHashAlgo aalgo, balgo; const unsigned char * adigest = rpmfiFDigest(afi, &aalgo, &adiglen); const unsigned char * bdigest = rpmfiFDigest(bfi, &balgo, &bdiglen); if (adigest == bdigest) return 0; if (adigest == NULL) return 1; if (bdigest == NULL) return -1; /* can't meaningfully compare different hash types */ if (aalgo != balgo || adiglen != bdiglen) return -1; return memcmp(adigest, bdigest, adiglen); } return 0; }
/* * Attempt to generate libmagic-style file class if missing from header: * we can easily generate this for symlinks and other special types. * Always return malloced strings to simplify life in fileclassTag(). */ static char *makeFClass(rpmfi fi) { char *fclass = NULL; const char *hc = rpmfiFClass(fi); if (hc != NULL && hc[0] != '\0') { fclass = xstrdup(hc); } else { switch (rpmfiFMode(fi) & S_IFMT) { case S_IFBLK: fclass = xstrdup("block special"); break; case S_IFCHR: fclass = xstrdup("character special"); break; case S_IFDIR: fclass = xstrdup("directory"); break; case S_IFIFO: fclass = xstrdup("fifo (named pipe)"); break; case S_IFSOCK: fclass = xstrdup("socket"); break; case S_IFLNK: fclass = rstrscat(NULL, "symbolic link to `", rpmfiFLink(fi), "'", NULL); break; } } return (fclass != NULL) ? fclass : xstrdup(""); }
/* Add fingerprint for each file not skipped. */ static void addFingerprints(rpmts ts, uint64_t fileCount, rpmFpHash ht, fingerPrintCache fpc) { rpmtsi pi; rpmte p; rpmfi fi; int i; rpmFpHash symlinks = rpmFpHashCreate(fileCount/16+16, fpHashFunction, fpEqual, NULL, NULL); pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { (void) rpmdbCheckSignals(); if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); rpmfiFpLookup(fi, fpc); /* collect symbolic links */ fi = rpmfiInit(fi, 0); while ((i = rpmfiNext(fi)) >= 0) { struct rpmffi_s ffi; char const *linktarget; linktarget = rpmfiFLink(fi); if (!(linktarget && *linktarget != '\0')) continue; if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i))) continue; ffi.p = p; ffi.fileno = i; rpmFpHashAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi)); } rpmtsiFree(pi); /* =============================================== * Check fingerprints if they contain symlinks * and add them to the hash table */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { (void) rpmdbCheckSignals(); fi = rpmfiInit(rpmteFI(p), 0); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); while ((i = rpmfiNext(fi)) >= 0) { if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i))) continue; fpLookupSubdir(symlinks, ht, fpc, p, i); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); } rpmtsiFree(pi); rpmFpHashFree(symlinks); }
static VALUE rpmfi_FLink_get(VALUE s) { rpmfi fi = rpmfi_ptr(s); if (_debug) fprintf(stderr, "==> %s(0x%lx) ptr %p\n", __FUNCTION__, s, fi); return INT2FIX(rpmfiFLink(fi)); }
int rpmfiConfigConflict(const rpmfi fi) { const char * fn = rpmfiFN(fi); rpmfileAttrs flags = rpmfiFFlags(fi); char buffer[1024]; rpmFileTypes newWhat, diskWhat; struct stat sb; if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) { return 0; } diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode); newWhat = rpmfiWhatis(rpmfiFMode(fi)); if (newWhat != LINK && newWhat != REG) return 1; if (diskWhat != newWhat) return 1; memset(buffer, 0, sizeof(buffer)); if (newWhat == REG) { int algo; size_t diglen; const unsigned char *ndigest = rpmfiFDigest(fi, &algo, &diglen); if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL)) return 0; /* assume file has been removed */ if (ndigest && !memcmp(ndigest, buffer, diglen)) return 0; /* unmodified config file */ } else /* newWhat == LINK */ { const char * nFLink; ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1); if (link_len == -1) return 0; /* assume file has been removed */ buffer[link_len] = '\0'; nFLink = rpmfiFLink(fi); if (nFLink && rstreq(nFLink, buffer)) return 0; /* unmodified config file */ } return 1; }
static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi) { archive_entry_clear(entry); char * filename = rstrscat(NULL, ".", rpmfiDN(fi), rpmfiBN(fi), NULL); archive_entry_copy_pathname(entry, filename); _free(filename); archive_entry_set_size(entry, rpmfiFSize(fi)); rpm_mode_t mode = rpmfiFMode(fi); archive_entry_set_filetype(entry, mode & S_IFMT); archive_entry_set_perm(entry, mode); archive_entry_set_uname(entry, rpmfiFUser(fi)); archive_entry_set_gname(entry, rpmfiFGroup(fi)); archive_entry_set_rdev(entry, rpmfiFRdev(fi)); archive_entry_set_mtime(entry, rpmfiFMtime(fi), 0); if (S_ISLNK(mode)) archive_entry_set_symlink(entry, rpmfiFLink(fi)); }
/*@null@*/ static PyObject * rpmfi_FLink(rpmfiObject * s) /*@*/ { return Py_BuildValue("s", xstrdup(rpmfiFLink(s->fi))); }
static PyObject * rpmfi_FLink(rpmfiObject * s, PyObject * unused) { return Py_BuildValue("s", rpmfiFLink(s->fi)); }
rpmFileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing) { const char * fn = rpmfiFN(nfi); rpmfileAttrs newFlags = rpmfiFFlags(nfi); char buffer[1024]; rpmFileTypes dbWhat, newWhat, diskWhat; struct stat sb; int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE; if (lstat(fn, &sb)) { /* * The file doesn't exist on the disk. Create it unless the new * package has marked it as missingok, or allfiles is requested. */ if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) { rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n", fn); return FA_SKIP; } else { return FA_CREATE; } } diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode); dbWhat = rpmfiWhatis(rpmfiFMode(ofi)); newWhat = rpmfiWhatis(rpmfiFMode(nfi)); /* * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore * them in older packages as well. */ if (newWhat == XDIR) return FA_CREATE; if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK) return save; else if (newWhat != dbWhat && diskWhat != dbWhat) return save; else if (dbWhat != newWhat) return FA_CREATE; else if (dbWhat != LINK && dbWhat != REG) return FA_CREATE; /* * This order matters - we'd prefer to CREATE the file if at all * possible in case something else (like the timestamp) has changed. */ memset(buffer, 0, sizeof(buffer)); if (dbWhat == REG) { pgpHashAlgo oalgo, nalgo; size_t odiglen, ndiglen; const unsigned char * odigest, * ndigest; odigest = rpmfiFDigest(ofi, &oalgo, &odiglen); if (diskWhat == REG) { if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL)) return FA_CREATE; /* assume file has been removed */ if (odigest && !memcmp(odigest, buffer, odiglen)) return FA_CREATE; /* unmodified config file, replace. */ } ndigest = rpmfiFDigest(nfi, &nalgo, &ndiglen); /* Can't compare different hash types, backup to avoid data loss */ if (oalgo != nalgo || odiglen != ndiglen) return save; if (odigest && ndigest && !memcmp(odigest, ndigest, odiglen)) return FA_SKIP; /* identical file, don't bother. */ } else /* dbWhat == LINK */ { const char * oFLink, * nFLink; oFLink = rpmfiFLink(ofi); if (diskWhat == LINK) { if (readlink(fn, buffer, sizeof(buffer) - 1) == -1) return FA_CREATE; /* assume file has been removed */ if (oFLink && rstreq(oFLink, buffer)) return FA_CREATE; /* unmodified config file, replace. */ } nFLink = rpmfiFLink(nfi); if (oFLink && nFLink && rstreq(oFLink, nFLink)) return FA_SKIP; /* identical file, don't bother. */ } /* * The config file on the disk has been modified, but * the ones in the two packages are different. It would * be nice if RPM was smart enough to at least try and * merge the difference ala CVS, but... */ return save; }
int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) { rpm_color_t tscolor = rpmtsColor(ts); int i; int rc = 0; int totalFileCount = 0; rpmfi fi; fingerPrintCache fpc; rpmps ps; rpmtsi pi; rpmte p; int numAdded; int numRemoved; void * lock = NULL; int xx; /* XXX programmer error segfault avoidance. */ if (rpmtsNElements(ts) <= 0) return -1; /* If we are in test mode, then there's no need for transaction lock. */ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) { lock = rpmtsAcquireLock(ts); if (lock == NULL) return -1; /* XXX W2DO? */ } if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers)); if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers)); if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers)); /* if SELinux isn't enabled or init fails, don't bother... */ if (!rpmtsSELinuxEnabled(ts)) { rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS)); } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) { char *fn = rpmGetPath("%{?_install_file_context_path}", NULL); if (matchpathcon_init(fn) == -1) { rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS)); } free(fn); } ts->probs = rpmpsFree(ts->probs); ts->probs = rpmpsCreate(); /* XXX Make sure the database is open RDWR for package install/erase. */ { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) ? O_RDONLY : (O_RDWR|O_CREAT); /* Open database RDWR for installing packages. */ if (rpmtsOpenDB(ts, dbmode)) { rpmtsFreeLock(lock); return -1; /* XXX W2DO? */ } } ts->ignoreSet = ignoreSet; { char * currDir = rpmGetCwd(); rpmtsSetCurrDir(ts, currDir); currDir = _free(currDir); } (void) rpmtsSetChrootDone(ts, 0); { rpm_tid_t tid = (rpm_tid_t) time(NULL); (void) rpmtsSetTid(ts, tid); } /* Get available space on mounted file systems. */ xx = rpmtsInitDSI(ts); /* =============================================== * For packages being installed: * - verify package arch/os. * - verify package epoch:version-release is newer. * - count files. * For packages being removed: * - count files. */ rpmlog(RPMLOG_DEBUG, "sanity checking %d elements\n", rpmtsNElements(ts)); ps = rpmtsProblems(ts); /* The ordering doesn't matter here */ pi = rpmtsiInit(ts); /* XXX Only added packages need be checked. */ while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) { rpmdbMatchIterator mi; int fc; if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH)) if (!archOkay(rpmteA(p))) rpmpsAppend(ps, RPMPROB_BADARCH, rpmteNEVRA(p), rpmteKey(p), rpmteA(p), NULL, NULL, 0); if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS)) if (!osOkay(rpmteO(p))) rpmpsAppend(ps, RPMPROB_BADOS, rpmteNEVRA(p), rpmteKey(p), rpmteO(p), NULL, NULL, 0); if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) { Header h; mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0); while ((h = rpmdbNextIterator(mi)) != NULL) xx = ensureOlder(ts, p, h); mi = rpmdbFreeIterator(mi); } if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) { mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0); xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(p)); xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(p)); xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(p)); if (tscolor) { xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(p)); xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(p)); } while (rpmdbNextIterator(mi) != NULL) { rpmpsAppend(ps, RPMPROB_PKG_INSTALLED, rpmteNEVRA(p), rpmteKey(p), NULL, NULL, NULL, 0); break; } mi = rpmdbFreeIterator(mi); } /* Count no. of files (if any). */ totalFileCount += fc; } pi = rpmtsiFree(pi); ps = rpmpsFree(ps); /* The ordering doesn't matter here */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) { int fc; if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); totalFileCount += fc; } pi = rpmtsiFree(pi); /* Run pre-transaction scripts, but only if there are no known * problems up to this point and not disabled otherwise. */ if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPRE)) || (rpmpsNumProblems(ts->probs) && (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) { rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n"); runTransScripts(ts, RPMTAG_PRETRANS); } /* =============================================== * Initialize transaction element file info for package: */ /* * FIXME?: we'd be better off assembling one very large file list and * calling fpLookupList only once. I'm not sure that the speedup is * worth the trouble though. */ rpmlog(RPMLOG_DEBUG, "computing %d file fingerprints\n", totalFileCount); numAdded = numRemoved = 0; pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { int fc; if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); switch (rpmteType(p)) { case TR_ADDED: numAdded++; /* Skip netshared paths, not our i18n files, and excluded docs */ if (fc > 0) skipFiles(ts, p); break; case TR_REMOVED: numRemoved++; break; } } pi = rpmtsiFree(pi); if (!rpmtsChrootDone(ts)) { const char * rootDir = rpmtsRootDir(ts); xx = chdir("/"); if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') { /* opening db before chroot not optimal, see rhbz#103852 c#3 */ xx = rpmdbOpenAll(ts->rdb); if (chroot(rootDir) == -1) { rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n")); return -1; } } (void) rpmtsSetChrootDone(ts, 1); } ts->ht = rpmFpHashCreate(totalFileCount/2+1, fpHashFunction, fpEqual, NULL, NULL); rpmFpHash symlinks = rpmFpHashCreate(totalFileCount/16+16, fpHashFunction, fpEqual, NULL, NULL); fpc = fpCacheCreate(totalFileCount/2 + 10001); /* =============================================== * Add fingerprint for each file not skipped. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { int fc; (void) rpmdbCheckSignals(); if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); rpmfiFpLookup(fi, fpc); /* collect symbolic links */ fi = rpmfiInit(fi, 0); if (fi != NULL) /* XXX lclint */ while ((i = rpmfiNext(fi)) >= 0) { struct rpmffi_s ffi; char const *linktarget; linktarget = rpmfiFLink(fi); if (!(linktarget && *linktarget != '\0')) continue; if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i))) continue; ffi.p = p; ffi.fileno = i; rpmFpHashAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc); } pi = rpmtsiFree(pi); /* =============================================== * Check fingerprints if they contain symlinks * and add them to the ts->ht hash table */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { (void) rpmdbCheckSignals(); if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fi = rpmfiInit(fi, 0); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); if (fi != NULL) /* XXX lclint */ while ((i = rpmfiNext(fi)) >= 0) { if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i))) continue; fpLookupSubdir(symlinks, ts->ht, fpc, p, i); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); } pi = rpmtsiFree(pi); rpmFpHashFree(symlinks); /* =============================================== * Compute file disposition for each package in transaction set. */ rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount); /* check against files in the rpmdb */ checkInstalledFiles(ts, fpc); pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); /* check files in ts against each other and update disk space needs on each partition for this package. */ handleOverlappedFiles(ts, p, fi); /* Check added package has sufficient space on each partition used. */ if (rpmteType(p) == TR_ADDED) { rpmtsCheckDSIProblems(ts, p); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); } pi = rpmtsiFree(pi); if (rpmtsChrootDone(ts)) { const char * rootDir = rpmtsRootDir(ts); const char * currDir = rpmtsCurrDir(ts); if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') xx = chroot("."); (void) rpmtsSetChrootDone(ts, 0); if (currDir != NULL) xx = chdir(currDir); } rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount); /* =============================================== * Free unused memory as soon as possible. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmteSetFI(p, NULL); } pi = rpmtsiFree(pi); fpc = fpCacheFree(fpc); ts->ht = rpmFpHashFree(ts->ht); /* =============================================== * If unfiltered problems exist, free memory and return. */ if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS) || (rpmpsNumProblems(ts->probs) && (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))) ) { rpmtsFreeLock(lock); return ts->orderCount; } /* Actually install and remove packages */ rc = rpmtsProcess(ts); if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPOST))) { rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n"); runTransScripts(ts, RPMTAG_POSTTRANS); } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) { matchpathcon_fini(); } rpmtsFreeLock(lock); /* FIX: ts->flList may be NULL */ if (rc) return -1; else return 0; }
int rpmVerifyFile(const rpmts ts, const rpmfi fi, rpmVerifyAttrs * res, rpmVerifyAttrs omitMask) { rpm_mode_t fmode = rpmfiFMode(fi); rpmfileAttrs fileAttrs = rpmfiFFlags(fi); rpmVerifyAttrs flags = rpmfiVFlags(fi); const char * fn = rpmfiFN(fi); struct stat sb; int rc; *res = RPMVERIFY_NONE; /* * Check to see if the file was installed - if not pretend all is OK. */ switch (rpmfiFState(fi)) { case RPMFILE_STATE_NETSHARED: case RPMFILE_STATE_REPLACED: case RPMFILE_STATE_NOTINSTALLED: case RPMFILE_STATE_WRONGCOLOR: return 0; break; case RPMFILE_STATE_NORMAL: break; } if (fn == NULL || lstat(fn, &sb) != 0) { *res |= RPMVERIFY_LSTATFAIL; return 1; } /* * Not all attributes of non-regular files can be verified. */ if (S_ISDIR(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else if (S_ISLNK(sb.st_mode)) { flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_MODE | RPMVERIFY_CAPS); #if CHOWN_FOLLOWS_SYMLINK flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP); #endif } else if (S_ISFIFO(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else if (S_ISCHR(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else if (S_ISBLK(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else flags &= ~(RPMVERIFY_LINKTO); /* * Content checks of %ghost files are meaningless. */ if (fileAttrs & RPMFILE_GHOST) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO); /* * Don't verify any features in omitMask. */ flags &= ~(omitMask | RPMVERIFY_FAILURES); if (flags & RPMVERIFY_MD5) { const unsigned char *digest; pgpHashAlgo algo; size_t diglen; /* XXX If --nomd5, then prelinked library sizes are not corrected. */ if ((digest = rpmfiFDigest(fi, &algo, &diglen))) { unsigned char fdigest[diglen]; rpm_loff_t fsize; rc = rpmDoDigest(algo, fn, 0, fdigest, &fsize); sb.st_size = fsize; if (rc) { *res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5); } else if (memcmp(fdigest, digest, diglen)) { *res |= RPMVERIFY_MD5; } } else { *res |= RPMVERIFY_MD5; } } if (flags & RPMVERIFY_LINKTO) { char linkto[1024+1]; int size = 0; if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1) *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); else { const char * flink = rpmfiFLink(fi); linkto[size] = '\0'; if (flink == NULL || strcmp(linkto, flink)) *res |= RPMVERIFY_LINKTO; } } if (flags & RPMVERIFY_FILESIZE) { if (sb.st_size != rpmfiFSize(fi)) *res |= RPMVERIFY_FILESIZE; } if (flags & RPMVERIFY_MODE) { rpm_mode_t metamode = fmode; rpm_mode_t filemode; /* * Platforms (like AIX) where sizeof(rpm_mode_t) != sizeof(mode_t) * need the (rpm_mode_t) cast here. */ filemode = (rpm_mode_t)sb.st_mode; /* * Comparing the type of %ghost files is meaningless, but perms are OK. */ if (fileAttrs & RPMFILE_GHOST) { metamode &= ~0xf000; filemode &= ~0xf000; } if (metamode != filemode) *res |= RPMVERIFY_MODE; #if WITH_ACL /* * For now, any non-default acl's on a file is a difference as rpm * cannot have set them. */ acl_t facl = acl_get_file(fn, ACL_TYPE_ACCESS); if (facl) { if (acl_equiv_mode(facl, NULL) == 1) { *res |= RPMVERIFY_MODE; } acl_free(facl); } #endif } if (flags & RPMVERIFY_RDEV) { if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode) || S_ISBLK(fmode) != S_ISBLK(sb.st_mode)) { *res |= RPMVERIFY_RDEV; } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) { rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff); rpm_rdev_t frdev = (rpmfiFRdev(fi) & 0xffff); if (st_rdev != frdev) *res |= RPMVERIFY_RDEV; } } #if WITH_CAP if (flags & RPMVERIFY_CAPS) { /* * Empty capability set ("=") is not exactly the same as no * capabilities at all but suffices for now... */ cap_t cap, fcap; cap = cap_from_text(rpmfiFCaps(fi)); if (!cap) { cap = cap_from_text("="); } fcap = cap_get_file(fn); if (!fcap) { fcap = cap_from_text("="); } if (cap_compare(cap, fcap) != 0) *res |= RPMVERIFY_CAPS; cap_free(fcap); cap_free(cap); } #endif if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) { /* Filter out timestamp differences of shared files */ rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0); if (rpmdbGetIteratorCount(mi) < 2) *res |= RPMVERIFY_MTIME; rpmdbFreeIterator(mi); } if (flags & RPMVERIFY_USER) { const char * name = uidToUname(sb.st_uid); const char * fuser = rpmfiFUser(fi); if (name == NULL || fuser == NULL || strcmp(name, fuser)) *res |= RPMVERIFY_USER; } if (flags & RPMVERIFY_GROUP) { const char * name = gidToGname(sb.st_gid); const char * fgroup = rpmfiFGroup(fi); if (name == NULL || fgroup == NULL || strcmp(name, fgroup)) *res |= RPMVERIFY_GROUP; } return 0; }