Remove nested functions from filesystem directory iterators.

* include/grub/fs.h (grub_fs_dir_hook_t): New type.
(struct grub_fs.dir): Add hook_data argument.

Update all implementations and callers.
This commit is contained in:
Colin Watson 2013-01-21 01:33:46 +00:00
parent 53d3e4e3df
commit fc524edf65
35 changed files with 1723 additions and 1451 deletions

View file

@ -1,3 +1,12 @@
2013-01-21 Colin Watson <cjwatson@ubuntu.com>
Remove nested functions from filesystem directory iterators.
* include/grub/fs.h (grub_fs_dir_hook_t): New type.
(struct grub_fs.dir): Add hook_data argument.
Update all implementations and callers.
2013-01-21 Colin Watson <cjwatson@ubuntu.com> 2013-01-21 Colin Watson <cjwatson@ubuntu.com>
* docs/grub.texi (Multi-boot manual config): Fix typo for * docs/grub.texi (Multi-boot manual config): Fix typo for

View file

@ -85,6 +85,119 @@ grub_ls_list_devices (int longlist)
return 0; return 0;
} }
/* Context for grub_ls_list_files. */
struct grub_ls_list_files_ctx
{
char *dirname;
int all;
int human;
};
/* Helper for grub_ls_list_files. */
static int
print_files (const char *filename, const struct grub_dirhook_info *info,
void *data)
{
struct grub_ls_list_files_ctx *ctx = data;
if (ctx->all || filename[0] != '.')
grub_printf ("%s%s ", filename, info->dir ? "/" : "");
return 0;
}
/* Helper for grub_ls_list_files. */
static int
print_files_long (const char *filename, const struct grub_dirhook_info *info,
void *data)
{
struct grub_ls_list_files_ctx *ctx = data;
if ((! ctx->all) && (filename[0] == '.'))
return 0;
if (! info->dir)
{
grub_file_t file;
char *pathname;
if (ctx->dirname[grub_strlen (ctx->dirname) - 1] == '/')
pathname = grub_xasprintf ("%s%s", ctx->dirname, filename);
else
pathname = grub_xasprintf ("%s/%s", ctx->dirname, filename);
if (!pathname)
return 1;
/* XXX: For ext2fs symlinks are detected as files while they
should be reported as directories. */
grub_file_filter_disable_compression ();
file = grub_file_open (pathname);
if (! file)
{
grub_errno = 0;
grub_free (pathname);
return 0;
}
if (! ctx->human)
grub_printf ("%-12llu", (unsigned long long) file->size);
else
{
grub_uint64_t fsize = file->size * 100ULL;
grub_uint64_t fsz = file->size;
int units = 0;
char buf[20];
while (fsz / 1024)
{
fsize = (fsize + 512) / 1024;
fsz /= 1024;
units++;
}
if (units)
{
grub_uint64_t whole, fraction;
whole = grub_divmod64 (fsize, 100, &fraction);
grub_snprintf (buf, sizeof (buf),
"%" PRIuGRUB_UINT64_T
".%02" PRIuGRUB_UINT64_T "%c", whole, fraction,
grub_human_sizes[units]);
grub_printf ("%-12s", buf);
}
else
grub_printf ("%-12llu", (unsigned long long) file->size);
}
grub_file_close (file);
grub_free (pathname);
}
else
grub_printf ("%-12s", _("DIR"));
if (info->mtimeset)
{
struct grub_datetime datetime;
grub_unixtime2datetime (info->mtime, &datetime);
if (ctx->human)
grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute,
datetime.second,
grub_get_weekday_name (&datetime));
else
grub_printf (" %04d%02d%02d%02d%02d%02d ",
datetime.year, datetime.month,
datetime.day, datetime.hour,
datetime.minute, datetime.second);
}
grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
return 0;
}
static grub_err_t static grub_err_t
grub_ls_list_files (char *dirname, int longlist, int all, int human) grub_ls_list_files (char *dirname, int longlist, int all, int human)
{ {
@ -93,107 +206,6 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
const char *path; const char *path;
grub_device_t dev; grub_device_t dev;
auto int print_files (const char *filename,
const struct grub_dirhook_info *info);
auto int print_files_long (const char *filename,
const struct grub_dirhook_info *info);
int print_files (const char *filename, const struct grub_dirhook_info *info)
{
if (all || filename[0] != '.')
grub_printf ("%s%s ", filename, info->dir ? "/" : "");
return 0;
}
int print_files_long (const char *filename,
const struct grub_dirhook_info *info)
{
if ((! all) && (filename[0] == '.'))
return 0;
if (! info->dir)
{
grub_file_t file;
char *pathname;
if (dirname[grub_strlen (dirname) - 1] == '/')
pathname = grub_xasprintf ("%s%s", dirname, filename);
else
pathname = grub_xasprintf ("%s/%s", dirname, filename);
if (!pathname)
return 1;
/* XXX: For ext2fs symlinks are detected as files while they
should be reported as directories. */
grub_file_filter_disable_compression ();
file = grub_file_open (pathname);
if (! file)
{
grub_errno = 0;
grub_free (pathname);
return 0;
}
if (! human)
grub_printf ("%-12llu", (unsigned long long) file->size);
else
{
grub_uint64_t fsize = file->size * 100ULL;
grub_uint64_t fsz = file->size;
int units = 0;
char buf[20];
while (fsz / 1024)
{
fsize = (fsize + 512) / 1024;
fsz /= 1024;
units++;
}
if (units)
{
grub_uint64_t whole, fraction;
whole = grub_divmod64 (fsize, 100, &fraction);
grub_snprintf (buf, sizeof (buf),
"%" PRIuGRUB_UINT64_T
".%02" PRIuGRUB_UINT64_T "%c", whole, fraction,
grub_human_sizes[units]);
grub_printf ("%-12s", buf);
}
else
grub_printf ("%-12llu", (unsigned long long) file->size);
}
grub_file_close (file);
grub_free (pathname);
}
else
grub_printf ("%-12s", _("DIR"));
if (info->mtimeset)
{
struct grub_datetime datetime;
grub_unixtime2datetime (info->mtime, &datetime);
if (human)
grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute,
datetime.second,
grub_get_weekday_name (&datetime));
else
grub_printf (" %04d%02d%02d%02d%02d%02d ",
datetime.year, datetime.month,
datetime.day, datetime.hour,
datetime.minute, datetime.second);
}
grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
return 0;
}
device_name = grub_file_get_device_name (dirname); device_name = grub_file_get_device_name (dirname);
dev = grub_device_open (device_name); dev = grub_device_open (device_name);
if (! dev) if (! dev)
@ -221,10 +233,16 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
} }
else if (fs) else if (fs)
{ {
struct grub_ls_list_files_ctx ctx = {
.dirname = dirname,
.all = all,
.human = human
};
if (longlist) if (longlist)
(fs->dir) (dev, path, print_files_long); (fs->dir) (dev, path, print_files_long, &ctx);
else else
(fs->dir) (dev, path, print_files); (fs->dir) (dev, path, print_files, &ctx);
if (grub_errno == GRUB_ERR_BAD_FILE_TYPE if (grub_errno == GRUB_ERR_BAD_FILE_TYPE
&& path[grub_strlen (path) - 1] != '/') && path[grub_strlen (path) - 1] != '/')
@ -250,9 +268,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
all = 1; all = 1;
grub_memset (&info, 0, sizeof (info)); grub_memset (&info, 0, sizeof (info));
if (longlist) if (longlist)
print_files_long (p, &info); print_files_long (p, &info, &ctx);
else else
print_files (p, &info); print_files (p, &info, &ctx);
grub_free (dirname); grub_free (dirname);
} }

View file

