[coreboot] Patch set updated: 7f65f07 Add POSIXy readdir/scandir support

Patrick Georgi (patrick@georgi-clan.de) gerrit at coreboot.org
Fri Sep 2 22:55:26 CEST 2011


Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/119

-gerrit

commit 7f65f079c80bf52ff9e2f12b3c118ad3dcb5647b
Author: Patrick Georgi <patrick.georgi at secunet.com>
Date:   Tue Jul 19 16:38:23 2011 +0200

    Add POSIXy readdir/scandir support
    
    This abuses the print_a_completion mechanism to build the right data
    structures to support opendir/readdir/closedir and scandir on top of
    them.
    
    It's BSD-licensed so it can eventually be moved over to libpayload.
    
    Change-Id: Iadc1daed3cab4cf2ead778c23ad756d36cbbb99a
    Signed-off-by: Patrick Georgi <patrick.georgi at secunet.com>
---
 fs/vfs.c                |  118 ++++++++++++++++++++++++++++++++++++++++++++++-
 include/dirent.h        |   28 +++++++++++
 include/grub/shared.h   |    2 +-
 main/grub/completions.c |   27 -----------
 4 files changed, 146 insertions(+), 29 deletions(-)

diff --git a/fs/vfs.c b/fs/vfs.c
index 49b38d8..18dbcbc 100644
--- a/fs/vfs.c
+++ b/fs/vfs.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include <fs.h>
 #include "filesys.h"
+#include <dirent.h>
 
 #define DEBUG_THIS CONFIG_DEBUG_VFS
 #include <debug.h>
@@ -241,7 +242,7 @@ void file_close(void)
 	devclose();
 }
 
-int dir(char *dirname)
+int dir(const char *dirname)
 {
 	char *dev = 0;
 	const char *path;
@@ -300,6 +301,8 @@ int dir(char *dirname)
 
 	retval = fsys->dir_func((char *) path);
 
+	print_possibilities = 0;
+
 out:
 	if (dev)
 		free(dev);
@@ -307,4 +310,117 @@ out:
 	return retval;
 }
 
+/* The following functions are BSD-L, Copyright 2011 secunet AG
+ * licensing is chosen to simplify migration to libpayload at some point */
+
+struct dirent **opendir_s;
+int opendir_ssize, opendir_selem;
+
+void print_a_completion(char *name)
+{
+	opendir_s[opendir_selem] = malloc(sizeof(struct dirent));
+	opendir_s[opendir_selem]->d_name = strdup(name);
+	opendir_selem++;
+	if (opendir_selem == opendir_ssize) {
+		opendir_ssize *= 2;
+		opendir_s = realloc(opendir_s, sizeof(struct dirent*)*opendir_ssize);
+	}
+	opendir_s[opendir_selem] = 0;
+}
+
+DIR *opendir(const char *path)
+{
+	DIR *p = malloc(sizeof(DIR));
+
+	if (opendir_s) free(opendir_s);
+	opendir_ssize = 32;
+	opendir_selem = 0;
+	opendir_s = malloc(sizeof(struct dirent*)*opendir_ssize);
+	dir(path);
+	p->items = opendir_s;
+	p->cur = opendir_s;
+	return p;
+}
+
+struct dirent *readdir(DIR *dirp)
+{
+	if (NULL == *dirp->cur) return NULL;
+
+	return *(dirp->cur++);
+}
+
+int closedir(DIR *dirp)
+{
+	if (!dirp) return -1;
+
+	struct dirent **cur = dirp->items;
+	while (*cur) {
+		free(*cur);
+		cur++;
+	}
+	free(dirp->items);
+	free(dirp);
+
+	return 0;
+}
+
+static int (*metafilter_flt)(const struct dirent *);
+static int (*metafilter_cmp)(const struct dirent **, const struct dirent **);
+
+static int metafilter(const struct dirent **a, const struct dirent **b)
+{
+	/* make sure that filtered out entries end up at the end, for simple elimination */
+	if ((metafilter_flt(*a) == 0) && (metafilter_flt(*b) == 0))
+		return 0;
+	if (metafilter_flt(*a) == 0)
+		return 1;
+	if (metafilter_flt(*b) == 0)
+		return -1;
+	return metafilter_cmp(a, b);
+}
+
+int scandir(const char *path, struct dirent ***namelist,
+	int (*filter)(const struct dirent *),
+	int (*compar)(const struct dirent **, const struct dirent **))
+{
+	DIR *dirp = opendir(path);
+
+	struct dirent **e = dirp->items;
+	int nelem = 0;
+	while (*e) {
+		nelem++;
+		e++;
+	}
+
+	if (filter) {
+		metafilter_flt = filter;
+		metafilter_cmp = compar;
+		compar = metafilter;
+	}
+
+	*namelist = malloc(sizeof(struct dirent*)*nelem);
+	memcpy(*namelist, dirp->items, sizeof(struct dirent*)*nelem);
+	qsort(*namelist, nelem, sizeof(struct dirent*), (int(*)(const void*, const void*))compar);
+
+	// if things were filtered, truncate them away
+	if (filter) {
+		int nelem2;
+		e = *namelist;
+		nelem2 = 0;
+		while ((nelem > nelem2) && filter(*e)) {
+			nelem2++;
+			e++;
+		}
+		realloc(namelist, sizeof(struct dirent**)*nelem2);
+	}
+
+	return nelem;
+}
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+	const struct dirent *a1 = *(const struct dirent **)(a);
+	const struct dirent *b1 = *(const struct dirent **)(b);
+	return strcmp(a1->d_name, b1->d_name);
+}
 
