summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2012-08-22 12:40:00 +0300
committerPanu Matilainen <pmatilai@redhat.com>2012-10-03 10:17:05 +0300
commitf2719855ecfb0fa19253daee20c3c3d0ac95af9f (patch)
treebacbe6a225397dfc9b60f3579264d9b114579050
parent46357627706b19cd0f80707944444b539b83fdad (diff)
downloadrpm-f2719855ecfb0fa19253daee20c3c3d0ac95af9f.tar.gz
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. - Backported from commit 80ee39da35544253cab12abd54af8754335ac945
-rw-r--r--lib/rpmfi.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index 40162023f..34d8e2780 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -677,24 +677,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) {
@@ -702,21 +711,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))
- 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)