Remove nested functions from filesystem directory iterators.

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

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

View file

@ -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)

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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. */

View file

@ -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);

View file

@ -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))

View file

@ -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;

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -443,46 +443,56 @@ grub_xfs_mode_to_filetype (grub_uint16_t mode)
}
/* Context for grub_xfs_iterate_dir. */
struct grub_xfs_iterate_dir_ctx
{
grub_fshelp_iterate_dir_hook_t hook;
void *hook_data;
struct grub_fshelp_node *diro;
};
/* Helper for grub_xfs_iterate_dir. */
static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename,
struct grub_xfs_iterate_dir_ctx *ctx)
{
struct grub_fshelp_node *fdiro;
grub_err_t err;
fdiro = grub_malloc (sizeof (struct grub_fshelp_node)
- sizeof (struct grub_xfs_inode)
+ (1 << ctx->diro->data->sblock.log2_inode));
if (!fdiro)
{
grub_print_error ();
return 0;
}
/* The inode should be read, otherwise the filetype can
not be determined. */
fdiro->ino = ino;
fdiro->inode_read = 1;
fdiro->data = ctx->diro->data;
err = grub_xfs_read_inode (ctx->diro->data, ino, &fdiro->inode);
if (err)
{
grub_print_error ();
return 0;
}
return ctx->hook (filename, grub_xfs_mode_to_filetype (fdiro->inode.mode),
fdiro, ctx->hook_data);
}
static int
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)

View file

@ -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;