diff --git a/include/dirent.h b/include/dirent.h
new file mode 100644
index 0000000..19b3696
--- /dev/null
+++ b/include/dirent.h
@@ -0,0 +1,28 @@
+/* Copyright 2011 secunet AG
+ * written by Patrick Georgi <patrick.georgi at secunet.com>
+ *
+ * Licensed as BSD-L to ease migration to libpayload */
+
+#ifndef __DIRENT_H
+#define __DIRENT_H
+struct dirent {
+	char *d_name;
+};
+
+typedef struct {
+	struct dirent **items;
+	struct dirent **cur;
+} DIR;
+
+DIR *opendir(const char *path);
+struct dirent *readdir(DIR *dirp);
+int closedir(DIR *dirp); // 0 on success, -1 on error, with errno set
+
+int scandir(const char *path, struct dirent ***namelist,
+		int (*filter)(const struct dirent *),
+		int (*compar)(const struct dirent **, const struct dirent **));
+
+int alphasort(const struct dirent **a, const struct dirent **b);
+
+#endif
+
diff --git a/include/grub/shared.h b/include/grub/shared.h
index 8d876de..127b74f 100644
--- a/include/grub/shared.h
+++ b/include/grub/shared.h
@@ -295,7 +295,7 @@ void grub_putstr (const char *str);
 
 /* List the contents of the directory that was opened with GRUB_OPEN,
    printing all completions. */
-int dir (char *dirname);
+int dir (const char *dirname);
 
 /* Display device and filename completions. */
 void print_a_completion (char *filename);
diff --git a/main/grub/completions.c b/main/grub/completions.c
index 6588301..161026b 100644
--- a/main/grub/completions.c
+++ b/main/grub/completions.c
@@ -64,33 +64,6 @@ set_device (char *device)
 	return 0;
 }
 
-/* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
-   part into UNIQUE_STRING.  */
-void print_a_completion(char *name)
-{
-	/* If NAME is "." or "..", do not count it.  */
-	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-		return;
-
-	if (do_completion) {
-		char *buf = unique_string;
-
-		if (!unique)
-			while ((*buf++ = *name++));
-		else {
-			while (*buf && (*buf == *name)) {
-				buf++;
-				name++;
-			}
-			/* mismatch, strip it.  */
-			*buf = '\0';
-		}
-	} else
-		grub_printf(" %s", name);
-
-	unique++;
-}
-
 /*
  *  This lists the possible completions of a device string, filename, or
  *  any sane combination of the two.




More information about the coreboot mailing list