[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