From fc524edf654930485066799f2a11cd71845608fd Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Mon, 21 Jan 2013 01:33:46 +0000 Subject: [PATCH] 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. --- ChangeLog | 9 + grub-core/commands/ls.c | 228 +++++++++--------- grub-core/commands/test.c | 315 +++++++++++++------------ grub-core/commands/wildcard.c | 164 +++++++------ grub-core/fs/affs.c | 211 +++++++++-------- grub-core/fs/bfs.c | 99 ++++---- grub-core/fs/btrfs.c | 5 +- grub-core/fs/cpio.c | 5 +- grub-core/fs/ext2.c | 91 +++---- grub-core/fs/fat.c | 16 +- grub-core/fs/fshelp.c | 353 ++++++++++++++------------- grub-core/fs/hfs.c | 9 +- grub-core/fs/hfsplus.c | 60 ++--- grub-core/fs/iso9660.c | 54 +++-- grub-core/fs/jfs.c | 5 +- grub-core/fs/minix.c | 5 +- grub-core/fs/nilfs2.c | 90 +++---- grub-core/fs/ntfs.c | 67 +++--- grub-core/fs/reiserfs.c | 54 +++-- grub-core/fs/romfs.c | 51 ++-- grub-core/fs/sfs.c | 137 +++++------ grub-core/fs/squash4.c | 57 ++--- grub-core/fs/udf.c | 109 ++++----- grub-core/fs/ufs.c | 5 +- grub-core/fs/xfs.c | 142 ++++++----- grub-core/fs/zfs/zfs.c | 432 +++++++++++++++++++--------------- grub-core/kern/corecmd.c | 5 +- grub-core/kern/emu/hostfs.c | 5 +- grub-core/kern/fs.c | 13 +- grub-core/loader/xnu.c | 205 +++++++++------- grub-core/net/net.c | 4 +- grub-core/normal/completion.c | 5 +- include/grub/fs.h | 7 +- include/grub/fshelp.h | 15 +- util/grub-mount.c | 142 ++++++----- 35 files changed, 1723 insertions(+), 1451 deletions(-) diff --git a/ChangeLog b/ChangeLog index afc2d388c..c975de1c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2013-01-21 Colin Watson + + 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 * docs/grub.texi (Multi-boot manual config): Fix typo for diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c index 79297476c..0b866196c 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -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); } diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c index 3a0e0e069..e3347ee56 100644 --- a/grub-core/commands/test.c +++ b/grub-core/commands/test.c @@ -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 diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c index 633de51b0..2807f806b 100644 --- a/grub-core/commands/wildcard.c +++ b/grub-core/commands/wildcard.c @@ -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 diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index 848a455ff..6c49e5d68 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -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) diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c index 318dc3eec..fa2fc3f3d 100644 --- a/grub-core/fs/bfs.c +++ b/grub-core/fs/bfs.c @@ -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; diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c index bcc75ba8b..196f3017c 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -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; } diff --git a/grub-core/fs/cpio.c b/grub-core/fs/cpio.c index e9236cd97..71d7fa405 100644 --- a/grub-core/fs/cpio.c +++ b/grub-core/fs/cpio.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; diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c index cf2e2f47d..0ebde35ac 100644 --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@ -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); diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c index 119fc945f..7664153da 100644 --- a/grub-core/fs/fat.c +++ b/grub-core/fs/fat.c @@ -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; } diff --git a/grub-core/fs/fshelp.c b/grub-core/fs/fshelp.c index 21a72de84..7e557c3fa 100644 --- a/grub-core/fs/fshelp.c +++ b/grub-core/fs/fshelp.c @@ -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; diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c index 0a249ccb8..9ed33309d 100644 --- a/grub-core/fs/hfs.c +++ b/grub-core/fs/hfs.c @@ -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; diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c index 981246475..dcca581c6 100644 --- a/grub-core/fs/hfsplus.c +++ b/grub-core/fs/hfsplus.c @@ -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) diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c index 547e15670..e37553db1 100644 --- a/grub-core/fs/iso9660.c +++ b/grub-core/fs/iso9660.c @@ -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); diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c index b98a5a374..7c17192c9 100644 --- a/grub-core/fs/jfs.c +++ b/grub-core/fs/jfs.c @@ -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; } diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c index a62253387..965521145 100644 --- a/grub-core/fs/minix.c +++ b/grub-core/fs/minix.c @@ -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. */ diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c index 5b34486c6..9bd444493 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -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); diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c index e7861d80e..7ac46f9ea 100644 --- a/grub-core/fs/ntfs.c +++ b/grub-core/fs/ntfs.c @@ -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)) diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c index 26adf23c4..686e4da69 100644 --- a/grub-core/fs/reiserfs.c +++ b/grub-core/fs/reiserfs.c @@ -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; diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c index b30caef35..b79b1e12d 100644 --- a/grub-core/fs/romfs.c +++ b/grub-core/fs/romfs.c @@ -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); diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c index f7cdb0898..fed17d379 100644 --- a/grub-core/fs/sfs.c +++ b/grub-core/fs/sfs.c @@ -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) diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c index 44af0f82a..cb3cc3a6e 100644 --- a/grub-core/fs/squash4.c +++ b/grub-core/fs/squash4.c @@ -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); diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c index 8e28d41e2..b7f3afb4c 100644 --- a/grub-core/fs/udf.c +++ b/grub-core/fs/udf.c @@ -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); diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c index 74a4a4002..089a5c625 100644 --- a/grub-core/fs/ufs.c +++ b/grub-core/fs/ufs.c @@ -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; } diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c index 1ed048fd3..49d2a8916 100644 --- a/grub-core/fs/xfs.c +++ b/grub-core/fs/xfs.c @@ -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) diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index 6ef6db315..822d65ba6 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -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; diff --git a/grub-core/kern/corecmd.c b/grub-core/kern/corecmd.c index 3441ccb68..0dc4d00fd 100644 --- a/grub-core/kern/corecmd.c +++ b/grub-core/kern/corecmd.c @@ -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 (); } diff --git a/grub-core/kern/emu/hostfs.c b/grub-core/kern/emu/hostfs.c index 3cb089c3f..46bf5e8cb 100644 --- a/grub-core/kern/emu/hostfs.c +++ b/grub-core/kern/emu/hostfs.c @@ -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); } diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c index 7e150f279..9085895b6 100644 --- a/grub-core/kern/fs.c +++ b/grub-core/kern/fs.c @@ -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--; diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index ed3fc72a7..8c522f5e8 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -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); diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 01c5d32ce..aebbe4b75 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -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"); diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c index 367a2b7e4..71c083c77 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -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); diff --git a/include/grub/fs.h b/include/grub/fs.h index 503d1a9cb..e4517972b 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -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); diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h index 4838fca30..e437d4cff 100644 --- a/include/grub/fshelp.h +++ b/include/grub/fshelp.h @@ -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); diff --git a/util/grub-mount.c b/util/grub-mount.c index e3eb1d7f3..d0ab6a2e2 100644 --- a/util/grub-mount.c +++ b/util/grub-mount.c @@ -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;