summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2009-09-25 14:40:23 +0200
committerKarel Zak <kzak@redhat.com>2009-09-25 14:57:17 +0200
commitf38fd19d2b0367f5f4517ba30a8964802c7ce1ab (patch)
treea0c3e7083307ef5ef708d6e1f234e4691058ca4b
parent0d17b1cf91f5c1a41660e8f240f9ff11259fcf1a (diff)
downloadutil-linux-old-f38fd19d2b0367f5f4517ba30a8964802c7ce1ab.tar.gz
libblkid: use fstatat(), improve readdir() usage
* fix possible memory leak in ubi_probe_all() * use dirent->d_type if available (this is tricky, because d_type is not supported on all systems and some filesystems returns DT_UNKNOWN). The dirent->d_type allows to avoid unnecessary stat() calls. * use fstatat() if available -- allows to avoid malloc() and sprintf("%s/%s", dirname, dirent->d_name) Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--TODO2
-rw-r--r--shlibs/blkid/src/blkidP.h5
-rw-r--r--shlibs/blkid/src/devname.c34
-rw-r--r--shlibs/blkid/src/devno.c96
4 files changed, 100 insertions, 37 deletions
diff --git a/TODO b/TODO
index 44fb2f85..bf2c5f9a 100644
--- a/TODO
+++ b/TODO
@@ -26,8 +26,6 @@ libblkid
[ -- Christoph Hellwig, 16 Feb 2009 ]
(1) http://git.kernel.org/?p=fs/xfs/xfsprogs-dev.git;a=tree;f=libdisk;
- - use fstatat() in blkid__scan_dir()
-
- add values:
FSSIZE -- filesystem size (klibc requirement)
diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h
index 68116c0c..d09529ef 100644
--- a/shlibs/blkid/src/blkidP.h
+++ b/shlibs/blkid/src/blkidP.h
@@ -17,6 +17,8 @@
#define CONFIG_BLKID_DEBUG 1
#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <stdarg.h>
@@ -279,6 +281,9 @@ struct blkid_struct_cache
extern char *blkid_strdup(const char *s);
extern char *blkid_strndup(const char *s, const int length);
+extern char *blkid_strconcat(const char *a, const char *b, const char *c);
+extern int blkid_fstatat(DIR *dir, const char *dirname, const char *filename,
+ struct stat *st, int nofollow);
#define BLKID_CACHE_FILE "/etc/blkid.tab"
#define BLKID_CONFIG_FILE "/etc/blkid.conf"
diff --git a/shlibs/blkid/src/devname.c b/shlibs/blkid/src/devname.c
index 1acb9d5a..fe0d1b33 100644
--- a/shlibs/blkid/src/devname.c
+++ b/shlibs/blkid/src/devname.c
@@ -407,35 +407,31 @@ ubi_probe_all(blkid_cache cache, int only_if_new)
continue ;
while ((iter = readdir(dir)) != NULL) {
- char *name, *device;
+ char *name;
struct stat st;
dev_t dev;
name = iter->d_name;
-
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (iter->d_type != DT_UNKNOWN &&
+ iter->d_type != DT_CHR && iter->d_type != DT_LNK)
+ continue;
+#endif
if (!strcmp(name, ".") || !strcmp(name, "..") ||
!strstr(name, "ubi"))
continue;
if (!strcmp(name, "ubi_ctrl"))
continue;
- device = malloc(strlen(*dirname) + strlen(name) + 2);
- if (!device)
- break ;
- sprintf(device, "%s/%s", *dirname, name);
- if (stat(device, &st))
- break ;
-
- if (!(st.st_rdev & 0xFF)) { // It's an UBI Device
- free(device);
- continue ;
- }
+ if (blkid_fstatat(dir, *dirname, name, &st, 0))
+ continue;
+
dev = st.st_rdev;
- DBG(DEBUG_DEVNAME, printf("UBI vol %s: devno 0x%04X\n",
- device,
- (int) dev));
- probe_one(cache, name, dev, BLKID_PRI_UBI,
- only_if_new);
- free(device);
+
+ if (!S_ISCHR(st.st_mode) || !minor(dev))
+ continue;
+ DBG(DEBUG_DEVNAME, printf("UBI vol %s/%s: devno 0x%04X\n",
+ *dirname, name, (int) dev));
+ probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new);
}
closedir(dir);
}
diff --git a/shlibs/blkid/src/devno.c b/shlibs/blkid/src/devno.c
index 8518f9fd..11f212ef 100644
--- a/shlibs/blkid/src/devno.c
+++ b/shlibs/blkid/src/devno.c
@@ -30,6 +30,7 @@
#if HAVE_SYS_MKDEV_H
#include <sys/mkdev.h>
#endif
+#include <fcntl.h>
#include "blkidP.h"
#include "pathnames.h"
@@ -57,17 +58,68 @@ char *blkid_strdup(const char *s)
return blkid_strndup(s, 0);
}
+char *blkid_strconcat(const char *a, const char *b, const char *c)
+{
+ char *res, *p;
+ size_t len, al, bl, cl;
+
+ al = a ? strlen(a) : 0;
+ bl = b ? strlen(b) : 0;
+ cl = c ? strlen(c) : 0;
+
+ len = al + bl + cl;
+ if (!len)
+ return NULL;
+ p = res = malloc(len + 1);
+ if (!res)
+ return NULL;
+ if (al) {
+ memcpy(p, a, al);
+ p += al;
+ }
+ if (bl) {
+ memcpy(p, b, bl);
+ p += bl;
+ }
+ if (cl) {
+ memcpy(p, c, cl);
+ p += cl;
+ }
+ *p = '\0';
+ return res;
+}
+
+int blkid_fstatat(DIR *dir, const char *dirname, const char *filename,
+ struct stat *st, int nofollow)
+{
+#ifdef HAVE_FSTATAT
+ return fstatat(dirfd(dir), filename, st,
+ nofollow ? AT_SYMLINK_NOFOLLOW : 0);
+#else
+ char device[PATH_MAX];
+ int len;
+
+ len = snprintf(device, sizeof(device), "%s/%s", *dirname, name);
+ if (len < 0 || len + 1 > sizeof(path))
+ return -1;
+
+ return nofollow ? lstat(device, st) : stat(device, st);
+#endif
+}
+
/*
* This function adds an entry to the directory list
*/
-static void add_to_dirlist(const char *name, struct dir_list **list)
+static void add_to_dirlist(const char *dir, const char *subdir,
+ struct dir_list **list)
{
struct dir_list *dp;
dp = malloc(sizeof(struct dir_list));
if (!dp)
return;
- dp->name = blkid_strdup(name);
+ dp->name = subdir ? blkid_strconcat(dir, "/", subdir) :
+ blkid_strdup(dir);
if (!dp->name) {
free(dp);
return;
@@ -96,36 +148,48 @@ void blkid__scan_dir(char *dirname, dev_t devno, struct dir_list **list,
{
DIR *dir;
struct dirent *dp;
- char path[1024];
- int dirlen;
struct stat st;
if ((dir = opendir(dirname)) == NULL)
return;
- dirlen = strlen(dirname) + 2;
+
while ((dp = readdir(dir)) != 0) {
- if (dirlen + strlen(dp->d_name) >= sizeof(path))
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_BLK &&
+ dp->d_type != DT_LNK && dp->d_type != DT_DIR)
continue;
-
+#endif
if (dp->d_name[0] == '.' &&
((dp->d_name[1] == 0) ||
((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
continue;
- sprintf(path, "%s/%s", dirname, dp->d_name);
- if (stat(path, &st) < 0)
+ if (blkid_fstatat(dir, dirname, dp->d_name, &st, 0))
continue;
if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
- *devname = blkid_strdup(path);
+ *devname = blkid_strconcat(dirname, "/", dp->d_name);
DBG(DEBUG_DEVNO,
- printf("found 0x%llx at %s (%p)\n", (long long)devno,
- path, *devname));
+ printf("found 0x%llx at %s\n", (long long)devno,
+ *devname));
break;
}
- if (list && S_ISDIR(st.st_mode) && !lstat(path, &st) &&
- S_ISDIR(st.st_mode))
- add_to_dirlist(path, list);
+
+ if (!list || !S_ISDIR(st.st_mode))
+ continue;
+
+ /* add subdirectory (but not symlink) to the list */
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (dp->d_type == DT_LNK)
+ continue;
+ if (dp->d_type == DT_UNKNOWN)
+#endif
+ {
+ if (blkid_fstatat(dir, dirname, dp->d_name, &st, 1) ||
+ !S_ISDIR(st.st_mode))
+ continue; /* symlink or lstat() failed */
+ }
+ add_to_dirlist(dirname, dp->d_name, list);
}
closedir(dir);
return;
@@ -161,7 +225,7 @@ char *blkid_devno_to_devname(dev_t devno)
* importance, since we are using a stack...
*/
for (dir = devdirs; *dir; dir++)
- add_to_dirlist(*dir, &list);
+ add_to_dirlist(*dir, NULL, &list);
while (list) {
struct dir_list *current = list;