Patrick Georgi (patrick@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@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@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@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.