@ -38,114 +38,125 @@ grub_strtosl (char *arg, char **end, int base)
return grub_strtoul (arg, end, base); return grub_strtoul (arg, end, base);
} }
/* Context for test_parse. */
struct test_parse_ctx
{
int ret, discard, invert;
int file_exists;
struct grub_dirhook_info file_info;
char *filename;
};
/* Take care of discarding and inverting. */
static void
update_val (int val, struct test_parse_ctx *ctx)
{
if (! ctx->discard)
ctx->ret = ctx->invert ? ! val : val;
ctx->invert = ctx->discard = 0;
}
/* A hook for iterating directories. */
static int
find_file (const char *cur_filename, const struct grub_dirhook_info *info,
void *data)
{
struct test_parse_ctx *ctx = data;
if ((info->case_insensitive ? grub_strcasecmp (cur_filename, ctx->filename)
: grub_strcmp (cur_filename, ctx->filename)) == 0)
{
ctx->file_info = *info;
ctx->file_exists = 1;
return 1;
}
return 0;
}
/* Check if file exists and fetch its information. */
static void
get_fileinfo (char *path, struct test_parse_ctx *ctx)
{
char *pathname;
char *device_name;
grub_fs_t fs;
grub_device_t dev;
ctx->file_exists = 0;
device_name = grub_file_get_device_name (path);
dev = grub_device_open (device_name);
if (! dev)
{
grub_free (device_name);
return;
}
fs = grub_fs_probe (dev);
if (! fs)
{
grub_free (device_name);
grub_device_close (dev);
return;
}
pathname = grub_strchr (path, ')');
if (! pathname)
pathname = path;
else
pathname++;
/* Remove trailing '/'. */
while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
pathname[grub_strlen (pathname) - 1] = 0;
/* Split into path and filename. */
ctx->filename = grub_strrchr (pathname, '/');
if (! ctx->filename)
{
path = grub_strdup ("/");
ctx->filename = pathname;
}
else
{
ctx->filename++;
path = grub_strdup (pathname);
path[ctx->filename - pathname] = 0;
}
/* It's the whole device. */
if (! *pathname)
{
ctx->file_exists = 1;
grub_memset (&ctx->file_info, 0, sizeof (ctx->file_info));
/* Root is always a directory. */
ctx->file_info.dir = 1;
/* Fetch writing time. */
ctx->file_info.mtimeset = 0;
if (fs->mtime)
{
if (! fs->mtime (dev, &ctx->file_info.mtime))
ctx->file_info.mtimeset = 1;
grub_errno = GRUB_ERR_NONE;
}
}
else
(fs->dir) (dev, path, find_file, ctx);
grub_device_close (dev);
grub_free (path);
grub_free (device_name);
}
/* Parse a test expression starting from *argn. */ /* Parse a test expression starting from *argn. */
static int static int
test_parse (char **args, int *argn, int argc) test_parse (char **args, int *argn, int argc)
{ {
int ret = 0, discard = 0, invert = 0; struct test_parse_ctx ctx = {
int file_exists; .ret = 0,
struct grub_dirhook_info file_info; .discard = 0,
.invert = 0
auto void update_val (int val); };
auto void get_fileinfo (char *pathname);
/* Take care of discarding and inverting. */
void update_val (int val)
{
if (! discard)
ret = invert ? ! val : val;
invert = discard = 0;
}
/* Check if file exists and fetch its information. */
void get_fileinfo (char *path)
{
char *filename, *pathname;
char *device_name;
grub_fs_t fs;
grub_device_t dev;
/* A hook for iterating directories. */
auto int find_file (const char *cur_filename,
const struct grub_dirhook_info *info);
int find_file (const char *cur_filename,
const struct grub_dirhook_info *info)
{
if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename)
: grub_strcmp (cur_filename, filename)) == 0)
{
file_info = *info;
file_exists = 1;
return 1;
}
return 0;
}
file_exists = 0;
device_name = grub_file_get_device_name (path);
dev = grub_device_open (device_name);
if (! dev)
{
grub_free (device_name);
return;
}
fs = grub_fs_probe (dev);
if (! fs)
{
grub_free (device_name);
grub_device_close (dev);
return;
}
pathname = grub_strchr (path, ')');
if (! pathname)
pathname = path;
else
pathname++;
/* Remove trailing '/'. */
while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
pathname[grub_strlen (pathname) - 1] = 0;
/* Split into path and filename. */
filename = grub_strrchr (pathname, '/');
if (! filename)
{
path = grub_strdup ("/");
filename = pathname;
}
else
{
filename++;
path = grub_strdup (pathname);
path[filename - pathname] = 0;
}
/* It's the whole device. */
if (! *pathname)
{
file_exists = 1;
grub_memset (&file_info, 0, sizeof (file_info));
/* Root is always a directory. */
file_info.dir = 1;
/* Fetch writing time. */
file_info.mtimeset = 0;
if (fs->mtime)
{
if (! fs->mtime (dev, &file_info.mtime))
file_info.mtimeset = 1;
grub_errno = GRUB_ERR_NONE;
}
}
else
(fs->dir) (dev, path, find_file);
grub_device_close (dev);
grub_free (path);
grub_free (device_name);
}
/* Here we have the real parsing. */ /* Here we have the real parsing. */
while (*argn < argc) while (*argn < argc)
@ -157,14 +168,16 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "=") == 0 if (grub_strcmp (args[*argn + 1], "=") == 0
|| grub_strcmp (args[*argn + 1], "==") == 0) || grub_strcmp (args[*argn + 1], "==") == 0)
{ {
update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0); update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0,
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
if (grub_strcmp (args[*argn + 1], "!=") == 0) if (grub_strcmp (args[*argn + 1], "!=") == 0)
{ {
update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0); update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0,
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -172,28 +185,32 @@ test_parse (char **args, int *argn, int argc)
/* GRUB extension: lexicographical sorting. */ /* GRUB extension: lexicographical sorting. */
if (grub_strcmp (args[*argn + 1], "<") == 0) if (grub_strcmp (args[*argn + 1], "<") == 0)
{ {
update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0); update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0,
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
if (grub_strcmp (args[*argn + 1], "<=") == 0) if (grub_strcmp (args[*argn + 1], "<=") == 0)
{ {
update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0); update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0,
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
if (grub_strcmp (args[*argn + 1], ">") == 0) if (grub_strcmp (args[*argn + 1], ">") == 0)
{ {
update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0); update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0,
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
if (grub_strcmp (args[*argn + 1], ">=") == 0) if (grub_strcmp (args[*argn + 1], ">=") == 0)
{ {
update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0); update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0,
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -202,7 +219,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-eq") == 0) if (grub_strcmp (args[*argn + 1], "-eq") == 0)
{ {
update_val (grub_strtosl (args[*argn], 0, 0) update_val (grub_strtosl (args[*argn], 0, 0)
== grub_strtosl (args[*argn + 2], 0, 0)); == grub_strtosl (args[*argn + 2], 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -210,7 +227,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-ge") == 0) if (grub_strcmp (args[*argn + 1], "-ge") == 0)
{ {
update_val (grub_strtosl (args[*argn], 0, 0) update_val (grub_strtosl (args[*argn], 0, 0)
>= grub_strtosl (args[*argn + 2], 0, 0)); >= grub_strtosl (args[*argn + 2], 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -218,7 +235,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-gt") == 0) if (grub_strcmp (args[*argn + 1], "-gt") == 0)
{ {
update_val (grub_strtosl (args[*argn], 0, 0) update_val (grub_strtosl (args[*argn], 0, 0)
> grub_strtosl (args[*argn + 2], 0, 0)); > grub_strtosl (args[*argn + 2], 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -226,7 +243,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-le") == 0) if (grub_strcmp (args[*argn + 1], "-le") == 0)
{ {
update_val (grub_strtosl (args[*argn], 0, 0) update_val (grub_strtosl (args[*argn], 0, 0)
<= grub_strtosl (args[*argn + 2], 0, 0)); <= grub_strtosl (args[*argn + 2], 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -234,7 +251,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-lt") == 0) if (grub_strcmp (args[*argn + 1], "-lt") == 0)
{ {
update_val (grub_strtosl (args[*argn], 0, 0) update_val (grub_strtosl (args[*argn], 0, 0)
< grub_strtosl (args[*argn + 2], 0, 0)); < grub_strtosl (args[*argn + 2], 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -242,7 +259,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-ne") == 0) if (grub_strcmp (args[*argn + 1], "-ne") == 0)
{ {
update_val (grub_strtosl (args[*argn], 0, 0) update_val (grub_strtosl (args[*argn], 0, 0)
!= grub_strtosl (args[*argn + 2], 0, 0)); != grub_strtosl (args[*argn + 2], 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -265,10 +282,10 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn + 1], "-pgt") == 0) if (grub_strcmp (args[*argn + 1], "-pgt") == 0)
update_val (grub_strtoul (args[*argn] + i, 0, 0) update_val (grub_strtoul (args[*argn] + i, 0, 0)
> grub_strtoul (args[*argn + 2] + i, 0, 0)); > grub_strtoul (args[*argn + 2] + i, 0, 0), &ctx);
else else
update_val (grub_strtoul (args[*argn] + i, 0, 0) update_val (grub_strtoul (args[*argn] + i, 0, 0)
< grub_strtoul (args[*argn + 2] + i, 0, 0)); < grub_strtoul (args[*argn + 2] + i, 0, 0), &ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -283,22 +300,24 @@ test_parse (char **args, int *argn, int argc)
int bias = 0; int bias = 0;
/* Fetch fileinfo. */ /* Fetch fileinfo. */
get_fileinfo (args[*argn]); get_fileinfo (args[*argn], &ctx);
file1 = file_info; file1 = ctx.file_info;
file1exists = file_exists; file1exists = ctx.file_exists;
get_fileinfo (args[*argn + 2]); get_fileinfo (args[*argn + 2], &ctx);
if (args[*argn + 1][3]) if (args[*argn + 1][3])
bias = grub_strtosl (args[*argn + 1] + 3, 0, 0); bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0) if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0)
update_val ((file1exists && ! file_exists) update_val ((file1exists && ! ctx.file_exists)
|| (file1.mtimeset && file_info.mtimeset || (file1.mtimeset && ctx.file_info.mtimeset
&& file1.mtime + bias > file_info.mtime)); && file1.mtime + bias > ctx.file_info.mtime),
&ctx);
else else
update_val ((! file1exists && file_exists) update_val ((! file1exists && ctx.file_exists)
|| (file1.mtimeset && file_info.mtimeset || (file1.mtimeset && ctx.file_info.mtimeset
&& file1.mtime + bias < file_info.mtime)); && file1.mtime + bias < ctx.file_info.mtime),
&ctx);
(*argn) += 3; (*argn) += 3;
continue; continue;
} }
@ -310,27 +329,27 @@ test_parse (char **args, int *argn, int argc)
/* File tests. */ /* File tests. */
if (grub_strcmp (args[*argn], "-d") == 0) if (grub_strcmp (args[*argn], "-d") == 0)
{ {
get_fileinfo (args[*argn + 1]); get_fileinfo (args[*argn + 1], &ctx);
update_val (file_exists && file_info.dir); update_val (ctx.file_exists && ctx.file_info.dir, &ctx);
(*argn) += 2; (*argn) += 2;
return ret; return ctx.ret;
} }
if (grub_strcmp (args[*argn], "-e") == 0) if (grub_strcmp (args[*argn], "-e") == 0)
{ {
get_fileinfo (args[*argn + 1]); get_fileinfo (args[*argn + 1], &ctx);
update_val (file_exists); update_val (ctx.file_exists, &ctx);
(*argn) += 2; (*argn) += 2;
return ret; return ctx.ret;
} }
if (grub_strcmp (args[*argn], "-f") == 0) if (grub_strcmp (args[*argn], "-f") == 0)
{ {
get_fileinfo (args[*argn + 1]); get_fileinfo (args[*argn + 1], &ctx);
/* FIXME: check for other types. */ /* FIXME: check for other types. */
update_val (file_exists && ! file_info.dir); update_val (ctx.file_exists && ! ctx.file_info.dir, &ctx);
(*argn) += 2; (*argn) += 2;
return ret; return ctx.ret;
} }
if (grub_strcmp (args[*argn], "-s") == 0) if (grub_strcmp (args[*argn], "-s") == 0)
@ -338,25 +357,25 @@ test_parse (char **args, int *argn, int argc)
grub_file_t file; grub_file_t file;
grub_file_filter_disable_compression (); grub_file_filter_disable_compression ();
file = grub_file_open (args[*argn + 1]); file = grub_file_open (args[*argn + 1]);
update_val (file && (grub_file_size (file) != 0)); update_val (file && (grub_file_size (file) != 0), &ctx);
if (file) if (file)
grub_file_close (file); grub_file_close (file);
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
(*argn) += 2; (*argn) += 2;
return ret; return ctx.ret;
} }
/* String tests. */ /* String tests. */
if (grub_strcmp (args[*argn], "-n") == 0) if (grub_strcmp (args[*argn], "-n") == 0)
{ {
update_val (args[*argn + 1][0]); update_val (args[*argn + 1][0], &ctx);
(*argn) += 2; (*argn) += 2;
continue; continue;
} }
if (grub_strcmp (args[*argn], "-z") == 0) if (grub_strcmp (args[*argn], "-z") == 0)
{ {
update_val (! args[*argn + 1][0]); update_val (! args[*argn + 1][0], &ctx);
(*argn) += 2; (*argn) += 2;
continue; continue;
} }
@ -368,42 +387,42 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn], ")") == 0) if (grub_strcmp (args[*argn], ")") == 0)
{ {
(*argn)++; (*argn)++;
return ret; return ctx.ret;
} }
/* Recursively invoke if parenthesis. */ /* Recursively invoke if parenthesis. */
if (grub_strcmp (args[*argn], "(") == 0) if (grub_strcmp (args[*argn], "(") == 0)
{ {
(*argn)++; (*argn)++;
update_val (test_parse (args, argn, argc)); update_val (test_parse (args, argn, argc), &ctx);
continue; continue;
} }
if (grub_strcmp (args[*argn], "!") == 0) if (grub_strcmp (args[*argn], "!") == 0)
{ {
invert = ! invert; ctx.invert = ! ctx.invert;
(*argn)++; (*argn)++;
continue; continue;
} }
if (grub_strcmp (args[*argn], "-a") == 0) if (grub_strcmp (args[*argn], "-a") == 0)
{ {
/* If current value is 0 second value is to be discarded. */ /* If current value is 0 second value is to be discarded. */
discard = ! ret; ctx.discard = ! ctx.ret;
(*argn)++; (*argn)++;
continue; continue;
} }
if (grub_strcmp (args[*argn], "-o") == 0) if (grub_strcmp (args[*argn], "-o") == 0)
{ {
/* If current value is 1 second value is to be discarded. */ /* If current value is 1 second value is to be discarded. */
discard = ret; ctx.discard = ctx.ret;
(*argn)++; (*argn)++;
continue; continue;
} }
/* No test found. Interpret if as just a string. */ /* No test found. Interpret if as just a string. */
update_val (args[*argn][0]); update_val (args[*argn][0], &ctx);
(*argn)++; (*argn)++;
} }
return ret; return ctx.ret;
} }
static grub_err_t static grub_err_t

View file

@ -279,63 +279,75 @@ match_devices (const regex_t *regexp, int noparts)
return 0; return 0;
} }
/* Context for match_files. */
struct match_files_ctx
{
const regex_t *regexp;
char **files;
unsigned nfile;
char *dir;
};
/* Helper for match_files. */
static int
match_files_iter (const char *name, const struct grub_dirhook_info *info,
void *data)
{
struct match_files_ctx *ctx = data;
char **t;
char *buffer;
/* skip . and .. names */
if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
return 0;
grub_dprintf ("expand", "matching: %s in %s\n", name, ctx->dir);
if (regexec (ctx->regexp, name, 0, 0, 0))
return 0;
grub_dprintf ("expand", "matched\n");
buffer = grub_xasprintf ("%s%s", ctx->dir, name);
if (! buffer)
return 1;
t = grub_realloc (ctx->files, sizeof (char*) * (ctx->nfile + 2));
if (! t)
{
grub_free (buffer);
return 1;
}
ctx->files = t;
ctx->files[ctx->nfile++] = buffer;
ctx->files[ctx->nfile] = 0;
return 0;
}
static char ** static char **
match_files (const char *prefix, const char *suffix, const char *end, match_files (const char *prefix, const char *suffix, const char *end,
const regex_t *regexp) const regex_t *regexp)
{ {
struct match_files_ctx ctx = {
.regexp = regexp,
.nfile = 0,
.files = 0
};
int i; int i;
char **files;
unsigned nfile;
char *dir;
const char *path; const char *path;
char *device_name; char *device_name;
grub_fs_t fs; grub_fs_t fs;
grub_device_t dev; grub_device_t dev;
auto int match (const char *name, const struct grub_dirhook_info *info);
int match (const char *name, const struct grub_dirhook_info *info)
{
char **t;
char *buffer;
/* skip . and .. names */
if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
return 0;
grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
if (regexec (regexp, name, 0, 0, 0))
return 0;
grub_dprintf ("expand", "matched\n");
buffer = grub_xasprintf ("%s%s", dir, name);
if (! buffer)
return 1;
t = grub_realloc (files, sizeof (char*) * (nfile + 2));
if (! t)
{
grub_free (buffer);
return 1;
}
files = t;
files[nfile++] = buffer;
files[nfile] = 0;
return 0;
}
nfile = 0;
files = 0;
dev = 0; dev = 0;
device_name = 0; device_name = 0;
grub_error_push (); grub_error_push ();
dir = make_dir (prefix, suffix, end); ctx.dir = make_dir (prefix, suffix, end);
if (! dir) if (! ctx.dir)
goto fail; goto fail;
device_name = grub_file_get_device_name (dir); device_name = grub_file_get_device_name (ctx.dir);
dev = grub_device_open (device_name); dev = grub_device_open (device_name);
if (! dev) if (! dev)
goto fail; goto fail;
@ -344,33 +356,33 @@ match_files (const char *prefix, const char *suffix, const char *end,
if (! fs) if (! fs)
goto fail; goto fail;
if (dir[0] == '(') if (ctx.dir[0] == '(')
{ {
path = grub_strchr (dir, ')'); path = grub_strchr (ctx.dir, ')');
if (!path) if (!path)
goto fail; goto fail;
path++; path++;
} }
else else
path = dir; path = ctx.dir;
if (fs->dir (dev, path, match)) if (fs->dir (dev, path, match_files_iter, &ctx))
goto fail; goto fail;
grub_free (dir); grub_free (ctx.dir);
grub_device_close (dev); grub_device_close (dev);
grub_free (device_name); grub_free (device_name);
grub_error_pop (); grub_error_pop ();
return files; return ctx.files;
fail: fail:
grub_free (dir); grub_free (ctx.dir);
for (i = 0; files && files[i]; i++) for (i = 0; ctx.files && ctx.files[i]; i++)
grub_free (files[i]); grub_free (ctx.files[i]);
grub_free (files); grub_free (ctx.files);
if (dev) if (dev)
grub_device_close (dev); grub_device_close (dev);
@ -381,28 +393,42 @@ match_files (const char *prefix, const char *suffix, const char *end,
return 0; return 0;
} }
/* Context for check_file. */
struct check_file_ctx
{
const char *basename;
int found;
};
/* Helper for check_file. */
static int
check_file_iter (const char *name, const struct grub_dirhook_info *info,
void *data)
{
struct check_file_ctx *ctx = data;
if (ctx->basename[0] == 0
|| (info->case_insensitive ? grub_strcasecmp (name, ctx->basename) == 0
: grub_strcmp (name, ctx->basename) == 0))
{
ctx->found = 1;
return 1;
}
return 0;
}
static int static int
check_file (const char *dir, const char *basename) check_file (const char *dir, const char *basename)
{ {
struct check_file_ctx ctx = {
.basename = basename,
.found = 0
};
grub_fs_t fs; grub_fs_t fs;
grub_device_t dev; grub_device_t dev;
int found = 0;
const char *device_name, *path; const char *device_name, *path;
auto int match (const char *name, const struct grub_dirhook_info *info);
int match (const char *name, const struct grub_dirhook_info *info)
{
if (basename[0] == 0
|| (info->case_insensitive ? grub_strcasecmp (name, basename) == 0
: grub_strcmp (name, basename) == 0))
{
found = 1;
return 1;
}
return 0;
}
device_name = grub_file_get_device_name (dir); device_name = grub_file_get_device_name (dir);
dev = grub_device_open (device_name); dev = grub_device_open (device_name);
if (! dev) if (! dev)
@ -422,14 +448,14 @@ check_file (const char *dir, const char *basename)
else else
path = dir; path = dir;
fs->dir (dev, path[0] ? path : "/", match); fs->dir (dev, path[0] ? path : "/", check_file_iter, &ctx);
if (grub_errno == 0 && basename[0] == 0) if (grub_errno == 0 && basename[0] == 0)
found = 1; ctx.found = 1;
fail: fail:
grub_errno = 0; grub_errno = 0;
return found; return ctx.found;
} }
static void static void

View file

@ -316,12 +316,87 @@ grub_affs_read_symlink (grub_fshelp_node_t node)
} }
/* Helper for grub_affs_iterate_dir. */
static int
grub_affs_create_node (grub_fshelp_node_t dir,
grub_fshelp_iterate_dir_hook_t hook, void *hook_data,
struct grub_fshelp_node **node,
grub_uint32_t **hashtable,
grub_uint32_t block, const struct grub_affs_file *fil)
{
struct grub_affs_data *data = dir->data;
int type;
grub_uint8_t name_u8[sizeof (fil->name) * GRUB_MAX_UTF8_PER_LATIN1 + 1];
grub_size_t len;
unsigned int nest;
*node = grub_zalloc (sizeof (**node));
if (!*node)
{
grub_free (*hashtable);
return 1;
}
(*node)->data = data;
(*node)->block = block;
(*node)->parent = dir;
len = fil->namelen;
if (len > sizeof (fil->name))
len = sizeof (fil->name);
*grub_latin1_to_utf8 (name_u8, fil->name, len) = '\0';
(*node)->di = *fil;
for (nest = 0; nest < 8; nest++)
{
switch ((*node)->di.type)
{
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_REG):
type = GRUB_FSHELP_REG;
break;
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_DIR):
type = GRUB_FSHELP_DIR;
break;
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_SYMLINK):
type = GRUB_FSHELP_SYMLINK;
break;
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_HARDLINK):
{
grub_err_t err;
(*node)->block = grub_be_to_cpu32 ((*node)->di.hardlink);
err = grub_disk_read (data->disk,
(((grub_uint64_t) (*node)->block + 1) << data->log_blocksize)
- 1,
GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
sizeof ((*node)->di), (char *) &(*node)->di);
if (err)
return 1;
continue;
}
default:
return 0;
}
break;
}
if (nest == 8)
return 0;
type |= GRUB_FSHELP_CASE_INSENSITIVE;
if (hook ((char *) name_u8, type, *node, hook_data))
{
grub_free (*hashtable);
*node = 0;
return 1;
}
*node = 0;
return 0;
}
static int static int
grub_affs_iterate_dir (grub_fshelp_node_t dir, grub_affs_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
unsigned int i; unsigned int i;
struct grub_affs_file file; struct grub_affs_file file;
@ -329,88 +404,13 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
struct grub_affs_data *data = dir->data; struct grub_affs_data *data = dir->data;
grub_uint32_t *hashtable; grub_uint32_t *hashtable;
auto int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block,
const struct grub_affs_file *fil);
int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block,
const struct grub_affs_file *fil)
{
int type;
grub_uint8_t name_u8[sizeof (fil->name) * GRUB_MAX_UTF8_PER_LATIN1 + 1];
grub_size_t len;
unsigned int nest;
node = grub_zalloc (sizeof (*node));
if (!node)
{
grub_free (hashtable);
return 1;
}
node->data = data;
node->block = block;
node->parent = dir;
len = fil->namelen;
if (len > sizeof (fil->name))
len = sizeof (fil->name);
*grub_latin1_to_utf8 (name_u8, fil->name, len) = '\0';
node->di = *fil;
for (nest = 0; nest < 8; nest++)
{
switch (node->di.type)
{
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_REG):
type = GRUB_FSHELP_REG;
break;
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_DIR):
type = GRUB_FSHELP_DIR;
break;
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_SYMLINK):
type = GRUB_FSHELP_SYMLINK;
break;
case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_HARDLINK):
{
grub_err_t err;
node->block = grub_be_to_cpu32 (node->di.hardlink);
err = grub_disk_read (data->disk,
(((grub_uint64_t) node->block + 1) << data->log_blocksize)
- 1,
GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
sizeof (node->di), (char *) &node->di);
if (err)
return 1;
continue;
}
default:
return 0;
}
break;
}
if (nest == 8)
return 0;
type |= GRUB_FSHELP_CASE_INSENSITIVE;
if (hook ((char *) name_u8, type, node))
{
grub_free (hashtable);
node = 0;
return 1;
}
node = 0;
return 0;
}
/* Create the directory entries for `.' and `..'. */ /* Create the directory entries for `.' and `..'. */
node = grub_zalloc (sizeof (*node)); node = grub_zalloc (sizeof (*node));
if (!node) if (!node)
return 1; return 1;
*node = *dir; *node = *dir;
if (hook (".", GRUB_FSHELP_DIR, node)) if (hook (".", GRUB_FSHELP_DIR, node, hook_data))
return 1; return 1;
if (dir->parent) if (dir->parent)
{ {
@ -418,7 +418,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
if (!node) if (!node)
return 1; return 1;
*node = *dir->parent; *node = *dir->parent;
if (hook ("..", GRUB_FSHELP_DIR, node)) if (hook ("..", GRUB_FSHELP_DIR, node, hook_data))
return 1; return 1;
} }
@ -454,7 +454,8 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
if (grub_errno) if (grub_errno)
goto fail; goto fail;
if (grub_affs_create_node (next, &file)) if (grub_affs_create_node (dir, hook, hook_data, &node, &hashtable,
next, &file))
return 1; return 1;
next = grub_be_to_cpu32 (file.next); next = grub_be_to_cpu32 (file.next);
@ -545,31 +546,37 @@ aftime2ctime (const struct grub_affs_time *t)
+ 8 * 365 * 86400 + 86400 * 2; + 8 * 365 * 86400 + 86400 * 2;
} }
/* Context for grub_affs_dir. */
struct grub_affs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_affs_dir. */
static int
grub_affs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_affs_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = aftime2ctime (&node->di.mtime);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_affs_dir (grub_device_t device, const char *path, grub_affs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_affs_dir_ctx ctx = { hook, hook_data };
struct grub_affs_data *data = 0; struct grub_affs_data *data = 0;
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = aftime2ctime (&node->di.mtime);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_affs_mount (device->disk); data = grub_affs_mount (device->disk);
@ -581,7 +588,7 @@ grub_affs_dir (grub_device_t device, const char *path,
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_affs_iterate_dir (fdiro, iterate); grub_affs_iterate_dir (fdiro, grub_affs_dir_iter, &ctx);
fail: fail:
if (data && fdiro != &data->diropen) if (data && fdiro != &data->diropen)

View file

@ -173,6 +173,15 @@ struct grub_bfs_data
struct grub_bfs_inode ino[0]; struct grub_bfs_inode ino[0];
}; };
/* Context for grub_bfs_dir. */
struct grub_bfs_dir_ctx
{
grub_device_t device;
grub_fs_dir_hook_t hook;
void *hook_data;
struct grub_bfs_superblock sb;
};
static grub_err_t static grub_err_t
read_extent (grub_disk_t disk, read_extent (grub_disk_t disk,
const struct grub_bfs_superblock *sb, const struct grub_bfs_superblock *sb,
@ -413,7 +422,9 @@ static int
iterate_in_b_tree (grub_disk_t disk, iterate_in_b_tree (grub_disk_t disk,
const struct grub_bfs_superblock *sb, const struct grub_bfs_superblock *sb,
const struct grub_bfs_inode *ino, const struct grub_bfs_inode *ino,
int NESTED_FUNC_ATTR (*hook) (const char *name, grub_uint64_t value)) int (*hook) (const char *name, grub_uint64_t value,
struct grub_bfs_dir_ctx *ctx),
struct grub_bfs_dir_ctx *ctx)
{ {
struct grub_bfs_btree_header head; struct grub_bfs_btree_header head;
grub_err_t err; grub_err_t err;
@ -496,7 +507,8 @@ iterate_in_b_tree (grub_disk_t disk,
end = grub_bfs_to_cpu_treehead (node.total_key_len); end = grub_bfs_to_cpu_treehead (node.total_key_len);
c = key_data[end]; c = key_data[end];
key_data[end] = 0; key_data[end] = 0;
if (hook (key_data + start, grub_bfs_to_cpu64 (key_values[i]))) if (hook (key_data + start, grub_bfs_to_cpu64 (key_values[i]),
ctx))
return 1; return 1;
key_data[end] = c; key_data[end] = c;
} }
@ -844,46 +856,52 @@ mount (grub_disk_t disk, struct grub_bfs_superblock *sb)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
/* Helper for grub_bfs_dir. */
static int
grub_bfs_dir_iter (const char *name, grub_uint64_t value,
struct grub_bfs_dir_ctx *ctx)
{
grub_err_t err2;
union
{
struct grub_bfs_inode ino;
grub_uint8_t raw[grub_bfs_to_cpu32 (ctx->sb.bsize)];
} ino;
struct grub_dirhook_info info;
err2 = grub_disk_read (ctx->device->disk, value
<< (grub_bfs_to_cpu32 (ctx->sb.log2_bsize)
- GRUB_DISK_SECTOR_BITS), 0,
grub_bfs_to_cpu32 (ctx->sb.bsize), (char *) ino.raw);
if (err2)
{
grub_print_error ();
return 0;
}
info.mtimeset = 1;
#ifdef MODE_AFS
info.mtime =
grub_divmod64 (grub_bfs_to_cpu64 (ino.ino.mtime), 1000000, 0);
#else
info.mtime = grub_bfs_to_cpu64 (ino.ino.mtime) >> 16;
#endif
info.dir = ((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) == ATTR_DIR);
return ctx->hook (name, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_bfs_dir (grub_device_t device, const char *path, grub_bfs_dir (grub_device_t device, const char *path,
int (*hook_in) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info * info))
{ {
struct grub_bfs_superblock sb; struct grub_bfs_dir_ctx ctx = {
.device = device,
.hook = hook,
.hook_data = hook_data
};
grub_err_t err; grub_err_t err;
auto int NESTED_FUNC_ATTR hook (const char *name, grub_uint64_t value);
int NESTED_FUNC_ATTR hook (const char *name, grub_uint64_t value) err = mount (device->disk, &ctx.sb);
{
grub_err_t err2;
union
{
struct grub_bfs_inode ino;
grub_uint8_t raw[grub_bfs_to_cpu32 (sb.bsize)];
} ino;
struct grub_dirhook_info info;
err2 = grub_disk_read (device->disk, value
<< (grub_bfs_to_cpu32 (sb.log2_bsize)
- GRUB_DISK_SECTOR_BITS), 0,
grub_bfs_to_cpu32 (sb.bsize), (char *) ino.raw);
if (err2)
{
grub_print_error ();
return 0;
}
info.mtimeset = 1;
#ifdef MODE_AFS
info.mtime =
grub_divmod64 (grub_bfs_to_cpu64 (ino.ino.mtime), 1000000, 0);
#else
info.mtime = grub_bfs_to_cpu64 (ino.ino.mtime) >> 16;
#endif
info.dir = ((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) == ATTR_DIR);
return hook_in (name, &info);
}
err = mount (device->disk, &sb);
if (err) if (err)
return err; return err;
@ -891,14 +909,15 @@ grub_bfs_dir (grub_device_t device, const char *path,
union union
{ {
struct grub_bfs_inode ino; struct grub_bfs_inode ino;
grub_uint8_t raw[grub_bfs_to_cpu32 (sb.bsize)]; grub_uint8_t raw[grub_bfs_to_cpu32 (ctx.sb.bsize)];
} ino; } ino;
err = find_file (path, device->disk, &sb, &ino.ino); err = find_file (path, device->disk, &ctx.sb, &ino.ino);
if (err) if (err)
return err; return err;
if (((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) != ATTR_DIR)) if (((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) != ATTR_DIR))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
iterate_in_b_tree (device->disk, &sb, &ino.ino, hook); iterate_in_b_tree (device->disk, &ctx.sb, &ino.ino, grub_bfs_dir_iter,
&ctx);
} }
return grub_errno; return grub_errno;

View file

@ -1491,8 +1491,7 @@ find_path (struct grub_btrfs_data *data,
static grub_err_t static grub_err_t
grub_btrfs_dir (grub_device_t device, const char *path, grub_btrfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_btrfs_data *data = grub_btrfs_mount (device); struct grub_btrfs_data *data = grub_btrfs_mount (device);
struct grub_btrfs_key key_in, key_out; struct grub_btrfs_key key_in, key_out;
@ -1586,7 +1585,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
c = cdirel->name[grub_le_to_cpu16 (cdirel->n)]; c = cdirel->name[grub_le_to_cpu16 (cdirel->n)];
cdirel->name[grub_le_to_cpu16 (cdirel->n)] = 0; cdirel->name[grub_le_to_cpu16 (cdirel->n)] = 0;
info.dir = (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY); info.dir = (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY);
if (hook (cdirel->name, &info)) if (hook (cdirel->name, &info, hook_data))
goto out; goto out;
cdirel->name[grub_le_to_cpu16 (cdirel->n)] = c; cdirel->name[grub_le_to_cpu16 (cdirel->n)] = c;
} }

View file

@ -513,8 +513,7 @@ handle_symlink (struct grub_cpio_data *data,
static grub_err_t static grub_err_t
grub_cpio_dir (grub_device_t device, const char *path_in, grub_cpio_dir (grub_device_t device, const char *path_in,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_cpio_data *data; struct grub_cpio_data *data;
grub_disk_addr_t ofs; grub_disk_addr_t ofs;
@ -575,7 +574,7 @@ grub_cpio_dir (grub_device_t device, const char *path_in,
info.mtime = mtime; info.mtime = mtime;
info.mtimeset = 1; info.mtimeset = 1;
if (hook (n, &info)) if (hook (n, &info, hook_data))
{ {
grub_free (name); grub_free (name);
goto fail; goto fail;

View file

@ -692,10 +692,7 @@ grub_ext2_read_symlink (grub_fshelp_node_t node)
static int static int
grub_ext2_iterate_dir (grub_fshelp_node_t dir, grub_ext2_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
unsigned int fpos = 0; unsigned int fpos = 0;
struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
@ -777,7 +774,7 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir,
type = GRUB_FSHELP_REG; type = GRUB_FSHELP_REG;
} }
if (hook (filename, type, fdiro)) if (hook (filename, type, fdiro, hook_data))
return 1; return 1;
} }
@ -858,59 +855,69 @@ grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
} }
static grub_err_t /* Context for grub_ext2_dir. */
grub_ext2_dir (grub_device_t device, const char *path, struct grub_ext2_dir_ctx
int (*hook) (const char *filename,
const struct grub_dirhook_info *info))
{ {
struct grub_ext2_data *data = 0; grub_fs_dir_hook_t hook;
struct grub_fshelp_node *fdiro = 0; void *hook_data;
struct grub_ext2_data *data;
};
auto int NESTED_FUNC_ATTR iterate (const char *filename, /* Helper for grub_ext2_dir. */
enum grub_fshelp_filetype filetype, static int
grub_fshelp_node_t node); grub_ext2_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_ext2_dir_ctx *ctx = data;
struct grub_dirhook_info info;
int NESTED_FUNC_ATTR iterate (const char *filename, grub_memset (&info, 0, sizeof (info));
enum grub_fshelp_filetype filetype, if (! node->inode_read)
grub_fshelp_node_t node)
{ {
struct grub_dirhook_info info; grub_ext2_read_inode (ctx->data, node->ino, &node->inode);
grub_memset (&info, 0, sizeof (info)); if (!grub_errno)
if (! node->inode_read) node->inode_read = 1;
{ grub_errno = GRUB_ERR_NONE;
grub_ext2_read_inode (data, node->ino, &node->inode);
if (!grub_errno)
node->inode_read = 1;
grub_errno = GRUB_ERR_NONE;
}
if (node->inode_read)
{
info.mtimeset = 1;
info.mtime = grub_le_to_cpu32 (node->inode.mtime);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return hook (filename, &info);
} }
if (node->inode_read)
{
info.mtimeset = 1;
info.mtime = grub_le_to_cpu32 (node->inode.mtime);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t
grub_ext2_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
void *hook_data)
{
struct grub_ext2_dir_ctx ctx = {
.hook = hook,
.hook_data = hook_data
};
struct grub_fshelp_node *fdiro = 0;
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_ext2_mount (device->disk); ctx.data = grub_ext2_mount (device->disk);
if (! data) if (! ctx.data)
goto fail; goto fail;
grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_ext2_iterate_dir, grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro,
grub_ext2_read_symlink, GRUB_FSHELP_DIR); grub_ext2_iterate_dir, grub_ext2_read_symlink,
GRUB_FSHELP_DIR);
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_ext2_iterate_dir (fdiro, iterate); grub_ext2_iterate_dir (fdiro, grub_ext2_dir_iter, &ctx);
fail: fail:
if (fdiro != &data->diropen) if (fdiro != &ctx.data->diropen)
grub_free (fdiro); grub_free (fdiro);
grub_free (data); grub_free (ctx.data);
grub_dl_unref (my_mod); grub_dl_unref (my_mod);

View file

@ -844,8 +844,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
static char * static char *
grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
const char *path, const char *origpath, const char *path, const char *origpath,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
char *dirname, *dirp; char *dirname, *dirp;
int call_hook; int call_hook;
@ -905,7 +904,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
#endif #endif
if (*dirname == '\0' && call_hook) if (*dirname == '\0' && call_hook)
{ {
if (hook (ctxt.filename, &info)) if (hook (ctxt.filename, &info, hook_data))
break; break;
else else
continue; continue;
@ -926,7 +925,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
data->cur_cluster_num = ~0U; data->cur_cluster_num = ~0U;
if (call_hook) if (call_hook)
hook (ctxt.filename, &info); hook (ctxt.filename, &info, hook_data);
break; break;
} }
@ -946,9 +945,8 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
} }
static grub_err_t static grub_err_t
grub_fat_dir (grub_device_t device, const char *path, grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
int (*hook) (const char *filename, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_fat_data *data = 0; struct grub_fat_data *data = 0;
grub_disk_t disk = device->disk; grub_disk_t disk = device->disk;
@ -976,7 +974,7 @@ grub_fat_dir (grub_device_t device, const char *path,
do do
{ {
p = grub_fat_find_dir (disk, data, p, path, hook); p = grub_fat_find_dir (disk, data, p, path, hook, hook_data);
} }
while (p && grub_errno == GRUB_ERR_NONE); while (p && grub_errno == GRUB_ERR_NONE);
@ -1004,7 +1002,7 @@ grub_fat_open (grub_file_t file, const char *name)
do do
{ {
p = grub_fat_find_dir (file->device->disk, data, p, name, 0); p = grub_fat_find_dir (file->device->disk, data, p, name, 0, 0);
if (grub_errno != GRUB_ERR_NONE) if (grub_errno != GRUB_ERR_NONE)
goto fail; goto fail;
} }

View file

@ -27,184 +27,199 @@
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
typedef int (*iterate_dir_func) (grub_fshelp_node_t dir,
grub_fshelp_iterate_dir_hook_t hook,
void *data);
typedef char *(*read_symlink_func) (grub_fshelp_node_t node);
/* Context for grub_fshelp_find_file. */
struct grub_fshelp_find_file_ctx
{
const char *path;
grub_fshelp_node_t rootnode, currroot, currnode, oldnode;
enum grub_fshelp_filetype foundtype;
int symlinknest;
char *name;
enum grub_fshelp_filetype type;
};
/* Helper for find_file_iter. */
static void
free_node (grub_fshelp_node_t node, struct grub_fshelp_find_file_ctx *ctx)
{
if (node != ctx->rootnode && node != ctx->currroot)
grub_free (node);
}
/* Helper for grub_fshelp_find_file. */
static int
find_file_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_fshelp_find_file_ctx *ctx = data;
if (filetype == GRUB_FSHELP_UNKNOWN ||
(grub_strcmp (ctx->name, filename) &&
(! (filetype & GRUB_FSHELP_CASE_INSENSITIVE) ||
grub_strcasecmp (ctx->name, filename))))
{
grub_free (node);
return 0;
}
/* The node is found, stop iterating over the nodes. */
ctx->type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
ctx->oldnode = ctx->currnode;
ctx->currnode = node;
return 1;
}
static grub_err_t
find_file (const char *currpath, grub_fshelp_node_t currroot,
grub_fshelp_node_t *currfound,
iterate_dir_func iterate_dir, read_symlink_func read_symlink,
struct grub_fshelp_find_file_ctx *ctx)
{
char fpath[grub_strlen (currpath) + 1];
char *next;
ctx->currroot = currroot;
ctx->name = fpath;
ctx->type = GRUB_FSHELP_DIR;
ctx->currnode = currroot;
ctx->oldnode = currroot;
grub_strncpy (fpath, currpath, grub_strlen (currpath) + 1);
/* Remove all leading slashes. */
while (*ctx->name == '/')
ctx->name++;
if (! *ctx->name)
{
*currfound = ctx->currnode;
return 0;
}
for (;;)
{
int found;
/* Extract the actual part from the pathname. */
next = grub_strchr (ctx->name, '/');
if (next)
{
/* Remove all leading slashes. */
while (*next == '/')
*(next++) = '\0';
}
/* At this point it is expected that the current node is a
directory, check if this is true. */
if (ctx->type != GRUB_FSHELP_DIR)
{
free_node (ctx->currnode, ctx);
ctx->currnode = 0;
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
}
/* Iterate over the directory. */
found = iterate_dir (ctx->currnode, find_file_iter, ctx);
if (! found)
{
free_node (ctx->currnode, ctx);
ctx->currnode = 0;
if (grub_errno)
return grub_errno;
break;
}
/* Read in the symlink and follow it. */
if (ctx->type == GRUB_FSHELP_SYMLINK)
{
char *symlink;
/* Test if the symlink does not loop. */
if (++ctx->symlinknest == 8)
{
free_node (ctx->currnode, ctx);
free_node (ctx->oldnode, ctx);
ctx->currnode = 0;
return grub_error (GRUB_ERR_SYMLINK_LOOP,
N_("too deep nesting of symlinks"));
}
symlink = read_symlink (ctx->currnode);
free_node (ctx->currnode, ctx);
ctx->currnode = 0;
if (!symlink)
{
free_node (ctx->oldnode, ctx);
return grub_errno;
}
/* The symlink is an absolute path, go back to the root inode. */
if (symlink[0] == '/')
{
free_node (ctx->oldnode, ctx);
ctx->oldnode = ctx->rootnode;
}
/* Lookup the node the symlink points to. */
find_file (symlink, ctx->oldnode, &ctx->currnode,
iterate_dir, read_symlink, ctx);
ctx->type = ctx->foundtype;
grub_free (symlink);
if (grub_errno)
{
free_node (ctx->oldnode, ctx);
return grub_errno;
}
}
if (ctx->oldnode != ctx->currnode)
free_node (ctx->oldnode, ctx);
/* Found the node! */
if (! next || *next == '\0')
{
*currfound = ctx->currnode;
ctx->foundtype = ctx->type;
return 0;
}
ctx->name = next;
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
ctx->path);
}
/* Lookup the node PATH. The node ROOTNODE describes the root of the /* Lookup the node PATH. The node ROOTNODE describes the root of the
directory tree. The node found is returned in FOUNDNODE, which is directory tree. The node found is returned in FOUNDNODE, which is
either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to
iterate over all directory entries in the current node. iterate over all directory entries in the current node.
READ_SYMLINK is used to read the symlink if a node is a symlink. READ_SYMLINK is used to read the symlink if a node is a symlink.
EXPECTTYPE is the type node that is expected by the called, an EXPECTTYPE is the type node that is expected by the called, an
error is generated if the node is not of the expected type. Make error is generated if the node is not of the expected type. */
sure you use the NESTED_FUNC_ATTR macro for HOOK, this is required
because GCC has a nasty bug when using regparm=3. */
grub_err_t grub_err_t
grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode, grub_fshelp_node_t *foundnode,
int (*iterate_dir) (grub_fshelp_node_t dir, iterate_dir_func iterate_dir,
int NESTED_FUNC_ATTR (*hook) read_symlink_func read_symlink,
(const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)),
char *(*read_symlink) (grub_fshelp_node_t node),
enum grub_fshelp_filetype expecttype) enum grub_fshelp_filetype expecttype)
{ {
struct grub_fshelp_find_file_ctx ctx = {
.path = path,
.rootnode = rootnode,
.foundtype = GRUB_FSHELP_DIR,
.symlinknest = 0
};
grub_err_t err; grub_err_t err;
enum grub_fshelp_filetype foundtype = GRUB_FSHELP_DIR;
int symlinknest = 0;
auto grub_err_t NESTED_FUNC_ATTR find_file (const char *currpath,
grub_fshelp_node_t currroot,
grub_fshelp_node_t *currfound);
grub_err_t NESTED_FUNC_ATTR find_file (const char *currpath,
grub_fshelp_node_t currroot,
grub_fshelp_node_t *currfound)
{
char fpath[grub_strlen (currpath) + 1];
char *name = fpath;
char *next;
enum grub_fshelp_filetype type = GRUB_FSHELP_DIR;
grub_fshelp_node_t currnode = currroot;
grub_fshelp_node_t oldnode = currroot;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
auto void free_node (grub_fshelp_node_t node);
void free_node (grub_fshelp_node_t node)
{
if (node != rootnode && node != currroot)
grub_free (node);
}
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
if (filetype == GRUB_FSHELP_UNKNOWN ||
(grub_strcmp (name, filename) &&
(! (filetype & GRUB_FSHELP_CASE_INSENSITIVE) ||
grub_strcasecmp (name, filename))))
{
grub_free (node);
return 0;
}
/* The node is found, stop iterating over the nodes. */
type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
oldnode = currnode;
currnode = node;
return 1;
}
grub_strncpy (fpath, currpath, grub_strlen (currpath) + 1);
/* Remove all leading slashes. */
while (*name == '/')
name++;
if (! *name)
{
*currfound = currnode;
return 0;
}
for (;;)
{
int found;
/* Extract the actual part from the pathname. */
next = grub_strchr (name, '/');
if (next)
{
/* Remove all leading slashes. */
while (*next == '/')
*(next++) = '\0';
}
/* At this point it is expected that the current node is a
directory, check if this is true. */
if (type != GRUB_FSHELP_DIR)
{
free_node (currnode);
currnode = 0;
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
}
/* Iterate over the directory. */
found = iterate_dir (currnode, iterate);
if (! found)
{
free_node (currnode);
currnode = 0;
if (grub_errno)
return grub_errno;
break;
}
/* Read in the symlink and follow it. */
if (type == GRUB_FSHELP_SYMLINK)
{
char *symlink;
/* Test if the symlink does not loop. */
if (++symlinknest == 8)
{
free_node (currnode);
free_node (oldnode);
currnode = 0;
return grub_error (GRUB_ERR_SYMLINK_LOOP,
N_("too deep nesting of symlinks"));
}
symlink = read_symlink (currnode);
free_node (currnode);
currnode = 0;
if (!symlink)
{
free_node (oldnode);
return grub_errno;
}
/* The symlink is an absolute path, go back to the root inode. */
if (symlink[0] == '/')
{
free_node (oldnode);
oldnode = rootnode;
}
/* Lookup the node the symlink points to. */
find_file (symlink, oldnode, &currnode);
type = foundtype;
grub_free (symlink);
if (grub_errno)
{
free_node (oldnode);
return grub_errno;
}
}
if (oldnode != currnode)
free_node (oldnode);
/* Found the node! */
if (! next || *next == '\0')
{
*currfound = currnode;
foundtype = type;
return 0;
}
name = next;
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), path);
}
if (!path || path[0] != '/') if (!path || path[0] != '/')
{ {
@ -212,14 +227,14 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
return grub_errno; return grub_errno;
} }
err = find_file (path, rootnode, foundnode); err = find_file (path, rootnode, foundnode, iterate_dir, read_symlink, &ctx);
if (err) if (err)
return err; return err;
/* Check if the node that was found was of the expected type. */ /* Check if the node that was found was of the expected type. */
if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype) if (expecttype == GRUB_FSHELP_REG && ctx.foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file")); return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype) else if (expecttype == GRUB_FSHELP_DIR && ctx.foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
return 0; return 0;

View file

@ -1151,9 +1151,8 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
static grub_err_t static grub_err_t
grub_hfs_dir (grub_device_t device, const char *path, grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
int (*hook) (const char *filename, void *hook_data)
const struct grub_dirhook_info *info))
{ {
int inode; int inode;
@ -1184,14 +1183,14 @@ grub_hfs_dir (grub_device_t device, const char *path,
info.dir = 1; info.dir = 1;
info.mtimeset = 1; info.mtimeset = 1;
info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800; info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800;
return hook (fname, &info); return hook (fname, &info, hook_data);
} }
if (frec->type == GRUB_HFS_FILETYPE_FILE) if (frec->type == GRUB_HFS_FILETYPE_FILE)
{ {
info.dir = 0; info.dir = 0;
info.mtimeset = 1; info.mtimeset = 1;
info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800; info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800;
return hook (fname, &info); return hook (fname, &info, hook_data);
} }
return 0; return 0;

View file

@ -766,10 +766,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
static int static int
grub_hfsplus_iterate_dir (grub_fshelp_node_t dir, grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
int ret = 0; int ret = 0;
@ -825,7 +822,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
node->size = 0; node->size = 0;
node->fileid = grub_be_to_cpu32 (fileinfo->parentid); node->fileid = grub_be_to_cpu32 (fileinfo->parentid);
ret = hook ("..", GRUB_FSHELP_DIR, node); ret = hook ("..", GRUB_FSHELP_DIR, node, hook_data);
return ret; return ret;
} }
@ -878,7 +875,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
node->size = grub_be_to_cpu64 (fileinfo->data.size); node->size = grub_be_to_cpu64 (fileinfo->data.size);
node->fileid = grub_be_to_cpu32 (fileinfo->fileid); node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
ret = hook (filename, type, node); ret = hook (filename, type, node, hook_data);
grub_free (filename); grub_free (filename);
@ -895,7 +892,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
if (!fsnode) if (!fsnode)
return 1; return 1;
*fsnode = *dir; *fsnode = *dir;
if (hook (".", GRUB_FSHELP_DIR, fsnode)) if (hook (".", GRUB_FSHELP_DIR, fsnode, hook_data))
return 1; return 1;
} }
@ -978,32 +975,39 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
file->offset, len, buf); file->offset, len, buf);
} }
/* Context for grub_hfsplus_dir. */
struct grub_hfsplus_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_hfsplus_dir. */
static int
grub_hfsplus_dir_iter (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_hfsplus_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = node->mtime;
info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_hfsplus_dir (grub_device_t device, const char *path, grub_hfsplus_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_hfsplus_dir_ctx ctx = { hook, hook_data };
struct grub_hfsplus_data *data = 0; struct grub_hfsplus_data *data = 0;
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = node->mtime;
info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_hfsplus_mount (device->disk); data = grub_hfsplus_mount (device->disk);
@ -1018,7 +1022,7 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
goto fail; goto fail;
/* Iterate over all entries in this directory. */ /* Iterate over all entries in this directory. */
grub_hfsplus_iterate_dir (fdiro, iterate); grub_hfsplus_iterate_dir (fdiro, grub_hfsplus_dir_iter, &ctx);
fail: fail:
if (data && fdiro != &data->dirroot) if (data && fdiro != &data->dirroot)

View file

@ -521,10 +521,7 @@ get_node_size (grub_fshelp_node_t node)
static int static int
grub_iso9660_iterate_dir (grub_fshelp_node_t dir, grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
struct grub_iso9660_dir dirent; struct grub_iso9660_dir dirent;
grub_off_t offset = 0; grub_off_t offset = 0;
@ -828,7 +825,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
symlink = 0; symlink = 0;
was_continue = 0; was_continue = 0;
} }
if (hook (filename, type, node)) if (hook (filename, type, node, hook_data))
{ {
if (filename_alloc) if (filename_alloc)
grub_free (filename); grub_free (filename);
@ -844,32 +841,39 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
/* Context for grub_iso9660_dir. */
struct grub_iso9660_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_iso9660_dir. */
static int
grub_iso9660_dir_iter (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_iso9660_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_iso9660_dir (grub_device_t device, const char *path, grub_iso9660_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_iso9660_dir_ctx ctx = { hook, hook_data };
struct grub_iso9660_data *data = 0; struct grub_iso9660_data *data = 0;
struct grub_fshelp_node rootnode; struct grub_fshelp_node rootnode;
struct grub_fshelp_node *foundnode; struct grub_fshelp_node *foundnode;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_iso9660_mount (device->disk); data = grub_iso9660_mount (device->disk);
@ -891,7 +895,7 @@ grub_iso9660_dir (grub_device_t device, const char *path,
goto fail; goto fail;
/* List the files in the directory. */ /* List the files in the directory. */
grub_iso9660_iterate_dir (foundnode, iterate); grub_iso9660_iterate_dir (foundnode, grub_iso9660_dir_iter, &ctx);
if (foundnode != &rootnode) if (foundnode != &rootnode)
grub_free (foundnode); grub_free (foundnode);

View file

@ -799,8 +799,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino)
static grub_err_t static grub_err_t
grub_jfs_dir (grub_device_t device, const char *path, grub_jfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_jfs_data *data = 0; struct grub_jfs_data *data = 0;
struct grub_jfs_diropen *diro = 0; struct grub_jfs_diropen *diro = 0;
@ -832,7 +831,7 @@ grub_jfs_dir (grub_device_t device, const char *path,
& GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR; & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
info.mtimeset = 1; info.mtimeset = 1;
info.mtime = grub_le_to_cpu32 (inode.mtime.sec); info.mtime = grub_le_to_cpu32 (inode.mtime.sec);
if (hook (diro->name, &info)) if (hook (diro->name, &info, hook_data))
goto fail; goto fail;
} }

View file

@ -536,8 +536,7 @@ grub_minix_mount (grub_disk_t disk)
static grub_err_t static grub_err_t
grub_minix_dir (grub_device_t device, const char *path, grub_minix_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_minix_data *data = 0; struct grub_minix_data *data = 0;
unsigned int pos = 0; unsigned int pos = 0;
@ -590,7 +589,7 @@ grub_minix_dir (grub_device_t device, const char *path,
info.mtimeset = 1; info.mtimeset = 1;
info.mtime = grub_minix_to_cpu32 (data->inode.mtime); info.mtime = grub_minix_to_cpu32 (data->inode.mtime);
if (hook (filename, &info) ? 1 : 0) if (hook (filename, &info, hook_data) ? 1 : 0)
break; break;
/* Load the old inode back in. */ /* Load the old inode back in. */

View file

@ -870,10 +870,7 @@ grub_nilfs2_read_symlink (grub_fshelp_node_t node)
static int static int
grub_nilfs2_iterate_dir (grub_fshelp_node_t dir, grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
grub_off_t fpos = 0; grub_off_t fpos = 0;
struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
@ -957,7 +954,7 @@ grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
type = GRUB_FSHELP_REG; type = GRUB_FSHELP_REG;
} }
if (hook (filename, type, fdiro)) if (hook (filename, type, fdiro, hook_data))
return 1; return 1;
} }
@ -1032,60 +1029,69 @@ grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
file->offset, len, buf); file->offset, len, buf);
} }
/* Context for grub_nilfs2_dir. */
struct grub_nilfs2_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
struct grub_nilfs2_data *data;
};
/* Helper for grub_nilfs2_dir. */
static int
grub_nilfs2_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_nilfs2_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
if (!node->inode_read)
{
grub_nilfs2_read_inode (ctx->data, node->ino, &node->inode);
if (!grub_errno)
node->inode_read = 1;
grub_errno = GRUB_ERR_NONE;
}
if (node->inode_read)
{
info.mtimeset = 1;
info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_nilfs2_dir (grub_device_t device, const char *path, grub_nilfs2_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info * info))
{ {
struct grub_nilfs2_data *data = 0; struct grub_nilfs2_dir_ctx ctx = {
.hook = hook,
.hook_data = hook_data
};
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
if (!node->inode_read)
{
grub_nilfs2_read_inode (data, node->ino, &node->inode);
if (!grub_errno)
node->inode_read = 1;
grub_errno = GRUB_ERR_NONE;
}
if (node->inode_read)
{
info.mtimeset = 1;
info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_nilfs2_mount (device->disk); ctx.data = grub_nilfs2_mount (device->disk);
if (!data) if (!ctx.data)
goto fail; goto fail;
grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro,
grub_nilfs2_iterate_dir, grub_nilfs2_read_symlink, grub_nilfs2_iterate_dir, grub_nilfs2_read_symlink,
GRUB_FSHELP_DIR); GRUB_FSHELP_DIR);
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_nilfs2_iterate_dir (fdiro, iterate); grub_nilfs2_iterate_dir (fdiro, grub_nilfs2_dir_iter, &ctx);
fail: fail:
if (fdiro != &data->diropen) if (fdiro != &ctx.data->diropen)
grub_free (fdiro); grub_free (fdiro);
grub_free (data); grub_free (ctx.data);
grub_dl_unref (my_mod); grub_dl_unref (my_mod);

View file

@ -600,10 +600,7 @@ free_file (struct grub_ntfs_file *mft)
static int static int
list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
grub_uint8_t *np; grub_uint8_t *np;
int ns; int ns;
@ -667,7 +664,7 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
if (namespace) if (namespace)
type |= GRUB_FSHELP_CASE_INSENSITIVE; type |= GRUB_FSHELP_CASE_INSENSITIVE;
if (hook (ustr, type, fdiro)) if (hook (ustr, type, fdiro, hook_data))
{ {
grub_free (ustr); grub_free (ustr);
return 1; return 1;
@ -778,10 +775,7 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node)
static int static int
grub_ntfs_iterate_dir (grub_fshelp_node_t dir, grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
grub_uint8_t *bitmap; grub_uint8_t *bitmap;
struct grub_ntfs_attr attr, *at; struct grub_ntfs_attr attr, *at;
@ -824,7 +818,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
} }
cur_pos += 0x10; /* Skip index root */ cur_pos += 0x10; /* Skip index root */
ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook); ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data);
if (ret) if (ret)
goto done; goto done;
@ -909,7 +903,8 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
|| (fixup (indx, mft->data->idx_size, || (fixup (indx, mft->data->idx_size,
(const grub_uint8_t *) "INDX"))) (const grub_uint8_t *) "INDX")))
goto done; goto done;
ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], hook); ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)],
hook, hook_data);
if (ret) if (ret)
goto done; goto done;
} }
@ -1017,33 +1012,39 @@ fail:
return 0; return 0;
} }
/* Context for grub_ntfs_dir. */
struct grub_ntfs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_ntfs_dir. */
static int
grub_ntfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_ntfs_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = grub_divmod64 (node->mtime, 10000000, 0)
- 86400ULL * 365 * (1970 - 1601)
- 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_ntfs_dir (grub_device_t device, const char *path, grub_ntfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_ntfs_dir_ctx ctx = { hook, hook_data };
struct grub_ntfs_data *data = 0; struct grub_ntfs_data *data = 0;
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = grub_divmod64 (node->mtime, 10000000, 0)
- 86400ULL * 365 * (1970 - 1601)
- 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_ntfs_mount (device->disk); data = grub_ntfs_mount (device->disk);
@ -1056,7 +1057,7 @@ grub_ntfs_dir (grub_device_t device, const char *path,
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_ntfs_iterate_dir (fdiro, iterate); grub_ntfs_iterate_dir (fdiro, grub_ntfs_dir_iter, &ctx);
fail: fail:
if ((fdiro) && (fdiro != &data->cmft)) if ((fdiro) && (fdiro != &data->cmft))

View file

@ -718,10 +718,8 @@ grub_reiserfs_mount (grub_disk_t disk)
/* Call HOOK for each file in directory ITEM. */ /* Call HOOK for each file in directory ITEM. */
static int static int
grub_reiserfs_iterate_dir (grub_fshelp_node_t item, grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook,
(*hook) (const char *filename, void *hook_data)
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
struct grub_reiserfs_data *data = item->data; struct grub_reiserfs_data *data = item->data;
struct grub_reiserfs_block_header *block_header = 0; struct grub_reiserfs_block_header *block_header = 0;
@ -946,7 +944,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
goto next; goto next;
} }
} }
if (hook (entry_name, entry_type, entry_item)) if (hook (entry_name, entry_type, entry_item, hook_data))
{ {
grub_dprintf ("reiserfs", "Found : %s, type=%d\n", grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
entry_name, entry_type); entry_name, entry_type);
@ -1254,32 +1252,40 @@ grub_reiserfs_close (grub_file_t file)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
/* Context for grub_reiserfs_dir. */
struct grub_reiserfs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_reiserfs_dir. */
static int
grub_reiserfs_dir_iter (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_reiserfs_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = node->mtime;
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
/* Call HOOK with each file under DIR. */ /* Call HOOK with each file under DIR. */
static grub_err_t static grub_err_t
grub_reiserfs_dir (grub_device_t device, const char *path, grub_reiserfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_reiserfs_dir_ctx ctx = { hook, hook_data };
struct grub_reiserfs_data *data = 0; struct grub_reiserfs_data *data = 0;
struct grub_fshelp_node root, *found; struct grub_fshelp_node root, *found;
struct grub_reiserfs_key root_key; struct grub_reiserfs_key root_key;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = node->mtime;
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_reiserfs_mount (device->disk); data = grub_reiserfs_mount (device->disk);
if (! data) if (! data)
@ -1300,7 +1306,7 @@ grub_reiserfs_dir (grub_device_t device, const char *path,
grub_reiserfs_read_symlink, GRUB_FSHELP_DIR); grub_reiserfs_read_symlink, GRUB_FSHELP_DIR);
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_reiserfs_iterate_dir (found, iterate); grub_reiserfs_iterate_dir (found, grub_reiserfs_dir_iter, &ctx);
grub_free (data); grub_free (data);
grub_dl_unref (my_mod); grub_dl_unref (my_mod);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;

View file

@ -171,10 +171,7 @@ grub_romfs_read_symlink (grub_fshelp_node_t node)
static int static int
grub_romfs_iterate_dir (grub_fshelp_node_t dir, grub_romfs_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
grub_disk_addr_t caddr; grub_disk_addr_t caddr;
struct grub_romfs_file_header hdr; struct grub_romfs_file_header hdr;
@ -306,7 +303,7 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir,
} }
} }
if (hook ((char *) name, filetype, node)) if (hook ((char *) name, filetype, node, hook_data))
{ {
grub_free (name); grub_free (name);
return 1; return 1;
@ -316,30 +313,36 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir,
return 0; return 0;
} }
/* Context for grub_romfs_dir. */
struct grub_romfs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_romfs_dir. */
static int
grub_romfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_romfs_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_romfs_dir (grub_device_t device, const char *path, grub_romfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_romfs_dir_ctx ctx = { hook, hook_data };
struct grub_romfs_data *data = 0; struct grub_romfs_data *data = 0;
struct grub_fshelp_node *fdiro = 0, start; struct grub_fshelp_node *fdiro = 0, start;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return hook (filename, &info);
}
data = grub_romfs_mount (device); data = grub_romfs_mount (device);
if (! data) if (! data)
goto fail; goto fail;
@ -352,7 +355,7 @@ grub_romfs_dir (grub_device_t device, const char *path,
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_romfs_iterate_dir (fdiro, iterate); grub_romfs_iterate_dir (fdiro, grub_romfs_dir_iter, &ctx);
fail: fail:
grub_free (data); grub_free (data);

View file

@ -460,12 +460,48 @@ grub_sfs_read_symlink (grub_fshelp_node_t node)
return symlink; return symlink;
} }
/* Helper for grub_sfs_iterate_dir. */
static int
grub_sfs_create_node (struct grub_fshelp_node **node,
struct grub_sfs_data *data,
const char *name,
grub_uint32_t block, grub_uint32_t size, int type,
grub_uint32_t mtime,
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
{
grub_size_t len = grub_strlen (name);
grub_uint8_t *name_u8;
int ret;
*node = grub_malloc (sizeof (**node));
if (!*node)
return 1;
name_u8 = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1);
if (!name_u8)
{
grub_free (*node);
return 1;
}
(*node)->data = data;
(*node)->size = size;
(*node)->block = block;
(*node)->mtime = mtime;
(*node)->cache = 0;
(*node)->cache_off = 0;
(*node)->next_extent = block;
(*node)->cache_size = 0;
(*node)->cache_allocated = 0;
*grub_latin1_to_utf8 (name_u8, (const grub_uint8_t *) name, len) = '\0';
ret = hook ((char *) name_u8, type | data->fshelp_flags, *node, hook_data);
grub_free (name_u8);
return ret;
}
static int static int
grub_sfs_iterate_dir (grub_fshelp_node_t dir, grub_sfs_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
struct grub_fshelp_node *node = 0; struct grub_fshelp_node *node = 0;
struct grub_sfs_data *data = dir->data; struct grub_sfs_data *data = dir->data;
@ -474,46 +510,6 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir,
unsigned int next = dir->block; unsigned int next = dir->block;
grub_uint32_t pos; grub_uint32_t pos;
auto int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name,
grub_uint32_t block,
grub_uint32_t size, int type,
grub_uint32_t mtime);
int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name,
grub_uint32_t block,
grub_uint32_t size, int type,
grub_uint32_t mtime)
{
grub_size_t len = grub_strlen (name);
grub_uint8_t *name_u8;
int ret;
node = grub_malloc (sizeof (*node));
if (!node)
return 1;
name_u8 = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1);
if (!name_u8)
{
grub_free (node);
return 1;
}
node->data = data;
node->size = size;
node->block = block;
node->mtime = mtime;
node->cache = 0;
node->cache_off = 0;
node->next_extent = block;
node->cache_size = 0;
node->cache_allocated = 0;
*grub_latin1_to_utf8 (name_u8, (const grub_uint8_t *) name, len) = '\0';
ret = hook ((char *) name_u8, type | data->fshelp_flags, node);
grub_free (name_u8);
return ret;
}
objc_data = grub_malloc (GRUB_DISK_SECTOR_SIZE << data->log_blocksize); objc_data = grub_malloc (GRUB_DISK_SECTOR_SIZE << data->log_blocksize);
if (!objc_data) if (!objc_data)
goto fail; goto fail;
@ -570,9 +566,10 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir,
else else
block = grub_be_to_cpu32 (obj->file_dir.file.first_block); block = grub_be_to_cpu32 (obj->file_dir.file.first_block);
if (grub_sfs_create_node (filename, block, if (grub_sfs_create_node (&node, data, filename, block,
grub_be_to_cpu32 (obj->file_dir.file.size), grub_be_to_cpu32 (obj->file_dir.file.size),
type, grub_be_to_cpu32 (obj->mtime))) type, grub_be_to_cpu32 (obj->mtime),
hook, hook_data))
{ {
grub_free (objc_data); grub_free (objc_data);
return 1; return 1;
@ -654,32 +651,38 @@ grub_sfs_read (grub_file_t file, char *buf, grub_size_t len)
} }
/* Context for grub_sfs_dir. */
struct grub_sfs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_sfs_dir. */
static int
grub_sfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_sfs_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtime = node->mtime + 8 * 365 * 86400 + 86400 * 2;
info.mtimeset = 1;
grub_free (node->cache);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_sfs_dir (grub_device_t device, const char *path, grub_sfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_sfs_dir_ctx ctx = { hook, hook_data };
struct grub_sfs_data *data = 0; struct grub_sfs_data *data = 0;
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtime = node->mtime + 8 * 365 * 86400 + 86400 * 2;
info.mtimeset = 1;
grub_free (node->cache);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_sfs_mount (device->disk); data = grub_sfs_mount (device->disk);
@ -691,7 +694,7 @@ grub_sfs_dir (grub_device_t device, const char *path,
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_sfs_iterate_dir (fdiro, iterate); grub_sfs_iterate_dir (fdiro, grub_sfs_dir_iter, &ctx);
fail: fail:
if (data && fdiro != &data->diropen) if (data && fdiro != &data->diropen)

View file

@ -478,10 +478,7 @@ grub_squash_read_symlink (grub_fshelp_node_t node)
static int static int
grub_squash_iterate_dir (grub_fshelp_node_t dir, grub_squash_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
grub_uint32_t off; grub_uint32_t off;
grub_uint32_t endoff; grub_uint32_t endoff;
@ -514,7 +511,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
return 0; return 0;
grub_memcpy (node, dir, grub_memcpy (node, dir,
sizeof (*node) + dir->stsize * sizeof (dir->stack[0])); sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
if (hook (".", GRUB_FSHELP_DIR, node)) if (hook (".", GRUB_FSHELP_DIR, node, hook_data))
return 1; return 1;
if (dir->stsize != 1) if (dir->stsize != 1)
@ -536,7 +533,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
if (err) if (err)
return 0; return 0;
if (hook ("..", GRUB_FSHELP_DIR, node)) if (hook ("..", GRUB_FSHELP_DIR, node, hook_data))
return 1; return 1;
} }
} }
@ -604,7 +601,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
node->stack[node->stsize].ino_chunk = grub_le_to_cpu32 (dh.ino_chunk); node->stack[node->stsize].ino_chunk = grub_le_to_cpu32 (dh.ino_chunk);
node->stack[node->stsize].ino_offset = grub_le_to_cpu16 (di.ino_offset); node->stack[node->stsize].ino_offset = grub_le_to_cpu16 (di.ino_offset);
node->stsize++; node->stsize++;
r = hook (buf, filetype, node); r = hook (buf, filetype, node, hook_data);
grub_free (buf); grub_free (buf);
if (r) if (r)
@ -640,28 +637,34 @@ squash_unmount (struct grub_squash_data *data)
} }
/* Context for grub_squash_dir. */
struct grub_squash_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_squash_dir. */
static int
grub_squash_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_squash_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = grub_le_to_cpu32 (node->ino.mtime);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_squash_dir (grub_device_t device, const char *path, grub_squash_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
auto int NESTED_FUNC_ATTR iterate (const char *filename, struct grub_squash_dir_ctx ctx = { hook, hook_data };
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = grub_le_to_cpu32 (node->ino.mtime);
grub_free (node);
return hook (filename, &info);
}
struct grub_squash_data *data = 0; struct grub_squash_data *data = 0;
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
struct grub_fshelp_node root; struct grub_fshelp_node root;
@ -678,7 +681,7 @@ grub_squash_dir (grub_device_t device, const char *path,
grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir, grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir,
grub_squash_read_symlink, GRUB_FSHELP_DIR); grub_squash_read_symlink, GRUB_FSHELP_DIR);
if (!grub_errno) if (!grub_errno)
grub_squash_iterate_dir (fdiro, iterate); grub_squash_iterate_dir (fdiro, grub_squash_dir_iter, &ctx);
squash_unmount (data); squash_unmount (data);

