HFS: Convert to fshelp.

HFS doesn't handle "." and ".." properly. Convert it to fshelp to reuse the
logic.
This commit is contained in:
Vladimir Serbinenko 2015-07-27 12:50:22 +02:00
parent bfb5b33e96
commit 5fb1e859f7
1 changed files with 78 additions and 99 deletions

View File

@ -29,6 +29,7 @@
#include <grub/types.h>
#include <grub/hfs.h>
#include <grub/i18n.h>
#include <grub/fshelp.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -1125,90 +1126,81 @@ utf8_to_macroman (grub_uint8_t *to, const char *from)
return optr - to;
}
union grub_hfs_anyrec {
struct grub_hfs_filerec frec;
struct grub_hfs_dirrec dir;
};
struct grub_fshelp_node
{
struct grub_hfs_data *data;
union grub_hfs_anyrec fdrec;
grub_uint32_t inode;
};
static grub_err_t
lookup_file (grub_fshelp_node_t dir,
const char *name,
grub_fshelp_node_t *foundnode,
enum grub_fshelp_filetype *foundtype)
{
struct grub_hfs_catalog_key key;
grub_ssize_t slen;
union grub_hfs_anyrec fdrec;
key.parent_dir = grub_cpu_to_be32 (dir->inode);
slen = utf8_to_macroman (key.str, name);
if (slen < 0)
/* Not found */
return GRUB_ERR_NONE;
key.strlen = slen;
/* Lookup this node. */
if (! grub_hfs_find_node (dir->data, (char *) &key, dir->data->cat_root,
0, (char *) &fdrec.frec, sizeof (fdrec.frec)))
/* Not found */
return GRUB_ERR_NONE;
*foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
if (!*foundnode)
return grub_errno;
(*foundnode)->inode = grub_be_to_cpu32 (fdrec.dir.dirid);
(*foundnode)->fdrec = fdrec;
(*foundnode)->data = dir->data;
*foundtype = (fdrec.frec.type == GRUB_HFS_FILETYPE_DIR) ? GRUB_FSHELP_DIR : GRUB_FSHELP_REG;
return GRUB_ERR_NONE;
}
/* Find a file or directory with the pathname PATH in the filesystem
DATA. Return the file record in RETDATA when it is non-zero.
Return the directory number in RETINODE when it is non-zero. */
static grub_err_t
grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
struct grub_hfs_filerec *retdata, int *retinode)
grub_fshelp_node_t *found,
enum grub_fshelp_filetype exptype)
{
int inode = data->rootdir;
char *next;
char *origpath;
union {
struct grub_hfs_filerec frec;
struct grub_hfs_dirrec dir;
} fdrec;
fdrec.frec.type = GRUB_HFS_FILETYPE_DIR;
if (path[0] != '/')
{
grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path);
return 0;
struct grub_fshelp_node root = {
.data = data,
.inode = data->rootdir,
.fdrec = {
.frec = {
.type = GRUB_HFS_FILETYPE_DIR
}
}
};
grub_err_t err;
origpath = grub_strdup (path);
if (!origpath)
return grub_errno;
err = grub_fshelp_find_file_lookup (path, &root, found, lookup_file, NULL, exptype);
path = origpath;
while (*path == '/')
path++;
while (path && grub_strlen (path))
if (&root == *found)
{
grub_ssize_t slen;
if (fdrec.frec.type != GRUB_HFS_FILETYPE_DIR)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
goto fail;
}
/* Isolate a part of the path. */
next = grub_strchr (path, '/');
if (next)
{
while (*next == '/')
*(next++) = '\0';
}
struct grub_hfs_catalog_key key;
key.parent_dir = grub_cpu_to_be32 (inode);
slen = utf8_to_macroman (key.str, path);
if (slen < 0)
{
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), path);
goto fail;
}
key.strlen = slen;
/* Lookup this node. */
if (! grub_hfs_find_node (data, (char *) &key, data->cat_root,
0, (char *) &fdrec.frec, sizeof (fdrec.frec)))
{
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath);
goto fail;
}
if (grub_errno)
goto fail;
inode = grub_be_to_cpu32 (fdrec.dir.dirid);
path = next;
*found = grub_malloc (sizeof (root));
if (!*found)
return grub_errno;
grub_memcpy (*found, &root, sizeof (root));
}
if (retdata)
grub_memcpy (retdata, &fdrec.frec, sizeof (fdrec.frec));
if (retinode)
*retinode = inode;
fail:
grub_free (origpath);
return grub_errno;
return err;
}
struct grub_hfs_dir_hook_ctx
@ -1266,16 +1258,14 @@ static grub_err_t
grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
void *hook_data)
{
int inode;
struct grub_hfs_data *data;
struct grub_hfs_filerec frec;
struct grub_hfs_dir_hook_ctx ctx =
{
.hook = hook,
.hook_data = hook_data
};
grub_fshelp_node_t found = NULL;
grub_dl_ref (my_mod);
data = grub_hfs_mount (device->disk);
@ -1283,18 +1273,13 @@ grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
goto fail;
/* First the directory ID for the directory. */
if (grub_hfs_find_dir (data, path, &frec, &inode))
if (grub_hfs_find_dir (data, path, &found, GRUB_FSHELP_DIR))
goto fail;
if (frec.type != GRUB_HFS_FILETYPE_DIR)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
goto fail;
}
grub_hfs_iterate_dir (data, data->cat_root, inode, grub_hfs_dir_hook, &ctx);
grub_hfs_iterate_dir (data, data->cat_root, found->inode, grub_hfs_dir_hook, &ctx);
fail:
grub_free (found);
grub_free (data);
grub_dl_unref (my_mod);
@ -1308,8 +1293,8 @@ static grub_err_t
grub_hfs_open (struct grub_file *file, const char *name)
{
struct grub_hfs_data *data;
struct grub_hfs_filerec frec;
grub_fshelp_node_t found = NULL;
grub_dl_ref (my_mod);
data = grub_hfs_mount (file->device->disk);
@ -1320,29 +1305,23 @@ grub_hfs_open (struct grub_file *file, const char *name)
return grub_errno;
}
if (grub_hfs_find_dir (data, name, &frec, 0))
if (grub_hfs_find_dir (data, name, &found, GRUB_FSHELP_REG))
{
grub_free (data);
grub_dl_unref (my_mod);
return grub_errno;
}
if (frec.type != GRUB_HFS_FILETYPE_FILE)
{
grub_free (data);
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
grub_dl_unref (my_mod);
return grub_errno;
}
grub_memcpy (data->extents, frec.extents, sizeof (grub_hfs_datarecord_t));
file->size = grub_be_to_cpu32 (frec.size);
data->size = grub_be_to_cpu32 (frec.size);
data->fileid = grub_be_to_cpu32 (frec.fileid);
grub_memcpy (data->extents, found->fdrec.frec.extents, sizeof (grub_hfs_datarecord_t));
file->size = grub_be_to_cpu32 (found->fdrec.frec.size);
data->size = grub_be_to_cpu32 (found->fdrec.frec.size);
data->fileid = grub_be_to_cpu32 (found->fdrec.frec.fileid);
file->offset = 0;
file->data = data;
grub_free (found);
return 0;
}