#include <grub/dl.h>
#include <grub/types.h>
#include <grub/i18n.h>
+#include <grub/fshelp.h>
GRUB_MOD_LICENSE ("GPLv3+");
}
static int
-bfs_strcmp (const char *a, const char *b, grub_size_t alen, grub_size_t blen)
+bfs_strcmp (const char *a, const char *b, grub_size_t alen)
{
char ac, bc;
- while (blen && alen)
+ while (*b && alen)
{
if (*a != *b)
break;
a++;
b++;
alen--;
- blen--;
}
ac = alen ? *a : 0;
- bc = blen ? *b : 0;
+ bc = *b;
#ifdef MODE_AFS
return (int) (grub_int8_t) ac - (int) (grub_int8_t) bc;
find_in_b_tree (grub_disk_t disk,
const struct grub_bfs_superblock *sb,
const struct grub_bfs_inode *ino, const char *name,
- grub_size_t name_len,
grub_uint64_t * res)
{
struct grub_bfs_btree_header head;
end = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j))]);
if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
end = grub_bfs_to_cpu_treehead (node->total_key_len);
- cmp = bfs_strcmp (key_data + start, name, end - start, name_len);
+ cmp = bfs_strcmp (key_data + start, name, end - start);
if (cmp == 0 && level == 0)
{
*res = grub_bfs_to_cpu64 (key_values[i | (1 << j)].val);
end = grub_bfs_to_cpu16 (keylen_idx[0]);
if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
end = grub_bfs_to_cpu_treehead (node->total_key_len);
- cmp = bfs_strcmp (key_data, name, end, name_len);
+ cmp = bfs_strcmp (key_data, name, end);
if (cmp == 0 && level == 0)
{
*res = grub_bfs_to_cpu64 (key_values[0].val);
}
}
+struct grub_fshelp_node
+{
+ grub_disk_t disk;
+ const struct grub_bfs_superblock *sb;
+ struct grub_bfs_inode ino;
+};
+
static grub_err_t
-hop_level (grub_disk_t disk,
- const struct grub_bfs_superblock *sb,
- struct grub_bfs_inode *ino, const char *name,
- const char *name_end)
+lookup_file (grub_fshelp_node_t dir,
+ const char *name,
+ grub_fshelp_node_t *foundnode,
+ enum grub_fshelp_filetype *foundtype)
{
grub_err_t err;
+ struct grub_bfs_inode *new_ino;
grub_uint64_t res = 0;
- if (((grub_bfs_to_cpu32 (ino->mode) & ATTR_TYPE) != ATTR_DIR))
- return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
-
- err = find_in_b_tree (disk, sb, ino, name, name_end - name, &res);
+ err = find_in_b_tree (dir->disk, dir->sb, &dir->ino, name, &res);
if (err)
return err;
- return grub_disk_read (disk, res
- << (grub_bfs_to_cpu32 (sb->log2_bsize)
- - GRUB_DISK_SECTOR_BITS), 0,
- sizeof (*ino), (char *) ino);
+ *foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
+ if (!*foundnode)
+ return grub_errno;
+
+ (*foundnode)->disk = dir->disk;
+ (*foundnode)->sb = dir->sb;
+ new_ino = &(*foundnode)->ino;
+
+ if (grub_disk_read (dir->disk, res
+ << (grub_bfs_to_cpu32 (dir->sb->log2_bsize)
+ - GRUB_DISK_SECTOR_BITS), 0,
+ sizeof (*new_ino), (char *) new_ino))
+ {
+ grub_free (*foundnode);
+ return grub_errno;
+ }
+ switch (grub_bfs_to_cpu32 (new_ino->mode) & ATTR_TYPE)
+ {
+ default:
+ case ATTR_REG:
+ *foundtype = GRUB_FSHELP_REG;
+ break;
+ case ATTR_DIR:
+ *foundtype = GRUB_FSHELP_DIR;
+ break;
+ case ATTR_LNK:
+ *foundtype = GRUB_FSHELP_SYMLINK;
+ break;
+ }
+ return GRUB_ERR_NONE;
}
-static grub_err_t
-find_file (const char *path, grub_disk_t disk,
- const struct grub_bfs_superblock *sb, struct grub_bfs_inode *ino)
+static char *
+read_symlink (grub_fshelp_node_t node)
{
- const char *ptr, *next = path;
char *alloc = NULL;
- char *wptr;
grub_err_t err;
- struct grub_bfs_inode old_ino;
- unsigned symlinks_max = 32;
- err = read_extent (disk, sb, &sb->root_dir, 0, 0, ino,
- sizeof (*ino));
- if (err)
- return err;
-
- while (1)
+#ifndef MODE_AFS
+ if (!(grub_bfs_to_cpu32 (node->ino.flags) & LONG_SYMLINK))
{
- ptr = next;
- while (*ptr == '/')
- ptr++;
- if (*ptr == 0)
+ alloc = grub_malloc (sizeof (node->ino.inplace_link) + 1);
+ if (!alloc)
{
- grub_free (alloc);
- return GRUB_ERR_NONE;
+ return NULL;
}
- for (next = ptr; *next && *next != '/'; next++);
- grub_memcpy (&old_ino, ino, sizeof (old_ino));
- err = hop_level (disk, sb, ino, ptr, next);
+ grub_memcpy (alloc, node->ino.inplace_link,
+ sizeof (node->ino.inplace_link));
+ alloc[sizeof (node->ino.inplace_link)] = 0;
+ }
+ else
+#endif
+ {
+ grub_size_t symsize = grub_bfs_to_cpu64 (node->ino.size);
+ alloc = grub_malloc (symsize + 1);
+ if (!alloc)
+ return NULL;
+ err = read_bfs_file (node->disk, node->sb, &node->ino, 0, alloc, symsize, 0, 0);
if (err)
- return err;
-
- if (((grub_bfs_to_cpu32 (ino->mode) & ATTR_TYPE) == ATTR_LNK))
{
- char *old_alloc = alloc;
- if (--symlinks_max == 0)
- {
- grub_free (alloc);
- return grub_error (GRUB_ERR_SYMLINK_LOOP,
- N_("too deep nesting of symlinks"));
- }
-
-#ifndef MODE_AFS
- if (grub_bfs_to_cpu32 (ino->flags) & LONG_SYMLINK)
-#endif
- {
- grub_size_t symsize = grub_bfs_to_cpu64 (ino->size);
- alloc = grub_malloc (grub_strlen (next)
- + symsize + 1);
- if (!alloc)
- {
- grub_free (alloc);
- return grub_errno;
- }
- grub_free (old_alloc);
- err = read_bfs_file (disk, sb, ino, 0, alloc, symsize, 0, 0);
- if (err)
- {
- grub_free (alloc);
- return err;
- }
- alloc[symsize] = 0;
- }
-#ifndef MODE_AFS
- else
- {
- alloc = grub_malloc (grub_strlen (next)
- + sizeof (ino->inplace_link) + 1);
- if (!alloc)
- {
- grub_free (alloc);
- return grub_errno;
- }
- grub_free (old_alloc);
- grub_memcpy (alloc, ino->inplace_link,
- sizeof (ino->inplace_link));
- alloc[sizeof (ino->inplace_link)] = 0;
- }
-#endif
- if (alloc[0] == '/')
- {
- err = read_extent (disk, sb, &sb->root_dir, 0, 0, ino,
- sizeof (*ino));
- if (err)
- {
- grub_free (alloc);
- return err;
- }
- }
- else
- grub_memcpy (ino, &old_ino, sizeof (old_ino));
- wptr = alloc + grub_strlen (alloc);
- if (next)
- wptr = grub_stpcpy (wptr, next);
- *wptr = 0;
- next = alloc;
- continue;
+ grub_free (alloc);
+ return NULL;
}
+ alloc[symsize] = 0;
}
+
+ return alloc;
+}
+
+static grub_err_t
+find_file (const char *path, grub_disk_t disk,
+ const struct grub_bfs_superblock *sb, struct grub_bfs_inode *ino,
+ enum grub_fshelp_filetype exptype)
+{
+ grub_err_t err;
+ struct grub_fshelp_node root = {
+ .disk = disk,
+ .sb = sb,
+ };
+ struct grub_fshelp_node *found;
+
+ err = read_extent (disk, sb, &sb->root_dir, 0, 0, &root.ino,
+ sizeof (root.ino));
+ if (err)
+ return err;
+ err = grub_fshelp_find_file_lookup (path, &root, &found, lookup_file, read_symlink, exptype);
+ if (!err)
+ grub_memcpy (ino, &found->ino, sizeof (*ino));
+
+ if (&root != found)
+ grub_free (found);
+ return err;
}
static grub_err_t
{
struct grub_bfs_inode ino;
- err = find_file (path, device->disk, &ctx.sb, &ino);
+ err = find_file (path, device->disk, &ctx.sb, &ino, GRUB_FSHELP_DIR);
if (err)
return err;
- if (((grub_bfs_to_cpu32 (ino.mode) & ATTR_TYPE) != ATTR_DIR))
- return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
iterate_in_b_tree (device->disk, &ctx.sb, &ino, grub_bfs_dir_iter,
&ctx);
}
{
struct grub_bfs_inode ino;
struct grub_bfs_data *data;
- err = find_file (name, file->device->disk, &sb, &ino);
+ err = find_file (name, file->device->disk, &sb, &ino, GRUB_FSHELP_REG);
if (err)
return err;
- if (((grub_bfs_to_cpu32 (ino.mode) & ATTR_TYPE) != ATTR_REG))
- return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
data = grub_zalloc (sizeof (struct grub_bfs_data));
if (!data)
if (err)
return -1;
- err = find_in_b_tree (disk, sb, ino, name, grub_strlen (name), &res);
+ err = find_in_b_tree (disk, sb, ino, name, &res);
if (err)
return -1;
grub_disk_read (disk, res