View file

@ -843,10 +843,7 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
static int static int
grub_udf_iterate_dir (grub_fshelp_node_t dir, grub_udf_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
grub_fshelp_node_t child; grub_fshelp_node_t child;
struct grub_udf_file_ident dirent; struct grub_udf_file_ident dirent;
@ -859,7 +856,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
/* The current directory is not stored. */ /* The current directory is not stored. */
grub_memcpy (child, dir, get_fshelp_size (dir->data)); grub_memcpy (child, dir, get_fshelp_size (dir->data));
if (hook (".", GRUB_FSHELP_DIR, child)) if (hook (".", GRUB_FSHELP_DIR, child, hook_data))
return 1; return 1;
while (offset < U64 (dir->block.fe.file_size)) while (offset < U64 (dir->block.fe.file_size))
@ -887,7 +884,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT) if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT)
{ {
/* This is the parent directory. */ /* This is the parent directory. */
if (hook ("..", GRUB_FSHELP_DIR, child)) if (hook ("..", GRUB_FSHELP_DIR, child, hook_data))
return 1; return 1;
} }
else else
@ -911,7 +908,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
if (!filename) if (!filename)
grub_print_error (); grub_print_error ();
if (filename && hook (filename, type, child)) if (filename && hook (filename, type, child, hook_data))
{ {
grub_free (filename); grub_free (filename);
return 1; return 1;
@ -1012,58 +1009,64 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
return NULL; return NULL;
} }
/* Context for grub_udf_dir. */
struct grub_udf_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_udf_dir. */
static int
grub_udf_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_udf_dir_ctx *ctx = data;
struct grub_dirhook_info info;
const struct grub_udf_timestamp *tstamp = NULL;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE)
tstamp = &node->block.fe.modification_time;
else if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_EFE)
tstamp = &node->block.efe.modification_time;
if (tstamp && (U16 (tstamp->type_and_timezone) & 0xf000) == 0x1000)
{
grub_int16_t tz;
struct grub_datetime datetime;
datetime.year = U16 (tstamp->year);
datetime.month = tstamp->month;
datetime.day = tstamp->day;
datetime.hour = tstamp->hour;
datetime.minute = tstamp->minute;
datetime.second = tstamp->second;
tz = U16 (tstamp->type_and_timezone) & 0xfff;
if (tz & 0x800)
tz |= 0xf000;
if (tz == -2047)
tz = 0;
info.mtimeset = !!grub_datetime2unixtime (&datetime, &info.mtime);
info.mtime -= 60 * tz;
}
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_udf_dir (grub_device_t device, const char *path, grub_udf_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_udf_dir_ctx ctx = { hook, hook_data };
struct grub_udf_data *data = 0; struct grub_udf_data *data = 0;
struct grub_fshelp_node *rootnode = 0; struct grub_fshelp_node *rootnode = 0;
struct grub_fshelp_node *foundnode = 0; struct grub_fshelp_node *foundnode = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
const struct grub_udf_timestamp *tstamp = NULL;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE)
tstamp = &node->block.fe.modification_time;
else if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_EFE)
tstamp = &node->block.efe.modification_time;
if (tstamp && (U16 (tstamp->type_and_timezone) & 0xf000) == 0x1000)
{
grub_int16_t tz;
struct grub_datetime datetime;
datetime.year = U16 (tstamp->year);
datetime.month = tstamp->month;
datetime.day = tstamp->day;
datetime.hour = tstamp->hour;
datetime.minute = tstamp->minute;
datetime.second = tstamp->second;
tz = U16 (tstamp->type_and_timezone) & 0xfff;
if (tz & 0x800)
tz |= 0xf000;
if (tz == -2047)
tz = 0;
info.mtimeset = !!grub_datetime2unixtime (&datetime, &info.mtime);
info.mtime -= 60 * tz;
}
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_udf_mount (device->disk); data = grub_udf_mount (device->disk);
@ -1083,7 +1086,7 @@ grub_udf_dir (grub_device_t device, const char *path,
GRUB_FSHELP_DIR)) GRUB_FSHELP_DIR))
goto fail; goto fail;
grub_udf_iterate_dir (foundnode, iterate); grub_udf_iterate_dir (foundnode, grub_udf_dir_iter, &ctx);
if (foundnode != rootnode) if (foundnode != rootnode)
grub_free (foundnode); grub_free (foundnode);

