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

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