The following commit has been merged in the master branch:
commit 365611d9f86e1da98007e5b3b3a14dfea2d5acda
Author: Guillem Jover <[email protected]>
Date: Mon Nov 9 19:06:18 2009 +0100
libcompat: Fix resource leaks on error conditions in scandir
diff --git a/TODO b/TODO
index e8b640b..84693f7 100644
--- a/TODO
+++ b/TODO
@@ -56,7 +56,6 @@ TODO
* Cleanup libcompat:
- Add fnmatch, IRIX5 doesn't have it.
- - Fix scandir, leaks on malloc and realloc.
* Man pages:
- Add example to dpkg-scanfoo manpages?
diff --git a/lib/compat/scandir.c b/lib/compat/scandir.c
index 95b4808..2fc8d01 100644
--- a/lib/compat/scandir.c
+++ b/lib/compat/scandir.c
@@ -2,6 +2,7 @@
* libcompat - system compatibility library
*
* Copyright © 1995 Ian Jackson <[email protected]>
+ * Copyright © 2008, 2009 Guillem Jover <[email protected]>
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,14 +27,31 @@
#include <stdlib.h>
#ifndef HAVE_SCANDIR
+static int
+cleanup(DIR *dir, struct dirent **dirlist, int used)
+{
+ if (dir)
+ closedir(dir);
+
+ if (dirlist) {
+ int i;
+
+ for (i = 0; i < used; i++)
+ free(dirlist[i]);
+ free(dirlist);
+ }
+
+ return -1;
+}
+
int
scandir(const char *dir, struct dirent ***namelist,
int (*filter)(const struct dirent *),
int (*cmp)(const void *, const void *))
{
DIR *d;
+ struct dirent *e, *m, **list;
int used, avail;
- struct dirent *e, *m;
d = opendir(dir);
if (!d)
@@ -42,34 +60,40 @@ scandir(const char *dir, struct dirent ***namelist,
used = 0;
avail = 20;
- *namelist = malloc(avail * sizeof(struct dirent *));
- if (!*namelist)
- return -1;
+ list = malloc(avail * sizeof(struct dirent *));
+ if (!list)
+ return cleanup(d, list, used);
while ((e = readdir(d)) != NULL) {
if (filter != NULL && !filter(e))
continue;
+ if (used >= avail - 1) {
+ struct dirent **newlist;
+
+ avail += avail;
+ newlist = realloc(list, avail * sizeof(struct dirent
*));
+ if (!newlist)
+ return cleanup(d, list, used);
+ }
+
m = malloc(sizeof(struct dirent) + strlen(e->d_name));
if (!m)
- return -1;
+ return cleanup(d, list, used);
*m = *e;
strcpy(m->d_name, e->d_name);
- if (used >= avail - 1) {
- avail += avail;
- *namelist = realloc(*namelist, avail * sizeof(struct
dirent *));
- if (!*namelist)
- return -1;
- }
-
- (*namelist)[used] = m;
+ list[used] = m;
used++;
}
- (*namelist)[used] = NULL;
+ list[used] = NULL;
+
+ closedir(d);
if (cmp != NULL)
- qsort(*namelist, used, sizeof(struct dirent *), cmp);
+ qsort(list, used, sizeof(struct dirent *), cmp);
+
+ *namelist = list;
return used;
}
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]