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
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue