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:
parent
53d3e4e3df
commit
fc524edf65
35 changed files with 1723 additions and 1451 deletions
|
@ -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>
|
||||
|
||||
* docs/grub.texi (Multi-boot manual config): Fix typo for
|
||||
|
|
|
@ -85,6 +85,119 @@ grub_ls_list_devices (int longlist)
|
|||
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
|
||||
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;
|
||||
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);
|
||||
dev = grub_device_open (device_name);
|
||||
if (! dev)
|
||||
|
@ -221,10 +233,16 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
|
|||
}
|
||||
else if (fs)
|
||||
{
|
||||
struct grub_ls_list_files_ctx ctx = {
|
||||
.dirname = dirname,
|
||||
.all = all,
|
||||
.human = human
|
||||
};
|
||||
|
||||
if (longlist)
|
||||
(fs->dir) (dev, path, print_files_long);
|
||||
(fs->dir) (dev, path, print_files_long, &ctx);
|
||||
else
|
||||
(fs->dir) (dev, path, print_files);
|
||||
(fs->dir) (dev, path, print_files, &ctx);
|
||||
|
||||
if (grub_errno == GRUB_ERR_BAD_FILE_TYPE
|
||||
&& path[grub_strlen (path) - 1] != '/')
|
||||
|
@ -250,9 +268,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
|
|||
all = 1;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
if (longlist)
|
||||
print_files_long (p, &info);
|
||||
print_files_long (p, &info, &ctx);
|
||||
else
|
||||
print_files (p, &info);
|
||||
print_files (p, &info, &ctx);
|
||||
|
||||
grub_free (dirname);
|
||||
}
|
||||
|
|
|
@ -38,114 +38,125 @@ grub_strtosl (char *arg, char **end, int 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. */
|
||||
static int
|
||||
test_parse (char **args, int *argn, int argc)
|
||||
{
|
||||
int ret = 0, discard = 0, invert = 0;
|
||||
int file_exists;
|
||||
struct grub_dirhook_info file_info;
|
||||
|
||||
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);
|
||||
}
|
||||
struct test_parse_ctx ctx = {
|
||||
.ret = 0,
|
||||
.discard = 0,
|
||||
.invert = 0
|
||||
};
|
||||
|
||||
/* Here we have the real parsing. */
|
||||
while (*argn < argc)
|
||||
|
@ -157,14 +168,16 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (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;
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
@ -172,28 +185,32 @@ test_parse (char **args, int *argn, int argc)
|
|||
/* GRUB extension: lexicographical sorting. */
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
@ -202,7 +219,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn + 1], "-eq") == 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;
|
||||
continue;
|
||||
}
|
||||
|
@ -210,7 +227,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn + 1], "-ge") == 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;
|
||||
continue;
|
||||
}
|
||||
|
@ -218,7 +235,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn + 1], "-gt") == 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;
|
||||
continue;
|
||||
}
|
||||
|
@ -226,7 +243,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn + 1], "-le") == 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;
|
||||
continue;
|
||||
}
|
||||
|
@ -234,7 +251,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn + 1], "-lt") == 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;
|
||||
continue;
|
||||
}
|
||||
|
@ -242,7 +259,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn + 1], "-ne") == 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;
|
||||
continue;
|
||||
}
|
||||
|
@ -265,10 +282,10 @@ test_parse (char **args, int *argn, int argc)
|
|||
|
||||
if (grub_strcmp (args[*argn + 1], "-pgt") == 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
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
@ -283,22 +300,24 @@ test_parse (char **args, int *argn, int argc)
|
|||
int bias = 0;
|
||||
|
||||
/* Fetch fileinfo. */
|
||||
get_fileinfo (args[*argn]);
|
||||
file1 = file_info;
|
||||
file1exists = file_exists;
|
||||
get_fileinfo (args[*argn + 2]);
|
||||
get_fileinfo (args[*argn], &ctx);
|
||||
file1 = ctx.file_info;
|
||||
file1exists = ctx.file_exists;
|
||||
get_fileinfo (args[*argn + 2], &ctx);
|
||||
|
||||
if (args[*argn + 1][3])
|
||||
bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
|
||||
|
||||
if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0)
|
||||
update_val ((file1exists && ! file_exists)
|
||||
|| (file1.mtimeset && file_info.mtimeset
|
||||
&& file1.mtime + bias > file_info.mtime));
|
||||
update_val ((file1exists && ! ctx.file_exists)
|
||||
|| (file1.mtimeset && ctx.file_info.mtimeset
|
||||
&& file1.mtime + bias > ctx.file_info.mtime),
|
||||
&ctx);
|
||||
else
|
||||
update_val ((! file1exists && file_exists)
|
||||
|| (file1.mtimeset && file_info.mtimeset
|
||||
&& file1.mtime + bias < file_info.mtime));
|
||||
update_val ((! file1exists && ctx.file_exists)
|
||||
|| (file1.mtimeset && ctx.file_info.mtimeset
|
||||
&& file1.mtime + bias < ctx.file_info.mtime),
|
||||
&ctx);
|
||||
(*argn) += 3;
|
||||
continue;
|
||||
}
|
||||
|
@ -310,27 +329,27 @@ test_parse (char **args, int *argn, int argc)
|
|||
/* File tests. */
|
||||
if (grub_strcmp (args[*argn], "-d") == 0)
|
||||
{
|
||||
get_fileinfo (args[*argn + 1]);
|
||||
update_val (file_exists && file_info.dir);
|
||||
get_fileinfo (args[*argn + 1], &ctx);
|
||||
update_val (ctx.file_exists && ctx.file_info.dir, &ctx);
|
||||
(*argn) += 2;
|
||||
return ret;
|
||||
return ctx.ret;
|
||||
}
|
||||
|
||||
if (grub_strcmp (args[*argn], "-e") == 0)
|
||||
{
|
||||
get_fileinfo (args[*argn + 1]);
|
||||
update_val (file_exists);
|
||||
get_fileinfo (args[*argn + 1], &ctx);
|
||||
update_val (ctx.file_exists, &ctx);
|
||||
(*argn) += 2;
|
||||
return ret;
|
||||
return ctx.ret;
|
||||
}
|
||||
|
||||
if (grub_strcmp (args[*argn], "-f") == 0)
|
||||
{
|
||||
get_fileinfo (args[*argn + 1]);
|
||||
get_fileinfo (args[*argn + 1], &ctx);
|
||||
/* FIXME: check for other types. */
|
||||
update_val (file_exists && ! file_info.dir);
|
||||
update_val (ctx.file_exists && ! ctx.file_info.dir, &ctx);
|
||||
(*argn) += 2;
|
||||
return ret;
|
||||
return ctx.ret;
|
||||
}
|
||||
|
||||
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_filter_disable_compression ();
|
||||
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)
|
||||
grub_file_close (file);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
(*argn) += 2;
|
||||
return ret;
|
||||
return ctx.ret;
|
||||
}
|
||||
|
||||
/* String tests. */
|
||||
if (grub_strcmp (args[*argn], "-n") == 0)
|
||||
{
|
||||
update_val (args[*argn + 1][0]);
|
||||
update_val (args[*argn + 1][0], &ctx);
|
||||
|
||||
(*argn) += 2;
|
||||
continue;
|
||||
}
|
||||
if (grub_strcmp (args[*argn], "-z") == 0)
|
||||
{
|
||||
update_val (! args[*argn + 1][0]);
|
||||
update_val (! args[*argn + 1][0], &ctx);
|
||||
(*argn) += 2;
|
||||
continue;
|
||||
}
|
||||
|
@ -368,42 +387,42 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn], ")") == 0)
|
||||
{
|
||||
(*argn)++;
|
||||
return ret;
|
||||
return ctx.ret;
|
||||
}
|
||||
/* Recursively invoke if parenthesis. */
|
||||
if (grub_strcmp (args[*argn], "(") == 0)
|
||||
{
|
||||
(*argn)++;
|
||||
update_val (test_parse (args, argn, argc));
|
||||
update_val (test_parse (args, argn, argc), &ctx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strcmp (args[*argn], "!") == 0)
|
||||
{
|
||||
invert = ! invert;
|
||||
ctx.invert = ! ctx.invert;
|
||||
(*argn)++;
|
||||
continue;
|
||||
}
|
||||
if (grub_strcmp (args[*argn], "-a") == 0)
|
||||
{
|
||||
/* If current value is 0 second value is to be discarded. */
|
||||
discard = ! ret;
|
||||
ctx.discard = ! ctx.ret;
|
||||
(*argn)++;
|
||||
continue;
|
||||
}
|
||||
if (grub_strcmp (args[*argn], "-o") == 0)
|
||||
{
|
||||
/* If current value is 1 second value is to be discarded. */
|
||||
discard = ret;
|
||||
ctx.discard = ctx.ret;
|
||||
(*argn)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No test found. Interpret if as just a string. */
|
||||
update_val (args[*argn][0]);
|
||||
update_val (args[*argn][0], &ctx);
|
||||
(*argn)++;
|
||||
}
|
||||
return ret;
|
||||
return ctx.ret;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
|
|
@ -279,63 +279,75 @@ match_devices (const regex_t *regexp, int noparts)
|
|||
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 **
|
||||
match_files (const char *prefix, const char *suffix, const char *end,
|
||||
const regex_t *regexp)
|
||||
{
|
||||
struct match_files_ctx ctx = {
|
||||
.regexp = regexp,
|
||||
.nfile = 0,
|
||||
.files = 0
|
||||
};
|
||||
int i;
|
||||
char **files;
|
||||
unsigned nfile;
|
||||
char *dir;
|
||||
const char *path;
|
||||
char *device_name;
|
||||
grub_fs_t fs;
|
||||
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;
|
||||
device_name = 0;
|
||||
grub_error_push ();
|
||||
|
||||
dir = make_dir (prefix, suffix, end);
|
||||
if (! dir)
|
||||
ctx.dir = make_dir (prefix, suffix, end);
|
||||
if (! ctx.dir)
|
||||
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);
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
@ -344,33 +356,33 @@ match_files (const char *prefix, const char *suffix, const char *end,
|
|||
if (! fs)
|
||||
goto fail;
|
||||
|
||||
if (dir[0] == '(')
|
||||
if (ctx.dir[0] == '(')
|
||||
{
|
||||
path = grub_strchr (dir, ')');
|
||||
path = grub_strchr (ctx.dir, ')');
|
||||
if (!path)
|
||||
goto fail;
|
||||
path++;
|
||||
}
|
||||
else
|
||||
path = dir;
|
||||
path = ctx.dir;
|
||||
|
||||
if (fs->dir (dev, path, match))
|
||||
if (fs->dir (dev, path, match_files_iter, &ctx))
|
||||
goto fail;
|
||||
|
||||
grub_free (dir);
|
||||
grub_free (ctx.dir);
|
||||
grub_device_close (dev);
|
||||
grub_free (device_name);
|
||||
grub_error_pop ();
|
||||
return files;
|
||||
return ctx.files;
|
||||
|
||||
fail:
|
||||
|
||||
grub_free (dir);
|
||||
grub_free (ctx.dir);
|
||||
|
||||
for (i = 0; files && files[i]; i++)
|
||||
grub_free (files[i]);
|
||||
for (i = 0; ctx.files && ctx.files[i]; i++)
|
||||
grub_free (ctx.files[i]);
|
||||
|
||||
grub_free (files);
|
||||
grub_free (ctx.files);
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
@ -381,28 +393,42 @@ match_files (const char *prefix, const char *suffix, const char *end,
|
|||
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
|
||||
check_file (const char *dir, const char *basename)
|
||||
{
|
||||
struct check_file_ctx ctx = {
|
||||
.basename = basename,
|
||||
.found = 0
|
||||
};
|
||||
grub_fs_t fs;
|
||||
grub_device_t dev;
|
||||
int found = 0;
|
||||
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);
|
||||
dev = grub_device_open (device_name);
|
||||
if (! dev)
|
||||
|
@ -422,14 +448,14 @@ check_file (const char *dir, const char *basename)
|
|||
else
|
||||
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)
|
||||
found = 1;
|
||||
ctx.found = 1;
|
||||
|
||||
fail:
|
||||
grub_errno = 0;
|
||||
|
||||
return found;
|
||||
return ctx.found;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -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
|
||||
grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
unsigned int i;
|
||||
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;
|
||||
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 `..'. */
|
||||
node = grub_zalloc (sizeof (*node));
|
||||
if (!node)
|
||||
return 1;
|
||||
|
||||
*node = *dir;
|
||||
if (hook (".", GRUB_FSHELP_DIR, node))
|
||||
if (hook (".", GRUB_FSHELP_DIR, node, hook_data))
|
||||
return 1;
|
||||
if (dir->parent)
|
||||
{
|
||||
|
@ -418,7 +418,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (!node)
|
||||
return 1;
|
||||
*node = *dir->parent;
|
||||
if (hook ("..", GRUB_FSHELP_DIR, node))
|
||||
if (hook ("..", GRUB_FSHELP_DIR, node, hook_data))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,8 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
if (grub_affs_create_node (next, &file))
|
||||
if (grub_affs_create_node (dir, hook, hook_data, &node, &hashtable,
|
||||
next, &file))
|
||||
return 1;
|
||||
|
||||
next = grub_be_to_cpu32 (file.next);
|
||||
|
@ -545,31 +546,37 @@ aftime2ctime (const struct grub_affs_time *t)
|
|||
+ 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
|
||||
grub_affs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_affs_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_affs_data *data = 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);
|
||||
|
||||
data = grub_affs_mount (device->disk);
|
||||
|
@ -581,7 +588,7 @@ grub_affs_dir (grub_device_t device, const char *path,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_affs_iterate_dir (fdiro, iterate);
|
||||
grub_affs_iterate_dir (fdiro, grub_affs_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if (data && fdiro != &data->diropen)
|
||||
|
|
|
@ -173,6 +173,15 @@ struct grub_bfs_data
|
|||
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
|
||||
read_extent (grub_disk_t disk,
|
||||
const struct grub_bfs_superblock *sb,
|
||||
|
@ -413,7 +422,9 @@ static int
|
|||
iterate_in_b_tree (grub_disk_t disk,
|
||||
const struct grub_bfs_superblock *sb,
|
||||
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;
|
||||
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);
|
||||
c = key_data[end];
|
||||
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;
|
||||
key_data[end] = c;
|
||||
}
|
||||
|
@ -844,46 +856,52 @@ mount (grub_disk_t disk, struct grub_bfs_superblock *sb)
|
|||
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
|
||||
grub_bfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook_in) (const char *filename,
|
||||
const struct grub_dirhook_info * info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_bfs_superblock sb;
|
||||
struct grub_bfs_dir_ctx ctx = {
|
||||
.device = device,
|
||||
.hook = hook,
|
||||
.hook_data = hook_data
|
||||
};
|
||||
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)
|
||||
{
|
||||
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);
|
||||
err = mount (device->disk, &ctx.sb);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -891,14 +909,15 @@ grub_bfs_dir (grub_device_t device, const char *path,
|
|||
union
|
||||
{
|
||||
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;
|
||||
err = find_file (path, device->disk, &sb, &ino.ino);
|
||||
err = find_file (path, device->disk, &ctx.sb, &ino.ino);
|
||||
if (err)
|
||||
return err;
|
||||
if (((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) != ATTR_DIR))
|
||||
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;
|
||||
|
|
|
@ -1491,8 +1491,7 @@ find_path (struct grub_btrfs_data *data,
|
|||
|
||||
static grub_err_t
|
||||
grub_btrfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_btrfs_data *data = grub_btrfs_mount (device);
|
||||
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)];
|
||||
cdirel->name[grub_le_to_cpu16 (cdirel->n)] = 0;
|
||||
info.dir = (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY);
|
||||
if (hook (cdirel->name, &info))
|
||||
if (hook (cdirel->name, &info, hook_data))
|
||||
goto out;
|
||||
cdirel->name[grub_le_to_cpu16 (cdirel->n)] = c;
|
||||
}
|
||||
|
|
|
@ -513,8 +513,7 @@ handle_symlink (struct grub_cpio_data *data,
|
|||
|
||||
static grub_err_t
|
||||
grub_cpio_dir (grub_device_t device, const char *path_in,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_cpio_data *data;
|
||||
grub_disk_addr_t ofs;
|
||||
|
@ -575,7 +574,7 @@ grub_cpio_dir (grub_device_t device, const char *path_in,
|
|||
info.mtime = mtime;
|
||||
info.mtimeset = 1;
|
||||
|
||||
if (hook (n, &info))
|
||||
if (hook (n, &info, hook_data))
|
||||
{
|
||||
grub_free (name);
|
||||
goto fail;
|
||||
|
|
|
@ -692,10 +692,7 @@ grub_ext2_read_symlink (grub_fshelp_node_t node)
|
|||
|
||||
static int
|
||||
grub_ext2_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
unsigned int fpos = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
if (hook (filename, type, fdiro))
|
||||
if (hook (filename, type, fdiro, hook_data))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -858,59 +855,69 @@ grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_ext2_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
/* Context for grub_ext2_dir. */
|
||||
struct grub_ext2_dir_ctx
|
||||
{
|
||||
struct grub_ext2_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0;
|
||||
grub_fs_dir_hook_t hook;
|
||||
void *hook_data;
|
||||
struct grub_ext2_data *data;
|
||||
};
|
||||
|
||||
auto int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node);
|
||||
/* Helper for grub_ext2_dir. */
|
||||
static int
|
||||
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,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node)
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
if (! node->inode_read)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
if (! node->inode_read)
|
||||
{
|
||||
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);
|
||||
grub_ext2_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_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);
|
||||
|
||||
data = grub_ext2_mount (device->disk);
|
||||
if (! data)
|
||||
ctx.data = grub_ext2_mount (device->disk);
|
||||
if (! ctx.data)
|
||||
goto fail;
|
||||
|
||||
grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_ext2_iterate_dir,
|
||||
grub_ext2_read_symlink, GRUB_FSHELP_DIR);
|
||||
grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro,
|
||||
grub_ext2_iterate_dir, grub_ext2_read_symlink,
|
||||
GRUB_FSHELP_DIR);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_ext2_iterate_dir (fdiro, iterate);
|
||||
grub_ext2_iterate_dir (fdiro, grub_ext2_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if (fdiro != &data->diropen)
|
||||
if (fdiro != &ctx.data->diropen)
|
||||
grub_free (fdiro);
|
||||
grub_free (data);
|
||||
grub_free (ctx.data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
|
|
@ -844,8 +844,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
|
|||
static char *
|
||||
grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
||||
const char *path, const char *origpath,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
char *dirname, *dirp;
|
||||
int call_hook;
|
||||
|
@ -905,7 +904,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
#endif
|
||||
if (*dirname == '\0' && call_hook)
|
||||
{
|
||||
if (hook (ctxt.filename, &info))
|
||||
if (hook (ctxt.filename, &info, hook_data))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
|
@ -926,7 +925,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
data->cur_cluster_num = ~0U;
|
||||
|
||||
if (call_hook)
|
||||
hook (ctxt.filename, &info);
|
||||
hook (ctxt.filename, &info, hook_data);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -946,9 +945,8 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
|
||||
void *hook_data)
|
||||
{
|
||||
struct grub_fat_data *data = 0;
|
||||
grub_disk_t disk = device->disk;
|
||||
|
@ -976,7 +974,7 @@ grub_fat_dir (grub_device_t device, const char *path,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -1004,7 +1002,7 @@ grub_fat_open (grub_file_t file, const char *name)
|
|||
|
||||
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)
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -27,184 +27,199 @@
|
|||
|
||||
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
|
||||
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
|
||||
iterate over all directory entries in the current node.
|
||||
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
|
||||
error is generated if the node is not of the expected type. Make
|
||||
sure you use the NESTED_FUNC_ATTR macro for HOOK, this is required
|
||||
because GCC has a nasty bug when using regparm=3. */
|
||||
error is generated if the node is not of the expected type. */
|
||||
grub_err_t
|
||||
grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
|
||||
grub_fshelp_node_t *foundnode,
|
||||
int (*iterate_dir) (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR (*hook)
|
||||
(const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node)),
|
||||
char *(*read_symlink) (grub_fshelp_node_t node),
|
||||
iterate_dir_func iterate_dir,
|
||||
read_symlink_func read_symlink,
|
||||
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;
|
||||
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] != '/')
|
||||
{
|
||||
|
@ -212,14 +227,14 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
err = find_file (path, rootnode, foundnode);
|
||||
err = find_file (path, rootnode, foundnode, iterate_dir, read_symlink, &ctx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* 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"));
|
||||
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 0;
|
||||
|
|
|
@ -1151,9 +1151,8 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
|
|||
|
||||
|
||||
static grub_err_t
|
||||
grub_hfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
|
||||
void *hook_data)
|
||||
{
|
||||
int inode;
|
||||
|
||||
|
@ -1184,14 +1183,14 @@ grub_hfs_dir (grub_device_t device, const char *path,
|
|||
info.dir = 1;
|
||||
info.mtimeset = 1;
|
||||
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)
|
||||
{
|
||||
info.dir = 0;
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800;
|
||||
return hook (fname, &info);
|
||||
return hook (fname, &info, hook_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -766,10 +766,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
|
||||
static int
|
||||
grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -825,7 +822,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
node->size = 0;
|
||||
node->fileid = grub_be_to_cpu32 (fileinfo->parentid);
|
||||
|
||||
ret = hook ("..", GRUB_FSHELP_DIR, node);
|
||||
ret = hook ("..", GRUB_FSHELP_DIR, node, hook_data);
|
||||
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->fileid = grub_be_to_cpu32 (fileinfo->fileid);
|
||||
|
||||
ret = hook (filename, type, node);
|
||||
ret = hook (filename, type, node, hook_data);
|
||||
|
||||
grub_free (filename);
|
||||
|
||||
|
@ -895,7 +892,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (!fsnode)
|
||||
return 1;
|
||||
*fsnode = *dir;
|
||||
if (hook (".", GRUB_FSHELP_DIR, fsnode))
|
||||
if (hook (".", GRUB_FSHELP_DIR, fsnode, hook_data))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -978,32 +975,39 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
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
|
||||
grub_hfsplus_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_hfsplus_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_hfsplus_data *data = 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);
|
||||
|
||||
data = grub_hfsplus_mount (device->disk);
|
||||
|
@ -1018,7 +1022,7 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
|
|||
goto fail;
|
||||
|
||||
/* Iterate over all entries in this directory. */
|
||||
grub_hfsplus_iterate_dir (fdiro, iterate);
|
||||
grub_hfsplus_iterate_dir (fdiro, grub_hfsplus_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if (data && fdiro != &data->dirroot)
|
||||
|
|
|
@ -521,10 +521,7 @@ get_node_size (grub_fshelp_node_t node)
|
|||
|
||||
static int
|
||||
grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_iso9660_dir dirent;
|
||||
grub_off_t offset = 0;
|
||||
|
@ -828,7 +825,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
symlink = 0;
|
||||
was_continue = 0;
|
||||
}
|
||||
if (hook (filename, type, node))
|
||||
if (hook (filename, type, node, hook_data))
|
||||
{
|
||||
if (filename_alloc)
|
||||
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
|
||||
grub_iso9660_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_iso9660_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_iso9660_data *data = 0;
|
||||
struct grub_fshelp_node rootnode;
|
||||
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);
|
||||
|
||||
data = grub_iso9660_mount (device->disk);
|
||||
|
@ -891,7 +895,7 @@ grub_iso9660_dir (grub_device_t device, const char *path,
|
|||
goto fail;
|
||||
|
||||
/* 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)
|
||||
grub_free (foundnode);
|
||||
|
|
|
@ -799,8 +799,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino)
|
|||
|
||||
static grub_err_t
|
||||
grub_jfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_jfs_data *data = 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;
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_le_to_cpu32 (inode.mtime.sec);
|
||||
if (hook (diro->name, &info))
|
||||
if (hook (diro->name, &info, hook_data))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -536,8 +536,7 @@ grub_minix_mount (grub_disk_t disk)
|
|||
|
||||
static grub_err_t
|
||||
grub_minix_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_minix_data *data = 0;
|
||||
unsigned int pos = 0;
|
||||
|
@ -590,7 +589,7 @@ grub_minix_dir (grub_device_t device, const char *path,
|
|||
info.mtimeset = 1;
|
||||
info.mtime = grub_minix_to_cpu32 (data->inode.mtime);
|
||||
|
||||
if (hook (filename, &info) ? 1 : 0)
|
||||
if (hook (filename, &info, hook_data) ? 1 : 0)
|
||||
break;
|
||||
|
||||
/* Load the old inode back in. */
|
||||
|
|
|
@ -870,10 +870,7 @@ grub_nilfs2_read_symlink (grub_fshelp_node_t node)
|
|||
|
||||
static int
|
||||
grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_off_t fpos = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
if (hook (filename, type, fdiro))
|
||||
if (hook (filename, type, fdiro, hook_data))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1032,60 +1029,69 @@ grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
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
|
||||
grub_nilfs2_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info * info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_nilfs2_data *data = 0;
|
||||
struct grub_nilfs2_dir_ctx ctx = {
|
||||
.hook = hook,
|
||||
.hook_data = hook_data
|
||||
};
|
||||
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);
|
||||
|
||||
data = grub_nilfs2_mount (device->disk);
|
||||
if (!data)
|
||||
ctx.data = grub_nilfs2_mount (device->disk);
|
||||
if (!ctx.data)
|
||||
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_FSHELP_DIR);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_nilfs2_iterate_dir (fdiro, iterate);
|
||||
grub_nilfs2_iterate_dir (fdiro, grub_nilfs2_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if (fdiro != &data->diropen)
|
||||
if (fdiro != &ctx.data->diropen)
|
||||
grub_free (fdiro);
|
||||
grub_free (data);
|
||||
grub_free (ctx.data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
|
|
@ -600,10 +600,7 @@ free_file (struct grub_ntfs_file *mft)
|
|||
|
||||
static int
|
||||
list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_uint8_t *np;
|
||||
int ns;
|
||||
|
@ -667,7 +664,7 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
|
|||
if (namespace)
|
||||
type |= GRUB_FSHELP_CASE_INSENSITIVE;
|
||||
|
||||
if (hook (ustr, type, fdiro))
|
||||
if (hook (ustr, type, fdiro, hook_data))
|
||||
{
|
||||
grub_free (ustr);
|
||||
return 1;
|
||||
|
@ -778,10 +775,7 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node)
|
|||
|
||||
static int
|
||||
grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_uint8_t *bitmap;
|
||||
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 */
|
||||
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)
|
||||
goto done;
|
||||
|
||||
|
@ -909,7 +903,8 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
|| (fixup (indx, mft->data->idx_size,
|
||||
(const grub_uint8_t *) "INDX")))
|
||||
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)
|
||||
goto done;
|
||||
}
|
||||
|
@ -1017,33 +1012,39 @@ fail:
|
|||
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
|
||||
grub_ntfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_ntfs_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_ntfs_data *data = 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);
|
||||
|
||||
data = grub_ntfs_mount (device->disk);
|
||||
|
@ -1056,7 +1057,7 @@ grub_ntfs_dir (grub_device_t device, const char *path,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_ntfs_iterate_dir (fdiro, iterate);
|
||||
grub_ntfs_iterate_dir (fdiro, grub_ntfs_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if ((fdiro) && (fdiro != &data->cmft))
|
||||
|
|
|
@ -718,10 +718,8 @@ grub_reiserfs_mount (grub_disk_t disk)
|
|||
/* Call HOOK for each file in directory ITEM. */
|
||||
static int
|
||||
grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook,
|
||||
void *hook_data)
|
||||
{
|
||||
struct grub_reiserfs_data *data = item->data;
|
||||
struct grub_reiserfs_block_header *block_header = 0;
|
||||
|
@ -946,7 +944,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
|
|||
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",
|
||||
entry_name, entry_type);
|
||||
|
@ -1254,32 +1252,40 @@ grub_reiserfs_close (grub_file_t file)
|
|||
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. */
|
||||
static grub_err_t
|
||||
grub_reiserfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_reiserfs_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_reiserfs_data *data = 0;
|
||||
struct grub_fshelp_node root, *found;
|
||||
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);
|
||||
data = grub_reiserfs_mount (device->disk);
|
||||
if (! data)
|
||||
|
@ -1300,7 +1306,7 @@ grub_reiserfs_dir (grub_device_t device, const char *path,
|
|||
grub_reiserfs_read_symlink, GRUB_FSHELP_DIR);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
grub_reiserfs_iterate_dir (found, iterate);
|
||||
grub_reiserfs_iterate_dir (found, grub_reiserfs_dir_iter, &ctx);
|
||||
grub_free (data);
|
||||
grub_dl_unref (my_mod);
|
||||
return GRUB_ERR_NONE;
|
||||
|
|
|
@ -171,10 +171,7 @@ grub_romfs_read_symlink (grub_fshelp_node_t node)
|
|||
|
||||
static int
|
||||
grub_romfs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_disk_addr_t caddr;
|
||||
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);
|
||||
return 1;
|
||||
|
@ -316,30 +313,36 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
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
|
||||
grub_romfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_romfs_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_romfs_data *data = 0;
|
||||
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);
|
||||
if (! data)
|
||||
goto fail;
|
||||
|
@ -352,7 +355,7 @@ grub_romfs_dir (grub_device_t device, const char *path,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_romfs_iterate_dir (fdiro, iterate);
|
||||
grub_romfs_iterate_dir (fdiro, grub_romfs_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
grub_free (data);
|
||||
|
|
|
@ -460,12 +460,48 @@ grub_sfs_read_symlink (grub_fshelp_node_t node)
|
|||
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
|
||||
grub_sfs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_fshelp_node *node = 0;
|
||||
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;
|
||||
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);
|
||||
if (!objc_data)
|
||||
goto fail;
|
||||
|
@ -570,9 +566,10 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
else
|
||||
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),
|
||||
type, grub_be_to_cpu32 (obj->mtime)))
|
||||
type, grub_be_to_cpu32 (obj->mtime),
|
||||
hook, hook_data))
|
||||
{
|
||||
grub_free (objc_data);
|
||||
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
|
||||
grub_sfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_sfs_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_sfs_data *data = 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);
|
||||
|
||||
data = grub_sfs_mount (device->disk);
|
||||
|
@ -691,7 +694,7 @@ grub_sfs_dir (grub_device_t device, const char *path,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_sfs_iterate_dir (fdiro, iterate);
|
||||
grub_sfs_iterate_dir (fdiro, grub_sfs_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if (data && fdiro != &data->diropen)
|
||||
|
|
|
@ -478,10 +478,7 @@ grub_squash_read_symlink (grub_fshelp_node_t node)
|
|||
|
||||
static int
|
||||
grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_uint32_t off;
|
||||
grub_uint32_t endoff;
|
||||
|
@ -514,7 +511,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 0;
|
||||
grub_memcpy (node, dir,
|
||||
sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
|
||||
if (hook (".", GRUB_FSHELP_DIR, node))
|
||||
if (hook (".", GRUB_FSHELP_DIR, node, hook_data))
|
||||
return 1;
|
||||
|
||||
if (dir->stsize != 1)
|
||||
|
@ -536,7 +533,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (err)
|
||||
return 0;
|
||||
|
||||
if (hook ("..", GRUB_FSHELP_DIR, node))
|
||||
if (hook ("..", GRUB_FSHELP_DIR, node, hook_data))
|
||||
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_offset = grub_le_to_cpu16 (di.ino_offset);
|
||||
node->stsize++;
|
||||
r = hook (buf, filetype, node);
|
||||
r = hook (buf, filetype, node, hook_data);
|
||||
|
||||
grub_free (buf);
|
||||
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
|
||||
grub_squash_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
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_le_to_cpu32 (node->ino.mtime);
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
||||
struct grub_squash_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_squash_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0;
|
||||
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_squash_read_symlink, GRUB_FSHELP_DIR);
|
||||
if (!grub_errno)
|
||||
grub_squash_iterate_dir (fdiro, iterate);
|
||||
grub_squash_iterate_dir (fdiro, grub_squash_dir_iter, &ctx);
|
||||
|
||||
squash_unmount (data);
|
||||
|
||||
|
|
|
@ -843,10 +843,7 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
|
|||
|
||||
static int
|
||||
grub_udf_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_fshelp_node_t child;
|
||||
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. */
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
/* This is the parent directory. */
|
||||
if (hook ("..", GRUB_FSHELP_DIR, child))
|
||||
if (hook ("..", GRUB_FSHELP_DIR, child, hook_data))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
@ -911,7 +908,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (!filename)
|
||||
grub_print_error ();
|
||||
|
||||
if (filename && hook (filename, type, child))
|
||||
if (filename && hook (filename, type, child, hook_data))
|
||||
{
|
||||
grub_free (filename);
|
||||
return 1;
|
||||
|
@ -1012,58 +1009,64 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
|
|||
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
|
||||
grub_udf_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_udf_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_udf_data *data = 0;
|
||||
struct grub_fshelp_node *rootnode = 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);
|
||||
|
||||
data = grub_udf_mount (device->disk);
|
||||
|
@ -1083,7 +1086,7 @@ grub_udf_dir (grub_device_t device, const char *path,
|
|||
GRUB_FSHELP_DIR))
|
||||
goto fail;
|
||||
|
||||
grub_udf_iterate_dir (foundnode, iterate);
|
||||
grub_udf_iterate_dir (foundnode, grub_udf_dir_iter, &ctx);
|
||||
|
||||
if (foundnode != rootnode)
|
||||
grub_free (foundnode);
|
||||
|
|
|
@ -625,8 +625,7 @@ grub_ufs_mount (grub_disk_t disk)
|
|||
|
||||
static grub_err_t
|
||||
grub_ufs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_ufs_data *data;
|
||||
unsigned int pos = 0;
|
||||
|
@ -697,7 +696,7 @@ grub_ufs_dir (grub_device_t device, const char *path,
|
|||
#endif
|
||||
info.mtimeset = 1;
|
||||
|
||||
if (hook (filename, &info))
|
||||
if (hook (filename, &info, hook_data))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
grub_xfs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
|
||||
auto int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, const char *filename);
|
||||
|
||||
int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, const char *filename)
|
||||
{
|
||||
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);
|
||||
}
|
||||
struct grub_xfs_iterate_dir_ctx ctx = {
|
||||
.hook = hook,
|
||||
.hook_data = hook_data,
|
||||
.diro = diro
|
||||
};
|
||||
|
||||
switch (diro->inode.format)
|
||||
{
|
||||
|
@ -508,10 +518,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
}
|
||||
|
||||
/* Synthesize the direntries for `.' and `..'. */
|
||||
if (call_hook (diro->ino, "."))
|
||||
if (iterate_dir_call_hook (diro->ino, ".", &ctx))
|
||||
return 1;
|
||||
|
||||
if (call_hook (parent, ".."))
|
||||
if (iterate_dir_call_hook (parent, "..", &ctx))
|
||||
return 1;
|
||||
|
||||
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);
|
||||
name[de->len] = '\0';
|
||||
if (call_hook (ino, name))
|
||||
if (iterate_dir_call_hook (ino, name, &ctx))
|
||||
return 1;
|
||||
|
||||
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. */
|
||||
filename[direntry->len] = '\0';
|
||||
|
||||
if (call_hook (direntry->inode, filename))
|
||||
if (iterate_dir_call_hook (direntry->inode, filename, &ctx))
|
||||
{
|
||||
grub_free (dirblock);
|
||||
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
|
||||
grub_xfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
struct grub_xfs_dir_ctx ctx = { hook, hook_data };
|
||||
struct grub_xfs_data *data = 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);
|
||||
|
||||
data = grub_xfs_mount (device->disk);
|
||||
|
@ -742,7 +758,7 @@ grub_xfs_dir (grub_device_t device, const char *path,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_xfs_iterate_dir (fdiro, iterate);
|
||||
grub_xfs_iterate_dir (fdiro, grub_xfs_dir_iter, &ctx);
|
||||
|
||||
fail:
|
||||
if (fdiro != &data->diropen)
|
||||
|
|
|
@ -253,6 +253,14 @@ struct grub_zfs_data
|
|||
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_uint64_t algo,
|
||||
void *nonce,
|
||||
|
@ -1790,8 +1798,9 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
|
|||
|
||||
static int
|
||||
mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
|
||||
int NESTED_FUNC_ATTR (*hook) (const char *name,
|
||||
grub_uint64_t val))
|
||||
int (*hook) (const char *name, grub_uint64_t val,
|
||||
struct grub_zfs_dir_ctx *ctx),
|
||||
struct grub_zfs_dir_ctx *ctx)
|
||||
{
|
||||
int i, chunks;
|
||||
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,
|
||||
(int)mzap_ent[i].mze_cd);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2054,12 +2063,11 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
|||
static int
|
||||
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
||||
grub_size_t name_elem_length,
|
||||
int NESTED_FUNC_ATTR (*hook) (const void *name,
|
||||
grub_size_t name_length,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize),
|
||||
struct grub_zfs_data *data)
|
||||
int (*hook) (const void *name, grub_size_t name_length,
|
||||
const void *val_in,
|
||||
grub_size_t nelem, grub_size_t elemsize,
|
||||
void *data),
|
||||
void *hook_data, struct grub_zfs_data *data)
|
||||
{
|
||||
zap_leaf_phys_t *l;
|
||||
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,
|
||||
val, le->le_value_length, le->le_int_size))
|
||||
val, le->le_value_length, le->le_int_size, hook_data))
|
||||
{
|
||||
grub_free (l);
|
||||
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");
|
||||
}
|
||||
|
||||
/* 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
|
||||
zap_iterate_u64 (dnode_end_t * zap_dnode,
|
||||
int NESTED_FUNC_ATTR (*hook) (const char *name,
|
||||
grub_uint64_t val),
|
||||
struct grub_zfs_data *data)
|
||||
int (*hook) (const char *name, grub_uint64_t val,
|
||||
struct grub_zfs_dir_ctx *ctx),
|
||||
struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx)
|
||||
{
|
||||
grub_uint64_t block_type;
|
||||
int size;
|
||||
|
@ -2234,23 +2266,6 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
|
|||
int ret;
|
||||
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. */
|
||||
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
|
||||
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)
|
||||
{
|
||||
grub_dprintf ("zfs", "micro zap\n");
|
||||
ret = mzap_iterate (zapbuf, endian, size, hook);
|
||||
ret = mzap_iterate (zapbuf, endian, size, hook, ctx);
|
||||
grub_free (zapbuf);
|
||||
return ret;
|
||||
}
|
||||
else if (block_type == ZBT_HEADER)
|
||||
{
|
||||
struct zap_iterate_u64_ctx transform_ctx = {
|
||||
.hook = hook,
|
||||
.dir_ctx = ctx
|
||||
};
|
||||
|
||||
grub_dprintf ("zfs", "fat zap\n");
|
||||
/* 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);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2282,12 +2303,11 @@ zap_iterate_u64 (dnode_end_t * zap_dnode,
|
|||
static int
|
||||
zap_iterate (dnode_end_t * zap_dnode,
|
||||
grub_size_t nameelemlen,
|
||||
int NESTED_FUNC_ATTR (*hook) (const void *name,
|
||||
grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem,
|
||||
grub_size_t elemsize),
|
||||
struct grub_zfs_data *data)
|
||||
int (*hook) (const void *name, grub_size_t namelen,
|
||||
const void *val_in,
|
||||
grub_size_t nelem, grub_size_t elemsize,
|
||||
void *data),
|
||||
void *hook_data, struct grub_zfs_data *data)
|
||||
{
|
||||
grub_uint64_t block_type;
|
||||
void *zapbuf;
|
||||
|
@ -2312,7 +2332,8 @@ zap_iterate (dnode_end_t * zap_dnode,
|
|||
{
|
||||
grub_dprintf ("zfs", "fat zap\n");
|
||||
/* 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);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2826,6 +2847,61 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
|
|||
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
|
||||
dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
||||
dnode_end_t * dn, int *isfs,
|
||||
|
@ -2835,57 +2911,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
|||
const char *ptr_at, *filename;
|
||||
grub_uint64_t headobj;
|
||||
grub_uint64_t keychainobj;
|
||||
grub_uint64_t salt;
|
||||
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, '@');
|
||||
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);
|
||||
if (grub_zfs_load_key && keychainobj)
|
||||
{
|
||||
struct dnode_get_fullpath_ctx ctx = {
|
||||
.subvol = subvol,
|
||||
.keyn = 0
|
||||
};
|
||||
dnode_end_t keychain_dn, props_dn;
|
||||
grub_uint64_t propsobj;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
err = 0;
|
||||
grub_errno = 0;
|
||||
salt = 0;
|
||||
ctx.salt = 0;
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
|
@ -2988,7 +3018,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
|||
return err;
|
||||
}
|
||||
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]));
|
||||
if (!subvol->keyring)
|
||||
{
|
||||
|
@ -2996,7 +3026,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
|||
grub_free (snapname);
|
||||
return err;
|
||||
}
|
||||
zap_iterate (&keychain_dn, 8, load_zap_key, data);
|
||||
zap_iterate (&keychain_dn, 8, load_zap_key, &ctx, data);
|
||||
}
|
||||
|
||||
if (snapname)
|
||||
|
@ -3748,108 +3778,122 @@ fill_fs_info (struct grub_dirhook_info *info,
|
|||
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
|
||||
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;
|
||||
grub_err_t err;
|
||||
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);
|
||||
if (! data)
|
||||
|
@ -3860,6 +3904,8 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
zfs_unmount (data);
|
||||
return err;
|
||||
}
|
||||
ctx.data = data;
|
||||
|
||||
if (isfs)
|
||||
{
|
||||
grub_uint64_t childobj, headobj;
|
||||
|
@ -3868,7 +3914,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (err)
|
||||
|
@ -3899,7 +3945,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
return err;
|
||||
}
|
||||
|
||||
zap_iterate_u64 (&dn, iterate_zap_snap, data);
|
||||
zap_iterate_u64 (&dn, iterate_zap_snap, data, &ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3908,7 +3954,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
|||
zfs_unmount (data);
|
||||
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);
|
||||
return grub_errno;
|
||||
|
|
|
@ -105,7 +105,8 @@ grub_mini_print_devices (const char *name, void *data __attribute__ ((unused)))
|
|||
|
||||
static int
|
||||
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 ? "/" : "");
|
||||
|
||||
|
@ -160,7 +161,7 @@ grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)),
|
|||
}
|
||||
else if (fs)
|
||||
{
|
||||
(fs->dir) (dev, path, grub_mini_print_files);
|
||||
(fs->dir) (dev, path, grub_mini_print_files, NULL);
|
||||
grub_xputs ("\n");
|
||||
grub_refresh ();
|
||||
}
|
||||
|
|
|
@ -65,8 +65,7 @@ struct grub_hostfs_data
|
|||
|
||||
static grub_err_t
|
||||
grub_hostfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
grub_fs_dir_hook_t hook, void *hook_data)
|
||||
{
|
||||
DIR *dir;
|
||||
|
||||
|
@ -91,7 +90,7 @@ grub_hostfs_dir (grub_device_t device, const char *path,
|
|||
break;
|
||||
|
||||
info.dir = !! is_dir (path, de->d_name);
|
||||
hook (de->d_name, &info);
|
||||
hook (de->d_name, &info, hook_data);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,11 @@ grub_fs_autoload_hook_t grub_fs_autoload_hook = 0;
|
|||
/* Helper for grub_fs_probe. */
|
||||
static int
|
||||
probe_dummy_iter (const char *filename __attribute__ ((unused)),
|
||||
const struct grub_dirhook_info *info __attribute__ ((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
const struct grub_dirhook_info *info __attribute__ ((unused)),
|
||||
void *data __attribute__ ((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_fs_t
|
||||
grub_fs_probe (grub_device_t device)
|
||||
|
@ -69,7 +70,7 @@ grub_fs_probe (grub_device_t device)
|
|||
}
|
||||
else
|
||||
#endif
|
||||
(p->dir) (device, "/", probe_dummy_iter);
|
||||
(p->dir) (device, "/", probe_dummy_iter, NULL);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
return p;
|
||||
|
||||
|
@ -93,7 +94,7 @@ grub_fs_probe (grub_device_t device)
|
|||
{
|
||||
p = grub_fs_list;
|
||||
|
||||
(p->dir) (device, "/", probe_dummy_iter);
|
||||
(p->dir) (device, "/", probe_dummy_iter, NULL);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
count--;
|
||||
|
|
|
@ -1017,49 +1017,66 @@ grub_xnu_check_os_bundle_required (char *plistname,
|
|||
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 */
|
||||
grub_err_t
|
||||
grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
|
||||
int maxrecursion)
|
||||
{
|
||||
struct grub_xnu_scan_dir_for_kexts_ctx ctx = {
|
||||
.dirname = dirname,
|
||||
.osbundlerequired = osbundlerequired,
|
||||
.maxrecursion = maxrecursion
|
||||
};
|
||||
grub_device_t dev;
|
||||
char *device_name;
|
||||
grub_fs_t fs;
|
||||
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)
|
||||
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++;
|
||||
|
||||
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_free (device_name);
|
||||
|
@ -1083,60 +1100,78 @@ grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
|
|||
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) */
|
||||
grub_err_t
|
||||
grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
|
||||
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;
|
||||
char *plistname = 0;
|
||||
char *newdirname;
|
||||
char *newpath;
|
||||
char *device_name;
|
||||
grub_fs_t fs;
|
||||
const char *path;
|
||||
char *binsuffix;
|
||||
int usemacos = 0;
|
||||
grub_file_t binfile;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
ctx.newdirname = grub_malloc (grub_strlen (dirname) + 20);
|
||||
if (! ctx.newdirname)
|
||||
return grub_errno;
|
||||
grub_strcpy (newdirname, dirname);
|
||||
newdirname[grub_strlen (dirname)] = '/';
|
||||
newdirname[grub_strlen (dirname) + 1] = 0;
|
||||
grub_strcpy (ctx.newdirname, dirname);
|
||||
ctx.newdirname[grub_strlen (dirname)] = '/';
|
||||
ctx.newdirname[grub_strlen (dirname) + 1] = 0;
|
||||
device_name = grub_file_get_device_name (dirname);
|
||||
dev = grub_device_open (device_name);
|
||||
if (dev)
|
||||
|
@ -1148,18 +1183,18 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
|
|||
else
|
||||
path++;
|
||||
|
||||
newpath = grub_strchr (newdirname, ')');
|
||||
newpath = grub_strchr (ctx.newdirname, ')');
|
||||
if (! newpath)
|
||||
newpath = newdirname;
|
||||
newpath = ctx.newdirname;
|
||||
else
|
||||
newpath++;
|
||||
|
||||
/* Look at the directory. */
|
||||
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
|
||||
(plistname, osbundlerequired, &binsuffix))
|
||||
if (ctx.plistname && grub_xnu_check_os_bundle_required
|
||||
(ctx.plistname, osbundlerequired, &binsuffix))
|
||||
{
|
||||
if (binsuffix)
|
||||
{
|
||||
|
@ -1168,29 +1203,29 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
|
|||
+ grub_strlen (binsuffix)
|
||||
+ sizeof ("/MacOS/"));
|
||||
grub_strcpy (binname, dirname);
|
||||
if (usemacos)
|
||||
if (ctx.usemacos)
|
||||
grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
|
||||
else
|
||||
grub_strcpy (binname + grub_strlen (binname), "/");
|
||||
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);
|
||||
if (! binfile)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* Load the extension. */
|
||||
grub_xnu_load_driver (plistname, binfile,
|
||||
grub_xnu_load_driver (ctx.plistname, binfile,
|
||||
binname);
|
||||
grub_free (binname);
|
||||
grub_free (binsuffix);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_dprintf ("xnu", "%s:0\n", plistname);
|
||||
grub_xnu_load_driver (plistname, 0, 0);
|
||||
grub_dprintf ("xnu", "%s:0\n", ctx.plistname);
|
||||
grub_xnu_load_driver (ctx.plistname, 0, 0);
|
||||
}
|
||||
}
|
||||
grub_free (plistname);
|
||||
grub_free (ctx.plistname);
|
||||
grub_device_close (dev);
|
||||
}
|
||||
grub_free (device_name);
|
||||
|
|
|
@ -1253,8 +1253,8 @@ grub_net_open_real (const char *name)
|
|||
|
||||
static grub_err_t
|
||||
grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info) __attribute__ ((unused)))
|
||||
grub_fs_dir_hook_t hook __attribute__ ((unused)),
|
||||
void *hook_data __attribute__ ((unused)))
|
||||
{
|
||||
if (!device->net)
|
||||
return grub_error (GRUB_ERR_BUG, "invalid net device");
|
||||
|
|
|
@ -123,7 +123,8 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -295,7 +296,7 @@ complete_file (void)
|
|||
dirfile[1] = '\0';
|
||||
|
||||
/* Iterate the directory. */
|
||||
(fs->dir) (dev, dir, iterate_dir);
|
||||
(fs->dir) (dev, dir, iterate_dir, NULL);
|
||||
|
||||
grub_free (dir);
|
||||
|
||||
|
|
|
@ -41,6 +41,10 @@ struct grub_dirhook_info
|
|||
grub_int32_t mtime;
|
||||
};
|
||||
|
||||
typedef int (*grub_fs_dir_hook_t) (const char *filename,
|
||||
const struct grub_dirhook_info *info,
|
||||
void *data);
|
||||
|
||||
/* Filesystem descriptor. */
|
||||
struct grub_fs
|
||||
{
|
||||
|
@ -53,8 +57,7 @@ struct grub_fs
|
|||
|
||||
/* Call HOOK with each file under DIR. */
|
||||
grub_err_t (*dir) (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info));
|
||||
grub_fs_dir_hook_t hook, void *hook_data);
|
||||
|
||||
/* Open a file named NAME and initialize FILE. */
|
||||
grub_err_t (*open) (struct grub_file *file, const char *name);
|
||||
|
|
|
@ -38,24 +38,25 @@ enum grub_fshelp_filetype
|
|||
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
|
||||
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
|
||||
iterate over all directory entries in the current node.
|
||||
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
|
||||
error is generated if the node is not of the expected type. Make
|
||||
sure you use the NESTED_FUNC_ATTR macro for HOOK, this is required
|
||||
because GCC has a nasty bug when using regparm=3. */
|
||||
error is generated if the node is not of the expected type. */
|
||||
grub_err_t
|
||||
EXPORT_FUNC(grub_fshelp_find_file) (const char *path,
|
||||
grub_fshelp_node_t rootnode,
|
||||
grub_fshelp_node_t *foundnode,
|
||||
int (*iterate_dir) (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node)),
|
||||
grub_fshelp_iterate_dir_hook_t hook,
|
||||
void *hook_data),
|
||||
char *(*read_symlink) (grub_fshelp_node_t node),
|
||||
enum grub_fshelp_filetype expect);
|
||||
|
||||
|
|
|
@ -116,30 +116,38 @@ translate_error (void)
|
|||
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
|
||||
fuse_getattr (const char *path, struct stat *st)
|
||||
{
|
||||
char *filename, *pathname, *path2;
|
||||
struct fuse_getattr_ctx ctx;
|
||||
char *pathname, *path2;
|
||||
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)
|
||||
{
|
||||
st->st_dev = 0;
|
||||
|
@ -155,7 +163,7 @@ fuse_getattr (const char *path, struct stat *st)
|
|||
return 0;
|
||||
}
|
||||
|
||||
file_exists = 0;
|
||||
ctx.file_exists = 0;
|
||||
|
||||
pathname_t = grub_strchr (path, ')');
|
||||
if (! pathname_t)
|
||||
|
@ -169,35 +177,35 @@ fuse_getattr (const char *path, struct stat *st)
|
|||
pathname[grub_strlen (pathname) - 1] = 0;
|
||||
|
||||
/* Split into path and filename. */
|
||||
filename = grub_strrchr (pathname, '/');
|
||||
if (! filename)
|
||||
ctx.filename = grub_strrchr (pathname, '/');
|
||||
if (! ctx.filename)
|
||||
{
|
||||
path2 = grub_strdup ("/");
|
||||
filename = pathname;
|
||||
ctx.filename = pathname;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename++;
|
||||
ctx.filename++;
|
||||
path2 = grub_strdup (pathname);
|
||||
path2[filename - pathname] = 0;
|
||||
path2[ctx.filename - pathname] = 0;
|
||||
}
|
||||
|
||||
/* It's the whole device. */
|
||||
(fs->dir) (dev, path2, find_file);
|
||||
(fs->dir) (dev, path2, fuse_getattr_find_file, &ctx);
|
||||
|
||||
grub_free (path2);
|
||||
if (!file_exists)
|
||||
if (!ctx.file_exists)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return -ENOENT;
|
||||
}
|
||||
st->st_dev = 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_gid = 0;
|
||||
st->st_rdev = 0;
|
||||
if (!file_info.dir)
|
||||
if (!ctx.file_info.dir)
|
||||
{
|
||||
grub_file_t file;
|
||||
file = grub_file_open (path);
|
||||
|
@ -210,8 +218,8 @@ fuse_getattr (const char *path, struct stat *st)
|
|||
st->st_size = 0;
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = (st->st_size + 511) >> 9;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = file_info.mtimeset
|
||||
? file_info.mtime : 0;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = ctx.file_info.mtimeset
|
||||
? ctx.file_info.mtime : 0;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
@ -271,39 +279,55 @@ fuse_release (const char *path, struct fuse_file_info *fi)
|
|||
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
|
||||
fuse_readdir (const char *path, void *buf,
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
/* Remove trailing '/'. */
|
||||
|
@ -311,7 +335,7 @@ fuse_readdir (const char *path, void *buf,
|
|||
&& pathname[grub_strlen (pathname) - 1] == '/')
|
||||
pathname[grub_strlen (pathname) - 1] = 0;
|
||||
|
||||
(fs->dir) (dev, pathname, call_fill);
|
||||
(fs->dir) (dev, pathname, fuse_readdir_call_fill, &ctx);
|
||||
free (pathname);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue