summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2012-08-22 12:40:00 +0300
committerPanu Matilainen <pmatilai@redhat.com>2012-08-22 12:43:20 +0300
commit80ee39da35544253cab12abd54af8754335ac945 (patch)
tree808f41ea4df7d5e9453fef4d27e6924f4e3f67cf /lib
parenta3a08a4b0aa96ae03c33050920baf894cc706c9e (diff)
downloadrpm-80ee39da35544253cab12abd54af8754335ac945.tar.gz
rpm-80ee39da35544253cab12abd54af8754335ac945.tar.bz2
rpm-80ee39da35544253cab12abd54af8754335ac945.zip
Fix a massive memleak from rpmfiConfigConflictIndex() and optimize it
- rpmfiFNIndex() returns a malloced string since commit 11116a67864c119e420297984bd9ec4b83fdadd7 but this wasn't taken into account in commit 3f996a588a56141df146c33583a13c0542323977, causing a massive memory leak on transaction preparations. - Optimize the entry by avoiding rpmfiFNIndex() and lstat() until really necessary, and use a central exit point beyond that so we can free fn. Besides fixing the memleak, this gives a small but measurable performance improvement on this rather busy path.
Diffstat (limited to 'lib')
-rw-r--r--lib/rpmfi.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index ea1769650..afc115f67 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -703,24 +703,33 @@ rpmFileAction rpmfiDecideFateIndex(rpmfi ofi, int oix, rpmfi nfi, int nix,
int rpmfiConfigConflictIndex(rpmfi fi, int ix)
{
- const char * fn = rpmfiFNIndex(fi, ix);
+ char * fn = NULL;
rpmfileAttrs flags = rpmfiFFlagsIndex(fi, ix);
char buffer[1024];
rpmFileTypes newWhat, diskWhat;
struct stat sb;
+ int rc = 0;
- if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
+ if (!(flags & RPMFILE_CONFIG))
return 0;
- }
- diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
+ /* 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 (diskWhat != newWhat)
- return 1;
+ /* If it's not on disk, there's nothing to be saved */
+ fn = rpmfiFNIndex(fi, ix);
+ if (lstat(fn, &sb))
+ 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;
+ }
memset(buffer, 0, sizeof(buffer));
if (newWhat == REG) {
@@ -728,21 +737,25 @@ int rpmfiConfigConflictIndex(rpmfi fi, int ix)
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 */
+ goto exit; /* assume file has been removed */
if (ndigest && memcmp(ndigest, buffer, diglen) == 0)
- return 0; /* unmodified config file */
+ 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)
- return 0; /* assume file has been removed */
+ goto exit; /* assume file has been removed */
buffer[link_len] = '\0';
nFLink = rpmfiFLinkIndex(fi, ix);
if (nFLink && rstreq(nFLink, buffer))
- return 0; /* unmodified config file */
+ goto exit; /* unmodified config file */
}
- return 1;
+ rc = 1;
+
+exit:
+ free(fn);
+ return rc;
}
static char **duparray(char ** src, int size)