View file

@ -625,8 +625,7 @@ grub_ufs_mount (grub_disk_t disk)
static grub_err_t static grub_err_t
grub_ufs_dir (grub_device_t device, const char *path, grub_ufs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_ufs_data *data; struct grub_ufs_data *data;
unsigned int pos = 0; unsigned int pos = 0;
@ -697,7 +696,7 @@ grub_ufs_dir (grub_device_t device, const char *path,
#endif #endif
info.mtimeset = 1; info.mtimeset = 1;
if (hook (filename, &info)) if (hook (filename, &info, hook_data))
break; break;
} }

View file

@ -443,46 +443,56 @@ grub_xfs_mode_to_filetype (grub_uint16_t mode)
} }
/* Context for grub_xfs_iterate_dir. */
struct grub_xfs_iterate_dir_ctx
{
grub_fshelp_iterate_dir_hook_t hook;
void *hook_data;
struct grub_fshelp_node *diro;
};
/* Helper for grub_xfs_iterate_dir. */
static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename,
struct grub_xfs_iterate_dir_ctx *ctx)
{
struct grub_fshelp_node *fdiro;
grub_err_t err;
fdiro = grub_malloc (sizeof (struct grub_fshelp_node)
- sizeof (struct grub_xfs_inode)
+ (1 << ctx->diro->data->sblock.log2_inode));
if (!fdiro)
{
grub_print_error ();
return 0;
}
/* The inode should be read, otherwise the filetype can
not be determined. */
fdiro->ino = ino;
fdiro->inode_read = 1;
fdiro->data = ctx->diro->data;
err = grub_xfs_read_inode (ctx->diro->data, ino, &fdiro->inode);
if (err)
{
grub_print_error ();
return 0;
}
return ctx->hook (filename, grub_xfs_mode_to_filetype (fdiro->inode.mode),
fdiro, ctx->hook_data);
}
static int static int
grub_xfs_iterate_dir (grub_fshelp_node_t dir, grub_xfs_iterate_dir (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
(*hook) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node))
{ {
struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
auto int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, const char *filename); struct grub_xfs_iterate_dir_ctx ctx = {
.hook = hook,
int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, const char *filename) .hook_data = hook_data,
{ .diro = diro
struct grub_fshelp_node *fdiro; };
grub_err_t err;
fdiro = grub_malloc (sizeof (struct grub_fshelp_node)
- sizeof (struct grub_xfs_inode)
+ (1 << diro->data->sblock.log2_inode));
if (!fdiro)
{
grub_print_error ();
return 0;
}
/* The inode should be read, otherwise the filetype can
not be determined. */
fdiro->ino = ino;
fdiro->inode_read = 1;
fdiro->data = diro->data;
err = grub_xfs_read_inode (diro->data, ino, &fdiro->inode);
if (err)
{
grub_print_error ();
return 0;
}
return hook (filename,
grub_xfs_mode_to_filetype (fdiro->inode.mode),
fdiro);
}
switch (diro->inode.format) switch (diro->inode.format)
{ {
@ -508,10 +518,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
} }
/* Synthesize the direntries for `.' and `..'. */ /* Synthesize the direntries for `.' and `..'. */
if (call_hook (diro->ino, ".")) if (iterate_dir_call_hook (diro->ino, ".", &ctx))
return 1; return 1;
if (call_hook (parent, "..")) if (iterate_dir_call_hook (parent, "..", &ctx))
return 1; return 1;
for (i = 0; i < diro->inode.data.dir.dirhead.count; i++) for (i = 0; i < diro->inode.data.dir.dirhead.count; i++)
@ -541,7 +551,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
grub_memcpy (name, de->name, de->len); grub_memcpy (name, de->name, de->len);
name[de->len] = '\0'; name[de->len] = '\0';
if (call_hook (ino, name)) if (iterate_dir_call_hook (ino, name, &ctx))
return 1; return 1;
de = ((struct grub_xfs_dir_entry *) de = ((struct grub_xfs_dir_entry *)
@ -619,7 +629,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
is not used by GRUB. So it can be overwritten. */ is not used by GRUB. So it can be overwritten. */
filename[direntry->len] = '\0'; filename[direntry->len] = '\0';
if (call_hook (direntry->inode, filename)) if (iterate_dir_call_hook (direntry->inode, filename, &ctx))
{ {
grub_free (dirblock); grub_free (dirblock);
return 1; return 1;
@ -703,34 +713,40 @@ grub_xfs_mount (grub_disk_t disk)
} }
/* Context for grub_xfs_dir. */
struct grub_xfs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
};
/* Helper for grub_xfs_dir. */
static int
grub_xfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_xfs_dir_ctx *ctx = data;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
if (node->inode_read)
{
info.mtimeset = 1;
info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
static grub_err_t static grub_err_t
grub_xfs_dir (grub_device_t device, const char *path, grub_xfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
struct grub_xfs_dir_ctx ctx = { hook, hook_data };
struct grub_xfs_data *data = 0; struct grub_xfs_data *data = 0;
struct grub_fshelp_node *fdiro = 0; struct grub_fshelp_node *fdiro = 0;
auto int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node);
int NESTED_FUNC_ATTR iterate (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
if (node->inode_read)
{
info.mtimeset = 1;
info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
grub_free (node);
return hook (filename, &info);
}
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
data = grub_xfs_mount (device->disk); data = grub_xfs_mount (device->disk);
@ -742,7 +758,7 @@ grub_xfs_dir (grub_device_t device, const char *path,
if (grub_errno) if (grub_errno)
goto fail; goto fail;
grub_xfs_iterate_dir (fdiro, iterate); grub_xfs_iterate_dir (fdiro, grub_xfs_dir_iter, &ctx);
fail: fail:
if (fdiro != &data->diropen) if (fdiro != &data->diropen)

View file

@ -253,6 +253,14 @@ struct grub_zfs_data
grub_uint64_t guid; grub_uint64_t guid;
}; };
/* Context for grub_zfs_dir. */
struct grub_zfs_dir_ctx
{
grub_fs_dir_hook_t hook;
void *hook_data;
struct grub_zfs_data *data;
};
grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher, grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
grub_uint64_t algo, grub_uint64_t algo,
void *nonce, void *nonce,
@ -1790,8 +1798,9 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
static int static int
mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
int NESTED_FUNC_ATTR (*hook) (const char *name, int (*hook) (const char *name, grub_uint64_t val,
grub_uint64_t val)) struct grub_zfs_dir_ctx *ctx),
struct grub_zfs_dir_ctx *ctx)
{ {
int i, chunks; int i, chunks;
mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
@ -1803,7 +1812,7 @@ mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value, mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value,
(int)mzap_ent[i].mze_cd); (int)mzap_ent[i].mze_cd);
if (hook (mzap_ent[i].mze_name, if (hook (mzap_ent[i].mze_name,
grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian))) grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian), ctx))
return 1; return 1;
} }
@ -2054,12 +2063,11 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
static int static int
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
grub_size_t name_elem_length, grub_size_t name_elem_length,
int NESTED_FUNC_ATTR (*hook) (const void *name, int (*hook) (const void *name, grub_size_t name_length,
grub_size_t name_length, const void *val_in,
const void *val_in, grub_size_t nelem, grub_size_t elemsize,
grub_size_t nelem, void *data),
grub_size_t elemsize), void *hook_data, struct grub_zfs_data *data)
struct grub_zfs_data *data)
{ {
zap_leaf_phys_t *l; zap_leaf_phys_t *l;
void *l_in; void *l_in;
@ -2158,7 +2166,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
} }
if (hook (buf, le->le_name_length, if (hook (buf, le->le_name_length,
val, le->le_value_length, le->le_int_size)) val, le->le_value_length, le->le_int_size, hook_data))
{ {
grub_free (l); grub_free (l);
return 1; return 1;
@ -2221,11 +2229,35 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val,
return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
} }
/* Context for zap_iterate_u64. */
struct zap_iterate_u64_ctx
{
int (*hook) (const char *, grub_uint64_t, struct grub_zfs_dir_ctx *);
struct grub_zfs_dir_ctx *dir_ctx;
};
/* Helper for zap_iterate_u64. */
static int
zap_iterate_u64_transform (const void *name,
grub_size_t namelen __attribute__ ((unused)),
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize,
void *data)
{
struct zap_iterate_u64_ctx *ctx = data;
if (elemsize != sizeof (grub_uint64_t) || nelem != 1)
return 0;
return ctx->hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in),
ctx->dir_ctx);
}
static int static int
zap_iterate_u64 (dnode_end_t * zap_dnode, zap_iterate_u64 (dnode_end_t * zap_dnode,
int NESTED_FUNC_ATTR (*hook) (const char *name, int (*hook) (const char *name, grub_uint64_t val,
grub_uint64_t val), struct grub_zfs_dir_ctx *ctx),
struct grub_zfs_data *data) struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx)
{ {
grub_uint64_t block_type; grub_uint64_t block_type;
int size; int size;
@ -2234,23 +2266,6 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
int ret; int ret;
grub_zfs_endian_t endian; grub_zfs_endian_t endian;
auto int NESTED_FUNC_ATTR transform (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR transform (const void *name,
grub_size_t namelen __attribute__ ((unused)),
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize)
{
if (elemsize != sizeof (grub_uint64_t) || nelem != 1)
return 0;
return hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in));
}
/* Read in the first block of the zap object data. */ /* Read in the first block of the zap object data. */
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT; size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
@ -2263,15 +2278,21 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
if (block_type == ZBT_MICRO) if (block_type == ZBT_MICRO)
{ {
grub_dprintf ("zfs", "micro zap\n"); grub_dprintf ("zfs", "micro zap\n");
ret = mzap_iterate (zapbuf, endian, size, hook); ret = mzap_iterate (zapbuf, endian, size, hook, ctx);
grub_free (zapbuf); grub_free (zapbuf);
return ret; return ret;
} }
else if (block_type == ZBT_HEADER) else if (block_type == ZBT_HEADER)
{ {
struct zap_iterate_u64_ctx transform_ctx = {
.hook = hook,
.dir_ctx = ctx
};
grub_dprintf ("zfs", "fat zap\n"); grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */ /* this is a fat zap */
ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data); ret = fzap_iterate (zap_dnode, zapbuf, 1,
zap_iterate_u64_transform, &transform_ctx, data);
grub_free (zapbuf); grub_free (zapbuf);
return ret; return ret;
} }
@ -2282,12 +2303,11 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
static int static int
zap_iterate (dnode_end_t * zap_dnode, zap_iterate (dnode_end_t * zap_dnode,
grub_size_t nameelemlen, grub_size_t nameelemlen,
int NESTED_FUNC_ATTR (*hook) (const void *name, int (*hook) (const void *name, grub_size_t namelen,
grub_size_t namelen, const void *val_in,
const void *val_in, grub_size_t nelem, grub_size_t elemsize,
grub_size_t nelem, void *data),
grub_size_t elemsize), void *hook_data, struct grub_zfs_data *data)
struct grub_zfs_data *data)
{ {
grub_uint64_t block_type; grub_uint64_t block_type;
void *zapbuf; void *zapbuf;
@ -2312,7 +2332,8 @@ zap_iterate (dnode_end_t * zap_dnode,
{ {
grub_dprintf ("zfs", "fat zap\n"); grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */ /* this is a fat zap */
ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data); ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, hook_data,
data);
grub_free (zapbuf); grub_free (zapbuf);
return ret; return ret;
} }
@ -2826,6 +2847,61 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
/* Context for dnode_get_fullpath. */
struct dnode_get_fullpath_ctx
{
struct subvolume *subvol;
grub_uint64_t salt;
int keyn;
};
/* Helper for dnode_get_fullpath. */
static int
count_zap_keys (const void *name __attribute__ ((unused)),
grub_size_t namelen __attribute__ ((unused)),
const void *val_in __attribute__ ((unused)),
grub_size_t nelem __attribute__ ((unused)),
grub_size_t elemsize __attribute__ ((unused)),
void *data)
{
struct dnode_get_fullpath_ctx *ctx = data;
ctx->subvol->nkeys++;
return 0;
}
/* Helper for dnode_get_fullpath. */
static int
load_zap_key (const void *name, grub_size_t namelen, const void *val_in,
grub_size_t nelem, grub_size_t elemsize, void *data)
{
struct dnode_get_fullpath_ctx *ctx = data;
if (namelen != 1)
{
grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
namelen);
return 0;
}
if (elemsize != 1)
{
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
elemsize);
return 0;
}
ctx->subvol->keyring[ctx->keyn].txg =
grub_be_to_cpu64 (*(grub_uint64_t *) name);
ctx->subvol->keyring[ctx->keyn].algo =
grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
ctx->subvol->keyring[ctx->keyn].cipher =
grub_zfs_load_key (val_in, nelem, ctx->salt,
ctx->subvol->keyring[ctx->keyn].algo);
ctx->keyn++;
return 0;
}
static grub_err_t static grub_err_t
dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
dnode_end_t * dn, int *isfs, dnode_end_t * dn, int *isfs,
@ -2835,57 +2911,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
const char *ptr_at, *filename; const char *ptr_at, *filename;
grub_uint64_t headobj; grub_uint64_t headobj;
grub_uint64_t keychainobj; grub_uint64_t keychainobj;
grub_uint64_t salt;
grub_err_t err; grub_err_t err;
int keyn = 0;
auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
grub_size_t namelen __attribute__ ((unused)),
const void *val_in __attribute__ ((unused)),
grub_size_t nelem __attribute__ ((unused)),
grub_size_t elemsize __attribute__ ((unused)))
{
subvol->nkeys++;
return 0;
}
auto int NESTED_FUNC_ATTR load_zap_key (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
int NESTED_FUNC_ATTR load_zap_key (const void *name,
grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize)
{
if (namelen != 1)
{
grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
namelen);
return 0;
}
if (elemsize != 1)
{
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
elemsize);
return 0;
}
subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name);
subvol->keyring[keyn].algo = grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt,
subvol->keyring[keyn].algo);
keyn++;
return 0;
}
ptr_at = grub_strchr (fullpath, '@'); ptr_at = grub_strchr (fullpath, '@');
if (! ptr_at) if (! ptr_at)
@ -2953,6 +2979,10 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian); keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian);
if (grub_zfs_load_key && keychainobj) if (grub_zfs_load_key && keychainobj)
{ {
struct dnode_get_fullpath_ctx ctx = {
.subvol = subvol,
.keyn = 0
};
dnode_end_t keychain_dn, props_dn; dnode_end_t keychain_dn, props_dn;
grub_uint64_t propsobj; grub_uint64_t propsobj;
propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian); propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian);
@ -2966,12 +2996,12 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
return err; return err;
} }
err = zap_lookup (&props_dn, "salt", &salt, data, 0); err = zap_lookup (&props_dn, "salt", &ctx.salt, data, 0);
if (err == GRUB_ERR_FILE_NOT_FOUND) if (err == GRUB_ERR_FILE_NOT_FOUND)
{ {
err = 0; err = 0;
grub_errno = 0; grub_errno = 0;
salt = 0; ctx.salt = 0;
} }
if (err) if (err)
{ {
@ -2988,7 +3018,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
return err; return err;
} }
subvol->nkeys = 0; subvol->nkeys = 0;
zap_iterate (&keychain_dn, 8, count_zap_keys, data); zap_iterate (&keychain_dn, 8, count_zap_keys, &ctx, data);
subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0])); subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0]));
if (!subvol->keyring) if (!subvol->keyring)
{ {
@ -2996,7 +3026,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_free (snapname); grub_free (snapname);
return err; return err;
} }
zap_iterate (&keychain_dn, 8, load_zap_key, data); zap_iterate (&keychain_dn, 8, load_zap_key, &ctx, data);
} }
if (snapname) if (snapname)
@ -3748,108 +3778,122 @@ fill_fs_info (struct grub_dirhook_info *info,
return; return;
} }
/* Helper for grub_zfs_dir. */
static int
iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx)
{
grub_err_t err;
struct grub_dirhook_info info;
dnode_end_t dn;
grub_memset (&info, 0, sizeof (info));
dnode_get (&(ctx->data->subvol.mdn), val, 0, &dn, ctx->data);
if (dn.dn.dn_bonustype == DMU_OT_SA)
{
void *sahdrp;
int hdrsize;
if (dn.dn.dn_bonuslen != 0)
{
sahdrp = (sa_hdr_phys_t *) DN_BONUS (&ctx->data->dnode.dn);
}
else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
{
blkptr_t *bp = &dn.dn.dn_spill;
err = zio_read (bp, dn.endian, &sahdrp, NULL, ctx->data);
if (err)
{
grub_print_error ();
return 0;
}
}
else
{
grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
grub_print_error ();
return 0;
}
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
info.mtimeset = 1;
info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
info.case_insensitive = ctx->data->subvol.case_insensitive;
}
if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
{
info.mtimeset = 1;
info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
dn.endian);
}
info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
grub_dprintf ("zfs", "type=%d, name=%s\n",
(int)dn.dn.dn_type, (char *)name);
return ctx->hook (name, &info, ctx->hook_data);
}
/* Helper for grub_zfs_dir. */
static int
iterate_zap_fs (const char *name, grub_uint64_t val,
struct grub_zfs_dir_ctx *ctx)
{
grub_err_t err;
struct grub_dirhook_info info;
dnode_end_t mdn;
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data);
if (err)
return 0;
if (mdn.dn.dn_type != DMU_OT_DSL_DIR)
return 0;
fill_fs_info (&info, mdn, ctx->data);
return ctx->hook (name, &info, ctx->hook_data);
}
/* Helper for grub_zfs_dir. */
static int
iterate_zap_snap (const char *name, grub_uint64_t val,
struct grub_zfs_dir_ctx *ctx)
{
grub_err_t err;
struct grub_dirhook_info info;
char *name2;
int ret;
dnode_end_t mdn;
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data);
if (err)
return 0;
if (mdn.dn.dn_type != DMU_OT_DSL_DATASET)
return 0;
fill_fs_info (&info, mdn, ctx->data);
name2 = grub_malloc (grub_strlen (name) + 2);
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = ctx->hook (name2, &info, ctx->hook_data);
grub_free (name2);
return ret;
}
static grub_err_t static grub_err_t
grub_zfs_dir (grub_device_t device, const char *path, grub_zfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *, const struct grub_dirhook_info *)) grub_fs_dir_hook_t hook, void *hook_data)
{ {
struct grub_zfs_dir_ctx ctx = {
.hook = hook,
.hook_data = hook_data
};
struct grub_zfs_data *data; struct grub_zfs_data *data;
grub_err_t err; grub_err_t err;
int isfs; int isfs;
auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val);
auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name,
grub_uint64_t val);
auto int NESTED_FUNC_ATTR iterate_zap_snap (const char *name,
grub_uint64_t val);
int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val)
{
struct grub_dirhook_info info;
dnode_end_t dn;
grub_memset (&info, 0, sizeof (info));
dnode_get (&(data->subvol.mdn), val, 0, &dn, data);
if (dn.dn.dn_bonustype == DMU_OT_SA)
{
void *sahdrp;
int hdrsize;
if (dn.dn.dn_bonuslen != 0)
{
sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
}
else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
{
blkptr_t *bp = &dn.dn.dn_spill;
err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
if (err)
{
grub_print_error ();
return 0;
}
}
else
{
grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
grub_print_error ();
return 0;
}
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
info.mtimeset = 1;
info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
info.case_insensitive = data->subvol.case_insensitive;
}
if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
{
info.mtimeset = 1;
info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
dn.endian);
}
info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
grub_dprintf ("zfs", "type=%d, name=%s\n",
(int)dn.dn.dn_type, (char *)name);
return hook (name, &info);
}
int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, grub_uint64_t val)
{
struct grub_dirhook_info info;
dnode_end_t mdn;
err = dnode_get (&(data->mos), val, 0, &mdn, data);
if (err)
return 0;
if (mdn.dn.dn_type != DMU_OT_DSL_DIR)
return 0;
fill_fs_info (&info, mdn, data);
return hook (name, &info);
}
int NESTED_FUNC_ATTR iterate_zap_snap (const char *name, grub_uint64_t val)
{
struct grub_dirhook_info info;
char *name2;
int ret;
dnode_end_t mdn;
err = dnode_get (&(data->mos), val, 0, &mdn, data);
if (err)
return 0;
if (mdn.dn.dn_type != DMU_OT_DSL_DATASET)
return 0;
fill_fs_info (&info, mdn, data);
name2 = grub_malloc (grub_strlen (name) + 2);
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = hook (name2, &info);
grub_free (name2);
return ret;
}
data = zfs_mount (device); data = zfs_mount (device);
if (! data) if (! data)
@ -3860,6 +3904,8 @@ grub_zfs_dir (grub_device_t device, const char *path,
zfs_unmount (data); zfs_unmount (data);
return err; return err;
} }
ctx.data = data;
if (isfs) if (isfs)
{ {
grub_uint64_t childobj, headobj; grub_uint64_t childobj, headobj;
@ -3868,7 +3914,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
struct grub_dirhook_info info; struct grub_dirhook_info info;
fill_fs_info (&info, data->dnode, data); fill_fs_info (&info, data->dnode, data);
hook ("@", &info); hook ("@", &info, hook_data);
childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian); childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian);
headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian); headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian);
@ -3880,7 +3926,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
return err; return err;
} }
zap_iterate_u64 (&dn, iterate_zap_fs, data); zap_iterate_u64 (&dn, iterate_zap_fs, data, &ctx);
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data); err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data);
if (err) if (err)
@ -3899,7 +3945,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
return err; return err;
} }
zap_iterate_u64 (&dn, iterate_zap_snap, data); zap_iterate_u64 (&dn, iterate_zap_snap, data, &ctx);
} }
else else
{ {
@ -3908,7 +3954,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
zfs_unmount (data); zfs_unmount (data);
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
} }
zap_iterate_u64 (&(data->dnode), iterate_zap, data); zap_iterate_u64 (&(data->dnode), iterate_zap, data, &ctx);
} }
zfs_unmount (data); zfs_unmount (data);
return grub_errno; return grub_errno;

