int rpmfiCompareIndex(rpmfi afi, int aix, rpmfi bfi, int bix) { mode_t amode = rpmfiFModeIndex(afi, aix); mode_t bmode = rpmfiFModeIndex(bfi, bix); rpmFileTypes awhat = rpmfiWhatis(amode); if ((rpmfiFFlagsIndex(afi, aix) & RPMFILE_GHOST) || (rpmfiFFlagsIndex(bfi, bix) & RPMFILE_GHOST)) return 0; /* Mode difference is a conflict, except for symlinks */ if (!(awhat == LINK && rpmfiWhatis(bmode) == LINK) && amode != bmode) return 1; if (awhat == LINK || awhat == REG) { if (rpmfiFSizeIndex(afi, aix) != rpmfiFSizeIndex(bfi, bix)) return 1; } if (!rstreq(rpmfiFUserIndex(afi, aix), rpmfiFUserIndex(bfi, bix))) return 1; if (!rstreq(rpmfiFGroupIndex(afi, aix), rpmfiFGroupIndex(bfi, bix))) return 1; if (awhat == LINK) { const char * alink = rpmfiFLinkIndex(afi, aix); const char * blink = rpmfiFLinkIndex(bfi, bix); 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; int aalgo, balgo; const unsigned char * adigest, * bdigest; adigest = rpmfiFDigestIndex(afi, aix, &aalgo, &adiglen); bdigest = rpmfiFDigestIndex(bfi, bix, &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); } else if (awhat == CDEV || awhat == BDEV) { if (rpmfiFRdevIndex(afi, aix) != rpmfiFRdevIndex(bfi, bix)) return 1; } return 0; }
int rpmfiConfigConflictIndex(rpmfi fi, int ix) { const char * fn = rpmfiFNIndex(fi, ix); rpmfileAttrs flags = rpmfiFFlagsIndex(fi, ix); 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(rpmfiFModeIndex(fi, ix)); 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 = rpmfiFDigestIndex(fi,ix, &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 = rpmfiFLinkIndex(fi, ix); if (nFLink && rstreq(nFLink, buffer)) return 0; /* unmodified config file */ } return 1; }
rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix, int skipMissing) { const char * fn = rpmfiFNIndex(nfi, nix); rpmfileAttrs newFlags = rpmfiFFlagsIndex(nfi, nix); 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(rpmfiFModeIndex(ofi, oix)); newWhat = rpmfiWhatis(rpmfiFModeIndex(nfi, nix)); /* * 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) { int oalgo, nalgo; size_t odiglen, ndiglen; const unsigned char * odigest, * ndigest; odigest = rpmfiFDigestIndex(ofi, oix, &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 = rpmfiFDigestIndex(nfi, nix, &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 = rpmfiFLinkIndex(ofi, oix); if (diskWhat == LINK) { ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1); if (link_len == -1) return FA_CREATE; /* assume file has been removed */ buffer[link_len] = '\0'; if (oFLink && rstreq(oFLink, buffer)) return FA_CREATE; /* unmodified config file, replace. */ } nFLink = rpmfiFLinkIndex(nfi, nix); 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 rpmfiConfigConflictIndex(rpmfi fi, int ix) { char * fn = NULL; rpmfileAttrs flags = rpmfiFFlagsIndex(fi, ix); char buffer[1024]; rpmFileTypes newWhat, diskWhat; struct stat sb; int rc = 0; /* Non-configs are not config conflicts. */ if (!(flags & RPMFILE_CONFIG)) return 0; /* Only links and regular files can be %config, this is kinda moot */ /* XXX: Why are we returning 1 here? */ newWhat = rpmfiWhatis(rpmfiFModeIndex(fi, ix)); if (newWhat != LINK && newWhat != REG) return 1; /* If it's not on disk, there's nothing to be saved */ fn = rpmfiFNIndex(fi, ix); if (lstat(fn, &sb)) goto exit; /* * Preserve legacy behavior: an existing %ghost %config is considered * "modified" but unlike regular %config, its never removed and * never backed up. Whether this actually makes sense is a whole * another question, but this is very long-standing behavior that * people might be depending on. The resulting FA_ALTNAME etc action * is special-cased in FSM to avoid actually creating backups on ghosts. */ if (flags & RPMFILE_GHOST) { rc = 1; goto exit; } /* Files of different types obviously are not identical */ diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode); if (diskWhat != newWhat) { rc = 1; goto exit; } /* Files of different sizes obviously are not identical */ if (rpmfiFSizeIndex(fi, ix) != sb.st_size) { rc = 1; goto exit; } memset(buffer, 0, sizeof(buffer)); if (newWhat == REG) { int algo; size_t diglen; const unsigned char *ndigest = rpmfiFDigestIndex(fi,ix, &algo, &diglen); if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL)) goto exit; /* assume file has been removed */ if (ndigest && memcmp(ndigest, buffer, diglen) == 0) goto exit; /* unmodified config file */ } else /* newWhat == LINK */ { const char * nFLink; ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1); if (link_len == -1) goto exit; /* assume file has been removed */ buffer[link_len] = '\0'; nFLink = rpmfiFLinkIndex(fi, ix); if (nFLink && rstreq(nFLink, buffer)) goto exit; /* unmodified config file */ } rc = 1; exit: free(fn); return rc; }
rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix, int skipMissing) { char * fn = rpmfiFNIndex(nfi, nix); rpmfileAttrs newFlags = rpmfiFFlagsIndex(nfi, nix); char buffer[1024]; rpmFileTypes dbWhat, newWhat, diskWhat; struct stat sb; int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE; int action = FA_CREATE; /* assume we can create */ /* If the new file is a ghost, leave whatever might be on disk alone. */ if (newFlags & RPMFILE_GHOST) { action = FA_SKIP; goto exit; } 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); action = FA_SKIP; goto exit; } else { goto exit; } } diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode); dbWhat = rpmfiWhatis(rpmfiFModeIndex(ofi, oix)); newWhat = rpmfiWhatis(rpmfiFModeIndex(nfi, nix)); /* * This order matters - we'd prefer to CREATE the file if at all * possible in case something else (like the timestamp) has changed. * Only regular files and symlinks might need a backup, everything * else falls through here with FA_CREATE. */ memset(buffer, 0, sizeof(buffer)); if (dbWhat == REG) { int oalgo, nalgo; size_t odiglen, ndiglen; const unsigned char * odigest, * ndigest; /* See if the file on disk is identical to the one in old pkg */ odigest = rpmfiFDigestIndex(ofi, oix, &oalgo, &odiglen); if (diskWhat == REG) { if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL)) goto exit; /* assume file has been removed */ if (odigest && memcmp(odigest, buffer, odiglen) == 0) goto exit; /* unmodified config file, replace. */ } /* See if the file on disk is identical to the one in new pkg */ ndigest = rpmfiFDigestIndex(nfi, nix, &nalgo, &ndiglen); if (diskWhat == REG && newWhat == REG) { /* hash algo changed in new, recalculate digest */ if (oalgo != nalgo) if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL)) goto exit; /* assume file has been removed */ if (ndigest && memcmp(ndigest, buffer, ndiglen) == 0) goto exit; /* file identical in new, replace. */ } /* If file can be determined identical in old and new pkg, let it be */ if (newWhat == REG && oalgo == nalgo && odiglen == ndiglen) { if (odigest && ndigest && memcmp(odigest, ndigest, odiglen) == 0) { action = FA_SKIP; /* identical file, dont bother */ goto exit; } } /* ...but otherwise a backup will be needed */ action = save; } else if (dbWhat == LINK) { const char * oFLink, * nFLink; /* See if the link on disk is identical to the one in old pkg */ oFLink = rpmfiFLinkIndex(ofi, oix); if (diskWhat == LINK) { ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1); if (link_len == -1) goto exit; /* assume file has been removed */ buffer[link_len] = '\0'; if (oFLink && rstreq(oFLink, buffer)) goto exit; /* unmodified config file, replace. */ } /* See if the link on disk is identical to the one in new pkg */ nFLink = rpmfiFLinkIndex(nfi, nix); if (diskWhat == LINK && newWhat == LINK) { if (nFLink && rstreq(nFLink, buffer)) goto exit; /* unmodified config file, replace. */ } /* If link is identical in old and new pkg, let it be */ if (newWhat == LINK && oFLink && nFLink && rstreq(oFLink, nFLink)) { action = FA_SKIP; /* identical file, don't bother. */ goto exit; } /* ...but otherwise a backup will be needed */ action = save; } exit: free(fn); return action; }