View file

@ -105,7 +105,8 @@ grub_mini_print_devices (const char *name, void *data __attribute__ ((unused)))
static int static int
grub_mini_print_files (const char *filename, grub_mini_print_files (const char *filename,
const struct grub_dirhook_info *info) const struct grub_dirhook_info *info,
void *data __attribute__ ((unused)))
{ {
grub_printf ("%s%s ", filename, info->dir ? "/" : ""); grub_printf ("%s%s ", filename, info->dir ? "/" : "");
@ -160,7 +161,7 @@ grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)),
} }
else if (fs) else if (fs)
{ {
(fs->dir) (dev, path, grub_mini_print_files); (fs->dir) (dev, path, grub_mini_print_files, NULL);
grub_xputs ("\n"); grub_xputs ("\n");
grub_refresh (); grub_refresh ();
} }

View file

@ -65,8 +65,7 @@ struct grub_hostfs_data
static grub_err_t static grub_err_t
grub_hostfs_dir (grub_device_t device, const char *path, grub_hostfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data)
const struct grub_dirhook_info *info))
{ {
DIR *dir; DIR *dir;
@ -91,7 +90,7 @@ grub_hostfs_dir (grub_device_t device, const char *path,
break; break;
info.dir = !! is_dir (path, de->d_name); info.dir = !! is_dir (path, de->d_name);
hook (de->d_name, &info); hook (de->d_name, &info, hook_data);
} }

View file

@ -35,10 +35,11 @@ grub_fs_autoload_hook_t grub_fs_autoload_hook = 0;
/* Helper for grub_fs_probe. */ /* Helper for grub_fs_probe. */
static int static int
probe_dummy_iter (const char *filename __attribute__ ((unused)), probe_dummy_iter (const char *filename __attribute__ ((unused)),
const struct grub_dirhook_info *info __attribute__ ((unused))) const struct grub_dirhook_info *info __attribute__ ((unused)),
{ void *data __attribute__ ((unused)))
return 1; {
} return 1;
}
grub_fs_t grub_fs_t
grub_fs_probe (grub_device_t device) grub_fs_probe (grub_device_t device)
@ -69,7 +70,7 @@ grub_fs_probe (grub_device_t device)
} }
else else
#endif #endif
(p->dir) (device, "/", probe_dummy_iter); (p->dir) (device, "/", probe_dummy_iter, NULL);
if (grub_errno == GRUB_ERR_NONE) if (grub_errno == GRUB_ERR_NONE)
return p; return p;
@ -93,7 +94,7 @@ grub_fs_probe (grub_device_t device)
{ {
p = grub_fs_list; p = grub_fs_list;
(p->dir) (device, "/", probe_dummy_iter); (p->dir) (device, "/", probe_dummy_iter, NULL);
if (grub_errno == GRUB_ERR_NONE) if (grub_errno == GRUB_ERR_NONE)
{ {
count--; count--;

View file

@ -1017,49 +1017,66 @@ grub_xnu_check_os_bundle_required (char *plistname,
return ret; return ret;
} }
/* Context for grub_xnu_scan_dir_for_kexts. */
struct grub_xnu_scan_dir_for_kexts_ctx
{
char *dirname;
const char *osbundlerequired;
int maxrecursion;
};
/* Helper for grub_xnu_scan_dir_for_kexts. */
static int
grub_xnu_scan_dir_for_kexts_load (const char *filename,
const struct grub_dirhook_info *info,
void *data)
{
struct grub_xnu_scan_dir_for_kexts_ctx *ctx = data;
char *newdirname;
if (! info->dir)
return 0;
if (filename[0] == '.')
return 0;
if (grub_strlen (filename) < 5 ||
grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
return 0;
newdirname
= grub_malloc (grub_strlen (ctx->dirname) + grub_strlen (filename) + 2);
/* It's a .kext. Try to load it. */
if (newdirname)
{
grub_strcpy (newdirname, ctx->dirname);
newdirname[grub_strlen (newdirname) + 1] = 0;
newdirname[grub_strlen (newdirname)] = '/';
grub_strcpy (newdirname + grub_strlen (newdirname), filename);
grub_xnu_load_kext_from_dir (newdirname, ctx->osbundlerequired,
ctx->maxrecursion);
if (grub_errno == GRUB_ERR_BAD_OS)
grub_errno = GRUB_ERR_NONE;
grub_free (newdirname);
}
return 0;
}
/* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */ /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
grub_err_t grub_err_t
grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired, grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
int maxrecursion) int maxrecursion)
{ {
struct grub_xnu_scan_dir_for_kexts_ctx ctx = {
.dirname = dirname,
.osbundlerequired = osbundlerequired,
.maxrecursion = maxrecursion
};
grub_device_t dev; grub_device_t dev;
char *device_name; char *device_name;
grub_fs_t fs; grub_fs_t fs;
const char *path; const char *path;
auto int load_hook (const char *filename,
const struct grub_dirhook_info *info);
int load_hook (const char *filename, const struct grub_dirhook_info *info)
{
char *newdirname;
if (! info->dir)
return 0;
if (filename[0] == '.')
return 0;
if (grub_strlen (filename) < 5 ||
grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
return 0;
newdirname
= grub_malloc (grub_strlen (dirname) + grub_strlen (filename) + 2);
/* It's a .kext. Try to load it. */
if (newdirname)
{
grub_strcpy (newdirname, dirname);
newdirname[grub_strlen (newdirname) + 1] = 0;
newdirname[grub_strlen (newdirname)] = '/';
grub_strcpy (newdirname + grub_strlen (newdirname), filename);
grub_xnu_load_kext_from_dir (newdirname, osbundlerequired,
maxrecursion);
if (grub_errno == GRUB_ERR_BAD_OS)
grub_errno = GRUB_ERR_NONE;
grub_free (newdirname);
}
return 0;
}
if (! grub_xnu_heap_size) if (! grub_xnu_heap_size)
return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first")); return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
@ -1075,7 +1092,7 @@ grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
path++; path++;
if (fs) if (fs)
(fs->dir) (dev, path, load_hook); (fs->dir) (dev, path, grub_xnu_scan_dir_for_kexts_load, &ctx);
grub_device_close (dev); grub_device_close (dev);
} }
grub_free (device_name); grub_free (device_name);
@ -1083,60 +1100,78 @@ grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
/* Context for grub_xnu_load_kext_from_dir. */
struct grub_xnu_load_kext_from_dir_ctx
{
char *dirname;
const char *osbundlerequired;
int maxrecursion;
char *plistname;
char *newdirname;
int usemacos;
};
/* Helper for grub_xnu_load_kext_from_dir. */
static int
grub_xnu_load_kext_from_dir_load (const char *filename,
const struct grub_dirhook_info *info,
void *data)
{
struct grub_xnu_load_kext_from_dir_ctx *ctx = data;
if (grub_strlen (filename) > 15)
return 0;
grub_strcpy (ctx->newdirname + grub_strlen (ctx->dirname) + 1, filename);
/* If the kext contains directory "Contents" all real stuff is in
this directory. */
if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
grub_xnu_load_kext_from_dir (ctx->newdirname, ctx->osbundlerequired,
ctx->maxrecursion - 1);
/* Directory "Plugins" contains nested kexts. */
if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
grub_xnu_scan_dir_for_kexts (ctx->newdirname, ctx->osbundlerequired,
ctx->maxrecursion - 1);
/* Directory "MacOS" contains executable, otherwise executable is
on the top. */
if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
ctx->usemacos = 1;
/* Info.plist is the file which governs our future actions. */
if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
&& ! ctx->plistname)
ctx->plistname = grub_strdup (ctx->newdirname);
return 0;
}
/* Load extension DIRNAME. (extensions are directories in xnu) */ /* Load extension DIRNAME. (extensions are directories in xnu) */
grub_err_t grub_err_t
grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired, grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
int maxrecursion) int maxrecursion)
{ {
struct grub_xnu_load_kext_from_dir_ctx ctx = {
.dirname = dirname,
.osbundlerequired = osbundlerequired,
.maxrecursion = maxrecursion,
.plistname = 0,
.usemacos = 0
};
grub_device_t dev; grub_device_t dev;
char *plistname = 0;
char *newdirname;
char *newpath; char *newpath;
char *device_name; char *device_name;
grub_fs_t fs; grub_fs_t fs;
const char *path; const char *path;
char *binsuffix; char *binsuffix;
int usemacos = 0;
grub_file_t binfile; grub_file_t binfile;
auto int load_hook (const char *filename, ctx.newdirname = grub_malloc (grub_strlen (dirname) + 20);
const struct grub_dirhook_info *info); if (! ctx.newdirname)
int load_hook (const char *filename, const struct grub_dirhook_info *info)
{
if (grub_strlen (filename) > 15)
return 0;
grub_strcpy (newdirname + grub_strlen (dirname) + 1, filename);
/* If the kext contains directory "Contents" all real stuff is in
this directory. */
if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
grub_xnu_load_kext_from_dir (newdirname, osbundlerequired,
maxrecursion - 1);
/* Directory "Plugins" contains nested kexts. */
if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
grub_xnu_scan_dir_for_kexts (newdirname, osbundlerequired,
maxrecursion - 1);
/* Directory "MacOS" contains executable, otherwise executable is
on the top. */
if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
usemacos = 1;
/* Info.plist is the file which governs our future actions. */
if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
&& ! plistname)
plistname = grub_strdup (newdirname);
return 0;
}
newdirname = grub_malloc (grub_strlen (dirname) + 20);
if (! newdirname)
return grub_errno; return grub_errno;
grub_strcpy (newdirname, dirname); grub_strcpy (ctx.newdirname, dirname);
newdirname[grub_strlen (dirname)] = '/'; ctx.newdirname[grub_strlen (dirname)] = '/';
newdirname[grub_strlen (dirname) + 1] = 0; ctx.newdirname[grub_strlen (dirname) + 1] = 0;
device_name = grub_file_get_device_name (dirname); device_name = grub_file_get_device_name (dirname);
dev = grub_device_open (device_name); dev = grub_device_open (device_name);
if (dev) if (dev)
@ -1148,18 +1183,18 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
else else
path++; path++;
newpath = grub_strchr (newdirname, ')'); newpath = grub_strchr (ctx.newdirname, ')');
if (! newpath) if (! newpath)
newpath = newdirname; newpath = ctx.newdirname;
else else
newpath++; newpath++;
/* Look at the directory. */ /* Look at the directory. */
if (fs) if (fs)
(fs->dir) (dev, path, load_hook); (fs->dir) (dev, path, grub_xnu_load_kext_from_dir_load, &ctx);
if (plistname && grub_xnu_check_os_bundle_required if (ctx.plistname && grub_xnu_check_os_bundle_required
(plistname, osbundlerequired, &binsuffix)) (ctx.plistname, osbundlerequired, &binsuffix))
{ {
if (binsuffix) if (binsuffix)
{ {
@ -1168,29 +1203,29 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
+ grub_strlen (binsuffix) + grub_strlen (binsuffix)
+ sizeof ("/MacOS/")); + sizeof ("/MacOS/"));
grub_strcpy (binname, dirname); grub_strcpy (binname, dirname);
if (usemacos) if (ctx.usemacos)
grub_strcpy (binname + grub_strlen (binname), "/MacOS/"); grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
else else
grub_strcpy (binname + grub_strlen (binname), "/"); grub_strcpy (binname + grub_strlen (binname), "/");
grub_strcpy (binname + grub_strlen (binname), binsuffix); grub_strcpy (binname + grub_strlen (binname), binsuffix);
grub_dprintf ("xnu", "%s:%s\n", plistname, binname); grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname);
binfile = grub_file_open (binname); binfile = grub_file_open (binname);
if (! binfile) if (! binfile)
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
/* Load the extension. */ /* Load the extension. */
grub_xnu_load_driver (plistname, binfile, grub_xnu_load_driver (ctx.plistname, binfile,
binname); binname);
grub_free (binname); grub_free (binname);
grub_free (binsuffix); grub_free (binsuffix);
} }
else else
{ {
grub_dprintf ("xnu", "%s:0\n", plistname); grub_dprintf ("xnu", "%s:0\n", ctx.plistname);
grub_xnu_load_driver (plistname, 0, 0); grub_xnu_load_driver (ctx.plistname, 0, 0);
} }
} }
grub_free (plistname); grub_free (ctx.plistname);
grub_device_close (dev); grub_device_close (dev);
} }
grub_free (device_name); grub_free (device_name);

View file

@ -1253,8 +1253,8 @@ grub_net_open_real (const char *name)
static grub_err_t static grub_err_t
grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused)), grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
int (*hook) (const char *filename, grub_fs_dir_hook_t hook __attribute__ ((unused)),
const struct grub_dirhook_info *info) __attribute__ ((unused))) void *hook_data __attribute__ ((unused)))
{ {
if (!device->net) if (!device->net)
return grub_error (GRUB_ERR_BUG, "invalid net device"); return grub_error (GRUB_ERR_BUG, "invalid net device");

View file

@ -123,7 +123,8 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p,
} }
static int static int
iterate_dir (const char *filename, const struct grub_dirhook_info *info) iterate_dir (const char *filename, const struct grub_dirhook_info *info,
void *data __attribute__ ((unused)))
{ {
if (! info->dir) if (! info->dir)
{ {
@ -295,7 +296,7 @@ complete_file (void)
dirfile[1] = '\0'; dirfile[1] = '\0';
/* Iterate the directory. */ /* Iterate the directory. */
(fs->dir) (dev, dir, iterate_dir); (fs->dir) (dev, dir, iterate_dir, NULL);
grub_free (dir); grub_free (dir);

View file

@ -41,6 +41,10 @@ struct grub_dirhook_info
grub_int32_t mtime; grub_int32_t mtime;
}; };
typedef int (*grub_fs_dir_hook_t) (const char *filename,
const struct grub_dirhook_info *info,
void *data);
/* Filesystem descriptor. */ /* Filesystem descriptor. */
struct grub_fs struct grub_fs
{ {
@ -53,8 +57,7 @@ struct grub_fs
/* Call HOOK with each file under DIR. */ /* Call HOOK with each file under DIR. */
grub_err_t (*dir) (grub_device_t device, const char *path, grub_err_t (*dir) (grub_device_t device, const char *path,
int (*hook) (const char *filename, grub_fs_dir_hook_t hook, void *hook_data);
const struct grub_dirhook_info *info));
/* Open a file named NAME and initialize FILE. */ /* Open a file named NAME and initialize FILE. */
grub_err_t (*open) (struct grub_file *file, const char *name); grub_err_t (*open) (struct grub_file *file, const char *name);

View file

@ -38,24 +38,25 @@ enum grub_fshelp_filetype
GRUB_FSHELP_SYMLINK GRUB_FSHELP_SYMLINK
}; };
typedef int (*grub_fshelp_iterate_dir_hook_t) (const char *filename,
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node,
void *data);
/* Lookup the node PATH. The node ROOTNODE describes the root of the /* Lookup the node PATH. The node ROOTNODE describes the root of the
directory tree. The node found is returned in FOUNDNODE, which is directory tree. The node found is returned in FOUNDNODE, which is
either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to
iterate over all directory entries in the current node. iterate over all directory entries in the current node.
READ_SYMLINK is used to read the symlink if a node is a symlink. READ_SYMLINK is used to read the symlink if a node is a symlink.
EXPECTTYPE is the type node that is expected by the called, an EXPECTTYPE is the type node that is expected by the called, an
error is generated if the node is not of the expected type. Make error is generated if the node is not of the expected type. */
sure you use the NESTED_FUNC_ATTR macro for HOOK, this is required
because GCC has a nasty bug when using regparm=3. */
grub_err_t grub_err_t
EXPORT_FUNC(grub_fshelp_find_file) (const char *path, EXPORT_FUNC(grub_fshelp_find_file) (const char *path,
grub_fshelp_node_t rootnode, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode, grub_fshelp_node_t *foundnode,
int (*iterate_dir) (grub_fshelp_node_t dir, int (*iterate_dir) (grub_fshelp_node_t dir,
int NESTED_FUNC_ATTR grub_fshelp_iterate_dir_hook_t hook,
(*hook) (const char *filename, void *hook_data),
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)),
char *(*read_symlink) (grub_fshelp_node_t node), char *(*read_symlink) (grub_fshelp_node_t node),
enum grub_fshelp_filetype expect); enum grub_fshelp_filetype expect);

View file

@ -116,30 +116,38 @@ translate_error (void)
return ret; return ret;
} }
/* Context for fuse_getattr. */
struct fuse_getattr_ctx
{
char *filename;
struct grub_dirhook_info file_info;
int file_exists;
};
/* A hook for iterating directories. */
static int
fuse_getattr_find_file (const char *cur_filename,
const struct grub_dirhook_info *info, void *data)
{
struct fuse_getattr_ctx *ctx = data;
if ((info->case_insensitive ? grub_strcasecmp (cur_filename, ctx->filename)
: grub_strcmp (cur_filename, ctx->filename)) == 0)
{
ctx->file_info = *info;
ctx->file_exists = 1;
return 1;
}
return 0;
}
static int static int
fuse_getattr (const char *path, struct stat *st) fuse_getattr (const char *path, struct stat *st)
{ {
char *filename, *pathname, *path2; struct fuse_getattr_ctx ctx;
char *pathname, *path2;
const char *pathname_t; const char *pathname_t;
struct grub_dirhook_info file_info;
int file_exists = 0;
/* A hook for iterating directories. */
auto int find_file (const char *cur_filename,
const struct grub_dirhook_info *info);
int find_file (const char *cur_filename,
const struct grub_dirhook_info *info)
{
if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename)
: grub_strcmp (cur_filename, filename)) == 0)
{
file_info = *info;
file_exists = 1;
return 1;
}
return 0;
}
if (path[0] == '/' && path[1] == 0) if (path[0] == '/' && path[1] == 0)
{ {
st->st_dev = 0; st->st_dev = 0;
@ -155,7 +163,7 @@ fuse_getattr (const char *path, struct stat *st)
return 0; return 0;
} }
file_exists = 0; ctx.file_exists = 0;
pathname_t = grub_strchr (path, ')'); pathname_t = grub_strchr (path, ')');
if (! pathname_t) if (! pathname_t)
@ -169,35 +177,35 @@ fuse_getattr (const char *path, struct stat *st)
pathname[grub_strlen (pathname) - 1] = 0; pathname[grub_strlen (pathname) - 1] = 0;
/* Split into path and filename. */ /* Split into path and filename. */
filename = grub_strrchr (pathname, '/'); ctx.filename = grub_strrchr (pathname, '/');
if (! filename) if (! ctx.filename)
{ {
path2 = grub_strdup ("/"); path2 = grub_strdup ("/");
filename = pathname; ctx.filename = pathname;
} }
else else
{ {
filename++; ctx.filename++;
path2 = grub_strdup (pathname); path2 = grub_strdup (pathname);
path2[filename - pathname] = 0; path2[ctx.filename - pathname] = 0;
} }
/* It's the whole device. */ /* It's the whole device. */
(fs->dir) (dev, path2, find_file); (fs->dir) (dev, path2, fuse_getattr_find_file, &ctx);
grub_free (path2); grub_free (path2);
if (!file_exists) if (!ctx.file_exists)
{ {
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
return -ENOENT; return -ENOENT;
} }
st->st_dev = 0; st->st_dev = 0;
st->st_ino = 0; st->st_ino = 0;
st->st_mode = file_info.dir ? (0555 | S_IFDIR) : (0444 | S_IFREG); st->st_mode = ctx.file_info.dir ? (0555 | S_IFDIR) : (0444 | S_IFREG);
st->st_uid = 0; st->st_uid = 0;
st->st_gid = 0; st->st_gid = 0;
st->st_rdev = 0; st->st_rdev = 0;
if (!file_info.dir) if (!ctx.file_info.dir)
{ {
grub_file_t file; grub_file_t file;
file = grub_file_open (path); file = grub_file_open (path);
@ -210,8 +218,8 @@ fuse_getattr (const char *path, struct stat *st)
st->st_size = 0; st->st_size = 0;
st->st_blksize = 512; st->st_blksize = 512;
st->st_blocks = (st->st_size + 511) >> 9; st->st_blocks = (st->st_size + 511) >> 9;
st->st_atime = st->st_mtime = st->st_ctime = file_info.mtimeset st->st_atime = st->st_mtime = st->st_ctime = ctx.file_info.mtimeset
? file_info.mtime : 0; ? ctx.file_info.mtime : 0;
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
return 0; return 0;
} }
@ -271,39 +279,55 @@ fuse_release (const char *path, struct fuse_file_info *fi)
return 0; return 0;
} }
/* Context for fuse_readdir. */
struct fuse_readdir_ctx
{
const char *path;
void *buf;
fuse_fill_dir_t fill;
};
/* Helper for fuse_readdir. */
static int
fuse_readdir_call_fill (const char *filename,
const struct grub_dirhook_info *info, void *data)
{
struct fuse_readdir_ctx *ctx = data;
struct stat st;
grub_memset (&st, 0, sizeof (st));
st.st_mode = info->dir ? (0555 | S_IFDIR) : (0444 | S_IFREG);
if (!info->dir)
{
grub_file_t file;
char *tmp;
tmp = xasprintf ("%s/%s", ctx->path, filename);
file = grub_file_open (tmp);
free (tmp);
if (! file)
return translate_error ();
st.st_size = file->size;
grub_file_close (file);
}
st.st_blksize = 512;
st.st_blocks = (st.st_size + 511) >> 9;
st.st_atime = st.st_mtime = st.st_ctime
= info->mtimeset ? info->mtime : 0;
ctx->fill (ctx->buf, filename, &st, 0);
return 0;
}
static int static int
fuse_readdir (const char *path, void *buf, fuse_readdir (const char *path, void *buf,
fuse_fill_dir_t fill, off_t off, struct fuse_file_info *fi) fuse_fill_dir_t fill, off_t off, struct fuse_file_info *fi)
{ {
struct fuse_readdir_ctx ctx = {
.path = path,
.buf = buf,
.fill = fill
};
char *pathname; char *pathname;
auto int call_fill (const char *filename,
const struct grub_dirhook_info *info);
int call_fill (const char *filename, const struct grub_dirhook_info *info)
{
struct stat st;
grub_memset (&st, 0, sizeof (st));
st.st_mode = info->dir ? (0555 | S_IFDIR) : (0444 | S_IFREG);
if (!info->dir)
{
grub_file_t file;
char *tmp;
tmp = xasprintf ("%s/%s", path, filename);
file = grub_file_open (tmp);
free (tmp);
if (! file)
return translate_error ();
st.st_size = file->size;
grub_file_close (file);
}
st.st_blksize = 512;
st.st_blocks = (st.st_size + 511) >> 9;
st.st_atime = st.st_mtime = st.st_ctime
= info->mtimeset ? info->mtime : 0;
fill (buf, filename, &st, 0);
return 0;
}
pathname = xstrdup (path); pathname = xstrdup (path);
/* Remove trailing '/'. */ /* Remove trailing '/'. */
@ -311,7 +335,7 @@ fuse_readdir (const char *path, void *buf,
&& pathname[grub_strlen (pathname) - 1] == '/') && pathname[grub_strlen (pathname) - 1] == '/')
pathname[grub_strlen (pathname) - 1] = 0; pathname[grub_strlen (pathname) - 1] = 0;
(fs->dir) (dev, pathname, call_fill); (fs->dir) (dev, pathname, fuse_readdir_call_fill, &ctx);
free (pathname); free (pathname);
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
return 0; return 0;