Merge branch 'master' into andrey/ext4_inline_data

Conflicts:
	grub-core/fs/ext2.c
This commit is contained in:
Andrei Borzenkov committed 2016-07-11 07:23:13 +03:00
commit e897f83635
527 files changed
+21786 -6418

No files matched your search

+4 -3
View File
@@ -34,12 +34,12 @@ canonicalize (char *name)
iptr++;
if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
{
iptr += 2;
iptr++;
continue;
}
if (iptr[0] == '.' && iptr[1] == '.' && (iptr[2] == '/' || iptr[2] == 0))
{
iptr += 3;
iptr += 2;
if (optr == name)
continue;
for (optr -= 2; optr >= name && *optr != '/'; optr--);
@@ -249,9 +249,10 @@ grub_archelp_open (struct grub_archelp_data *data,
while (1)
{
grub_uint32_t mode;
grub_int32_t mtime;
int restart;
if (arcops->find_file (data, &fn, NULL, &mode))
if (arcops->find_file (data, &fn, &mtime, &mode))
goto fail;
if (mode == GRUB_ARCHELP_ATTR_END)
+104 -117
View File
@@ -29,6 +29,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/i18n.h>
#include <grub/fshelp.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -561,10 +562,10 @@ iterate_in_b_tree (grub_disk_t disk,
}
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;
@@ -572,11 +573,10 @@ bfs_strcmp (const char *a, const char *b, grub_size_t alen, grub_size_t blen)
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;
@@ -589,7 +589,6 @@ static grub_err_t
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;
@@ -637,7 +636,7 @@ find_in_b_tree (grub_disk_t disk,
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);
@@ -658,7 +657,7 @@ find_in_b_tree (grub_disk_t disk,
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);
@@ -707,127 +706,119 @@ find_in_b_tree (grub_disk_t disk,
}
}
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 char *
read_symlink (grub_fshelp_node_t node)
{
char *alloc = NULL;
grub_err_t err;
#ifndef MODE_AFS
if (!(grub_bfs_to_cpu32 (node->ino.flags) & LONG_SYMLINK))
{
alloc = grub_malloc (sizeof (node->ino.inplace_link) + 1);
if (!alloc)
{
return NULL;
}
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)
{
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)
const struct grub_bfs_superblock *sb, struct grub_bfs_inode *ino,
enum grub_fshelp_filetype exptype)
{
const char *ptr, *next = path;
char *alloc = NULL;
char *wptr;
grub_err_t err;
struct grub_bfs_inode old_ino;
unsigned symlinks_max = 32;
struct grub_fshelp_node root = {
.disk = disk,
.sb = sb,
};
struct grub_fshelp_node *found;
err = read_extent (disk, sb, &sb->root_dir, 0, 0, ino,
sizeof (*ino));
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));
while (1)
{
ptr = next;
while (*ptr == '/')
ptr++;
if (*ptr == 0)
{
grub_free (alloc);
return GRUB_ERR_NONE;
}
for (next = ptr; *next && *next != '/'; next++);
grub_memcpy (&old_ino, ino, sizeof (old_ino));
err = hop_level (disk, sb, ino, ptr, next);
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;
}
}
if (&root != found)
grub_free (found);
return err;
}
static grub_err_t
@@ -909,11 +900,9 @@ grub_bfs_dir (grub_device_t device, const char *path,
{
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);
}
@@ -934,11 +923,9 @@ grub_bfs_open (struct grub_file *file, const char *name)
{
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)
@@ -1034,7 +1021,7 @@ read_bfs_attr (grub_disk_t disk,
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
+35 -18
View File
@@ -680,6 +680,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
grub_uint64_t stripen;
grub_uint64_t stripe_offset;
grub_uint64_t off = addr - grub_le_to_cpu64 (key->offset);
grub_uint64_t chunk_stripe_length;
grub_uint16_t nstripes;
unsigned redundancy = 1;
unsigned i, j;
@@ -690,15 +692,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
"couldn't find the chunk descriptor");
}
nstripes = grub_le_to_cpu16 (chunk->nstripes) ? : 1;
chunk_stripe_length = grub_le_to_cpu64 (chunk->stripe_length) ? : 512;
grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
"+0x%" PRIxGRUB_UINT64_T
" (%d stripes (%d substripes) of %"
PRIxGRUB_UINT64_T ")\n",
grub_le_to_cpu64 (key->offset),
grub_le_to_cpu64 (chunk->size),
grub_le_to_cpu16 (chunk->nstripes),
nstripes,
grub_le_to_cpu16 (chunk->nsubstripes),
grub_le_to_cpu64 (chunk->stripe_length));
chunk_stripe_length);
switch (grub_le_to_cpu64 (chunk->type)
& ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE)
@@ -708,8 +712,10 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
grub_uint64_t stripe_length;
grub_dprintf ("btrfs", "single\n");
stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size),
grub_le_to_cpu16 (chunk->nstripes),
nstripes,
NULL);
if (stripe_length == 0)
stripe_length = 512;
stripen = grub_divmod64 (off, stripe_length, &stripe_offset);
csize = (stripen + 1) * stripe_length - off;
break;
@@ -730,33 +736,34 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
grub_uint64_t low;
grub_dprintf ("btrfs", "RAID0\n");
middle = grub_divmod64 (off,
grub_le_to_cpu64 (chunk->stripe_length),
chunk_stripe_length,
&low);
high = grub_divmod64 (middle, grub_le_to_cpu16 (chunk->nstripes),
high = grub_divmod64 (middle, nstripes,
&stripen);
stripe_offset =
low + grub_le_to_cpu64 (chunk->stripe_length) * high;
csize = grub_le_to_cpu64 (chunk->stripe_length) - low;
low + chunk_stripe_length * high;
csize = chunk_stripe_length - low;
break;
}
case GRUB_BTRFS_CHUNK_TYPE_RAID10:
{
grub_uint64_t middle, high;
grub_uint64_t low;
grub_uint16_t nsubstripes;
nsubstripes = grub_le_to_cpu16 (chunk->nsubstripes) ? : 1;
middle = grub_divmod64 (off,
grub_le_to_cpu64 (chunk->stripe_length),
chunk_stripe_length,
&low);
high = grub_divmod64 (middle,
grub_le_to_cpu16 (chunk->nstripes)
/ grub_le_to_cpu16 (chunk->nsubstripes),
nstripes / nsubstripes ? : 1,
&stripen);
stripen *= grub_le_to_cpu16 (chunk->nsubstripes);
redundancy = grub_le_to_cpu16 (chunk->nsubstripes);
stripe_offset = low + grub_le_to_cpu64 (chunk->stripe_length)
stripen *= nsubstripes;
redundancy = nsubstripes;
stripe_offset = low + chunk_stripe_length
* high;
csize = grub_le_to_cpu64 (chunk->stripe_length) - low;
csize = chunk_stripe_length - low;
break;
}
default:
@@ -1051,7 +1058,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
data->extend = data->extstart + grub_le_to_cpu64 (data->extent->size);
if (data->extent->type == GRUB_BTRFS_EXTENT_REGULAR
&& (char *) &data->extent + elemsize
&& (char *) data->extent + elemsize
>= (char *) &data->extent->filled + sizeof (data->extent->filled))
data->extend =
data->extstart + grub_le_to_cpu64 (data->extent->filled);
@@ -1104,7 +1111,12 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
- (grub_uint8_t *) data->extent),
extoff, buf, csize)
!= (grub_ssize_t) csize)
return -1;
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"premature end of compressed");
return -1;
}
}
else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
{
@@ -1158,7 +1170,12 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
grub_free (tmp);
if (ret != (grub_ssize_t) csize)
return -1;
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"premature end of compressed");
return -1;
}
break;
}
@@ -1191,7 +1208,7 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
struct grub_btrfs_key key_out, key_in;
struct grub_btrfs_root_item ri;
key_in.object_id = GRUB_BTRFS_ROOT_VOL_OBJECTID;
key_in.object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_ROOT_VOL_OBJECTID);
key_in.offset = 0;
key_in.type = GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM;
err = lower_bound (data, &key_in, &key_out,
+15 -4
View File
@@ -74,8 +74,7 @@ grub_cbfs_find_file (struct grub_archelp_data *data, char **name,
(void) mtime;
offset = grub_be_to_cpu32 (hd.offset);
if (mode)
*mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME;
*mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME;
namesize = offset;
if (namesize >= sizeof (hd))
@@ -144,11 +143,14 @@ static struct grub_archelp_data *
grub_cbfs_mount (grub_disk_t disk)
{
struct cbfs_file hd;
struct grub_archelp_data *data;
struct grub_archelp_data *data = NULL;
grub_uint32_t ptr;
grub_off_t header_off;
struct cbfs_header head;
if (grub_disk_get_size (disk) == GRUB_DISK_SIZE_UNKNOWN)
goto fail;
if (grub_disk_read (disk, grub_disk_get_size (disk) - 1,
GRUB_DISK_SECTOR_SIZE - sizeof (ptr),
sizeof (ptr), &ptr))
@@ -193,6 +195,7 @@ grub_cbfs_mount (grub_disk_t disk)
return data;
fail:
grub_free (data);
grub_error (GRUB_ERR_BAD_FS, "not a cbfs filesystem");
return 0;
}
@@ -341,8 +344,16 @@ init_cbfsdisk (void)
ptr = *(grub_uint32_t *) 0xfffffffc;
head = (struct cbfs_header *) (grub_addr_t) ptr;
grub_dprintf ("cbfs", "head=%p\n", head);
if (!validate_head (head))
/* coreboot current supports only ROMs <= 16 MiB. Bigger ROMs will
have problems as RCBA is 18 MiB below end of 32-bit typically,
so either memory map would have to be rearranged or we'd need to support
reading ROMs through controller directly.
*/
if (ptr < 0xff000000
|| 0xffffffff - ptr < (grub_uint32_t) sizeof (*head) + 0xf
|| !validate_head (head))
return;
cbfsdisk_size = ALIGN_UP (grub_be_to_cpu32 (head->romsize),
+9 -2
View File
@@ -61,8 +61,15 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode));
namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize));
if (mode)
*mode = modeval;
/* Don't allow negative numbers. */
if (namesize >= 0x80000000)
{
/* Probably a corruption, don't attempt to recover. */
*mode = GRUB_ARCHELP_ATTR_END;
return GRUB_ERR_NONE;
}
*mode = modeval;
*name = grub_malloc (namesize + 1);
if (*name == NULL)
+79 -10
View File
@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */
#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */
#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */
@@ -115,6 +116,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
| EXT4_FEATURE_INCOMPAT_EXTENTS \
| EXT4_FEATURE_INCOMPAT_FLEX_BG \
| EXT2_FEATURE_INCOMPAT_META_BG \
| EXT4_FEATURE_INCOMPAT_64BIT \
| EXT4_FEATURE_INCOMPAT_INLINE_DATA)
/* List of rationales for the ignored "incompatible" features:
@@ -123,8 +125,13 @@ GRUB_MOD_LICENSE ("GPLv3+");
* journal because they will ignore the journal, but the next
* ext3 driver to mount the volume will find the journal and
* replay it, potentially corrupting the metadata written by
* the ext2 drivers. Safe to ignore for this RO driver. */
#define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER )
* the ext2 drivers. Safe to ignore for this RO driver.
* mmp: Not really back-incompatible - was added as such to
* avoid multiple read-write mounts. Safe to ignore for this
* RO driver.
*/
#define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
| EXT4_FEATURE_INCOMPAT_MMP)
#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
@@ -368,6 +375,35 @@ static grub_dl_t my_mod;
/* Check is a = b^x for some x. */
static inline int
is_power_of (grub_uint64_t a, grub_uint32_t b)
{
grub_uint64_t c;
/* Prevent overflow assuming b < 8. */
if (a >= (1LL << 60))
return 0;
for (c = 1; c <= a; c *= b);
return (c == a);
}
static inline int
group_has_super_block (struct grub_ext2_data *data, grub_uint64_t group)
{
if (!(data->sblock.feature_ro_compat
& grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)))
return 1;
/* Algorithm looked up in Linux source. */
if (group <= 1)
return 1;
/* Even number is never a power of odd number. */
if (!(group & 1))
return 0;
return (is_power_of(group, 7) || is_power_of(group, 5) ||
is_power_of(group, 3));
}
/* Inline data is stored using inline extended attributes. Attributes consist
of entry and value. Entries start after inode proper, following 4 bytes
magic header. Each entry is 4 bytes aligned, end of list is marked with
@@ -431,13 +467,36 @@ grub_ext2_find_inline_data (struct grub_fshelp_node *node, grub_size_t isize,
/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
the mounted filesystem DATA. */
inline static grub_err_t
grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
grub_ext2_blockgroup (struct grub_ext2_data *data, grub_uint64_t group,
struct grub_ext2_block_group *blkgrp)
{
grub_uint64_t full_offset = (group << data->log_group_desc_size);
grub_uint64_t block, offset;
block = (full_offset >> LOG2_BLOCK_SIZE (data));
offset = (full_offset & ((1 << LOG2_BLOCK_SIZE (data)) - 1));
if ((data->sblock.feature_incompat
& grub_cpu_to_le32_compile_time (EXT2_FEATURE_INCOMPAT_META_BG))
&& block >= grub_le_to_cpu32(data->sblock.first_meta_bg))
{
grub_uint64_t first_block_group;
/* Find the first block group for which a descriptor
is stored in given block. */
first_block_group = (block << (LOG2_BLOCK_SIZE (data)
- data->log_group_desc_size));
block = (first_block_group
* grub_le_to_cpu32(data->sblock.blocks_per_group));
if (group_has_super_block (data, first_block_group))
block++;
}
else
/* Superblock. */
block++;
return grub_disk_read (data->disk,
((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
<< LOG2_EXT2_BLOCK_SIZE (data)),
group << data->log_group_desc_size,
((grub_le_to_cpu32 (data->sblock.first_data_block)
+ block)
<< LOG2_EXT2_BLOCK_SIZE (data)), offset,
sizeof (struct grub_ext2_block_group), blkgrp);
}
@@ -576,11 +635,16 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
shift = 2;
goto indirect;
}
return grub_error (GRUB_ERR_BAD_FS,
"ext2fs doesn't support quadruple indirect blocks");
grub_error (GRUB_ERR_BAD_FS,
"ext2fs doesn't support quadruple indirect blocks");
return -1;
indirect:
do {
/* If the indirect block is zero, all child blocks are absent
(i.e. filled with zeros.) */
if (indir == 0)
return 0;
if (grub_disk_read (data->disk,
((grub_disk_addr_t) grub_le_to_cpu32 (indir))
<< log2_blksz,
@@ -588,7 +652,7 @@ indirect:
& ((1 << log_perblock) - 1))
* sizeof (indir),
sizeof (indir), &indir))
return grub_errno;
return -1;
} while (shift--);
return grub_le_to_cpu32 (indir);
@@ -737,7 +801,12 @@ grub_ext2_mount (grub_disk_t disk)
/* Make sure this is an ext2 filesystem. */
if (data->sblock.magic != grub_cpu_to_le16_compile_time (EXT2_MAGIC)
|| grub_le_to_cpu32 (data->sblock.log2_block_size) >= 16)
|| grub_le_to_cpu32 (data->sblock.log2_block_size) >= 16
|| data->sblock.inodes_per_group == 0
/* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
|| grub_le_to_cpu32 (data->sblock.log2_block_size) > 20
|| EXT2_INODE_SIZE (data) == 0
|| EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data) == 0)
{
grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
goto fail;
+175 -171
View File
@@ -31,6 +31,7 @@
#else
#include <grub/exfat.h>
#endif
#include <grub/fshelp.h>
#include <grub/i18n.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -173,8 +174,6 @@ struct grub_fat_data
#ifndef MODE_EXFAT
grub_uint32_t root_sector;
grub_uint32_t num_root_sectors;
#else
int is_contiguous;
#endif
int cluster_bits;
@@ -182,13 +181,22 @@ struct grub_fat_data
grub_uint32_t cluster_sector;
grub_uint32_t num_clusters;
grub_uint32_t uuid;
};
struct grub_fshelp_node {
grub_disk_t disk;
struct grub_fat_data *data;
grub_uint8_t attr;
grub_ssize_t file_size;
grub_uint32_t file_cluster;
grub_uint32_t cur_cluster_num;
grub_uint32_t cur_cluster;
grub_uint32_t uuid;
#ifdef MODE_EXFAT
int is_contiguous;
#endif
};
static grub_dl_t my_mod;
@@ -427,13 +435,6 @@ grub_fat_mount (grub_disk_t disk)
(void) magic;
#endif
/* Start from the root directory. */
data->file_cluster = data->root_cluster;
data->cur_cluster_num = ~0U;
data->attr = GRUB_FAT_ATTR_DIRECTORY;
#ifdef MODE_EXFAT
data->is_contiguous = 0;
#endif
return data;
fail:
@@ -444,7 +445,7 @@ grub_fat_mount (grub_disk_t disk)
}
static grub_ssize_t
grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
grub_fat_read_data (grub_disk_t disk, grub_fshelp_node_t node,
grub_disk_read_hook_t read_hook, void *read_hook_data,
grub_off_t offset, grub_size_t len, char *buf)
{
@@ -457,13 +458,13 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
#ifndef MODE_EXFAT
/* This is a special case. FAT12 and FAT16 doesn't have the root directory
in clusters. */
if (data->file_cluster == ~0U)
if (node->file_cluster == ~0U)
{
size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
size = (node->data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
if (size > len)
size = len;
if (grub_disk_read (disk, data->root_sector, offset, size, buf))
if (grub_disk_read (disk, node->data->root_sector, offset, size, buf))
return -1;
return size;
@@ -471,12 +472,12 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
#endif
#ifdef MODE_EXFAT
if (data->is_contiguous)
if (node->is_contiguous)
{
/* Read the data here. */
sector = (data->cluster_sector
+ ((data->file_cluster - 2)
<< data->cluster_bits));
sector = (node->data->cluster_sector
+ ((node->file_cluster - 2)
<< node->data->cluster_bits));
disk->read_hook = read_hook;
disk->read_hook_data = read_hook_data;
@@ -491,53 +492,53 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
#endif
/* Calculate the logical cluster number and offset. */
logical_cluster_bits = (data->cluster_bits
logical_cluster_bits = (node->data->cluster_bits
+ GRUB_DISK_SECTOR_BITS);
logical_cluster = offset >> logical_cluster_bits;
offset &= (1ULL << logical_cluster_bits) - 1;
if (logical_cluster < data->cur_cluster_num)
if (logical_cluster < node->cur_cluster_num)
{
data->cur_cluster_num = 0;
data->cur_cluster = data->file_cluster;
node->cur_cluster_num = 0;
node->cur_cluster = node->file_cluster;
}
while (len)
{
while (logical_cluster > data->cur_cluster_num)
while (logical_cluster > node->cur_cluster_num)
{
/* Find next cluster. */
grub_uint32_t next_cluster;
grub_uint32_t fat_offset;
switch (data->fat_size)
switch (node->data->fat_size)
{
case 32:
fat_offset = data->cur_cluster << 2;
fat_offset = node->cur_cluster << 2;
break;
case 16:
fat_offset = data->cur_cluster << 1;
fat_offset = node->cur_cluster << 1;
break;
default:
/* case 12: */
fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
fat_offset = node->cur_cluster + (node->cur_cluster >> 1);
break;
}
/* Read the FAT. */
if (grub_disk_read (disk, data->fat_sector, fat_offset,
(data->fat_size + 7) >> 3,
if (grub_disk_read (disk, node->data->fat_sector, fat_offset,
(node->data->fat_size + 7) >> 3,
(char *) &next_cluster))
return -1;
next_cluster = grub_le_to_cpu32 (next_cluster);
switch (data->fat_size)
switch (node->data->fat_size)
{
case 16:
next_cluster &= 0xFFFF;
break;
case 12:
if (data->cur_cluster & 1)
if (node->cur_cluster & 1)
next_cluster >>= 4;
next_cluster &= 0x0FFF;
@@ -545,27 +546,27 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
}
grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n",
data->fat_size, next_cluster);
node->data->fat_size, next_cluster);
/* Check the end. */
if (next_cluster >= data->cluster_eof_mark)
if (next_cluster >= node->data->cluster_eof_mark)
return ret;
if (next_cluster < 2 || next_cluster >= data->num_clusters)
if (next_cluster < 2 || next_cluster >= node->data->num_clusters)
{
grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
next_cluster);
return -1;
}
data->cur_cluster = next_cluster;
data->cur_cluster_num++;
node->cur_cluster = next_cluster;
node->cur_cluster_num++;
}
/* Read the data here. */
sector = (data->cluster_sector
+ ((data->cur_cluster - 2)
<< data->cluster_bits));
sector = (node->data->cluster_sector
+ ((node->cur_cluster - 2)
<< node->data->cluster_bits));
size = (1 << logical_cluster_bits) - offset;
if (size > len)
size = len;
@@ -631,7 +632,7 @@ grub_fat_iterate_fini (struct grub_fat_iterate_context *ctxt)
#ifdef MODE_EXFAT
static grub_err_t
grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
grub_fat_iterate_dir_next (grub_fshelp_node_t node,
struct grub_fat_iterate_context *ctxt)
{
grub_memset (&ctxt->dir, 0, sizeof (ctxt->dir));
@@ -641,7 +642,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
ctxt->offset += sizeof (dir);
if (grub_fat_read_data (disk, data, 0, 0, ctxt->offset, sizeof (dir),
if (grub_fat_read_data (node->disk, node, 0, 0, ctxt->offset, sizeof (dir),
(char *) &dir)
!= sizeof (dir))
break;
@@ -663,7 +664,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
{
struct grub_fat_dir_entry sec;
ctxt->offset += sizeof (sec);
if (grub_fat_read_data (disk, data, 0, 0,
if (grub_fat_read_data (node->disk, node, 0, 0,
ctxt->offset, sizeof (sec), (char *) &sec)
!= sizeof (sec))
break;
@@ -680,7 +681,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
ctxt->dir.file_size
= grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size);
ctxt->dir.have_stream = 1;
ctxt->dir.is_contiguous = !!(dir.type_specific.stream_extension.flags
ctxt->dir.is_contiguous = !!(sec.type_specific.stream_extension.flags
& grub_cpu_to_le16_compile_time (FLAG_CONTIGUOUS));
break;
case 0xc1:
@@ -727,7 +728,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
#else
static grub_err_t
grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
grub_fat_iterate_dir_next (grub_fshelp_node_t node,
struct grub_fat_iterate_context *ctxt)
{
char *filep = 0;
@@ -742,7 +743,7 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
ctxt->offset += sizeof (ctxt->dir);
/* Read a directory entry. */
if (grub_fat_read_data (disk, data, 0, 0,
if (grub_fat_read_data (node->disk, node, 0, 0,
ctxt->offset, sizeof (ctxt->dir),
(char *) &ctxt->dir)
!= sizeof (ctxt->dir) || ctxt->dir.name[0] == 0)
@@ -829,7 +830,9 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
i--;
}
*filep++ = '.';
/* XXX should we check that dir position is 0 or 1? */
if (i > 2 || filep[0] != '.' || (i == 2 && filep[1] != '.'))
*filep++ = '.';
for (i = 8; i < 11 && ctxt->dir.name[i]; i++)
*filep++ = grub_tolower (ctxt->dir.name[i]);
@@ -851,62 +854,20 @@ grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
#endif
/* Find the underlying directory or file in PATH and return the
next path. If there is no next path or an error occurs, return NULL.
If HOOK is specified, call it with each file name. */
static char *
grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
const char *path, const char *origpath,
grub_fs_dir_hook_t hook, void *hook_data)
static grub_err_t lookup_file (grub_fshelp_node_t node,
const char *name,
grub_fshelp_node_t *foundnode,
enum grub_fshelp_filetype *foundtype)
{
char *dirname, *dirp;
int call_hook;
int found = 0;
struct grub_fat_iterate_context ctxt;
grub_err_t err;
if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
return 0;
}
/* Extract a directory name. */
while (*path == '/')
path++;
dirp = grub_strchr (path, '/');
if (dirp)
{
unsigned len = dirp - path;
dirname = grub_malloc (len + 1);
if (! dirname)
goto fail;
grub_memcpy (dirname, path, len);
dirname[len] = '\0';
}
else
/* This is actually a file. */
dirname = grub_strdup (path);
call_hook = (! dirp && hook);
struct grub_fat_iterate_context ctxt;
err = grub_fat_iterate_init (&ctxt);
if (err)
{
grub_free (dirname);
return 0;
}
return err;
while (!(err = grub_fat_iterate_dir_next (disk, data, &ctxt)))
while (!(err = grub_fat_iterate_dir_next (node, &ctxt)))
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY);
info.case_insensitive = 1;
#ifdef MODE_EXFAT
if (!ctxt.dir.have_stream)
@@ -915,33 +876,33 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
continue;
#endif
if (*dirname == '\0' && call_hook)
{
if (hook (ctxt.filename, &info, hook_data))
break;
else
continue;
}
if (grub_strcasecmp (dirname, ctxt.filename) == 0)
if (grub_strcasecmp (name, ctxt.filename) == 0)
{
found = 1;
data->attr = ctxt.dir.attr;
*foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
if (!*foundnode)
return grub_errno;
(*foundnode)->attr = ctxt.dir.attr;
#ifdef MODE_EXFAT
data->file_size = ctxt.dir.file_size;
data->file_cluster = ctxt.dir.first_cluster;
data->is_contiguous = ctxt.dir.is_contiguous;
(*foundnode)->file_size = ctxt.dir.file_size;
(*foundnode)->file_cluster = ctxt.dir.first_cluster;
(*foundnode)->is_contiguous = ctxt.dir.is_contiguous;
#else
data->file_size = grub_le_to_cpu32 (ctxt.dir.file_size);
data->file_cluster = ((grub_le_to_cpu16 (ctxt.dir.first_cluster_high) << 16)
(*foundnode)->file_size = grub_le_to_cpu32 (ctxt.dir.file_size);
(*foundnode)->file_cluster = ((grub_le_to_cpu16 (ctxt.dir.first_cluster_high) << 16)
| grub_le_to_cpu16 (ctxt.dir.first_cluster_low));
/* If directory points to root, starting cluster is 0 */
if (!(*foundnode)->file_cluster)
(*foundnode)->file_cluster = node->data->root_cluster;
#endif
data->cur_cluster_num = ~0U;
(*foundnode)->cur_cluster_num = ~0U;
(*foundnode)->data = node->data;
(*foundnode)->disk = node->disk;
if (call_hook)
hook (ctxt.filename, &info, hook_data);
*foundtype = ((*foundnode)->attr & GRUB_FAT_ATTR_DIRECTORY) ? GRUB_FSHELP_DIR : GRUB_FSHELP_REG;
break;
grub_fat_iterate_fini (&ctxt);
return GRUB_ERR_NONE;
}
}
@@ -949,13 +910,8 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
if (err == GRUB_ERR_EOF)
err = 0;
if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath);
return err;
fail:
grub_free (dirname);
return found ? dirp : 0;
}
static grub_err_t
@@ -964,9 +920,9 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
{
struct grub_fat_data *data = 0;
grub_disk_t disk = device->disk;
grub_size_t len;
char *dirname = 0;
char *p;
grub_fshelp_node_t found = NULL;
grub_err_t err;
struct grub_fat_iterate_context ctxt;
grub_dl_ref (my_mod);
@@ -974,27 +930,53 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
if (! data)
goto fail;
/* Make sure that DIRNAME terminates with '/'. */
len = grub_strlen (path);
dirname = grub_malloc (len + 1 + 1);
if (! dirname)
goto fail;
grub_memcpy (dirname, path, len);
p = dirname + len;
if (path[len - 1] != '/')
*p++ = '/';
*p = '\0';
p = dirname;
struct grub_fshelp_node root = {
.data = data,
.disk = disk,
.attr = GRUB_FAT_ATTR_DIRECTORY,
.file_size = 0,
.file_cluster = data->root_cluster,
.cur_cluster_num = ~0U,
.cur_cluster = 0,
#ifdef MODE_EXFAT
.is_contiguous = 0,
#endif
};
do
err = grub_fshelp_find_file_lookup (path, &root, &found, lookup_file, NULL, GRUB_FSHELP_DIR);
if (err)
goto fail;
err = grub_fat_iterate_init (&ctxt);
if (err)
goto fail;
while (!(err = grub_fat_iterate_dir_next (found, &ctxt)))
{
p = grub_fat_find_dir (disk, data, p, path, hook, hook_data);
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY);
info.case_insensitive = 1;
#ifdef MODE_EXFAT
if (!ctxt.dir.have_stream)
continue;
#else
if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
continue;
#endif
if (hook (ctxt.filename, &info, hook_data))
break;
}
while (p && grub_errno == GRUB_ERR_NONE);
grub_fat_iterate_fini (&ctxt);
if (err == GRUB_ERR_EOF)
err = 0;
fail:
if (found != &root)
grub_free (found);
grub_free (dirname);
grub_free (data);
grub_dl_unref (my_mod);
@@ -1006,35 +988,43 @@ static grub_err_t
grub_fat_open (grub_file_t file, const char *name)
{
struct grub_fat_data *data = 0;
char *p = (char *) name;
grub_fshelp_node_t found = NULL;
grub_err_t err;
grub_disk_t disk = file->device->disk;
grub_dl_ref (my_mod);
data = grub_fat_mount (file->device->disk);
data = grub_fat_mount (disk);
if (! data)
goto fail;
do
{
p = grub_fat_find_dir (file->device->disk, data, p, name, 0, 0);
if (grub_errno != GRUB_ERR_NONE)
goto fail;
}
while (p);
struct grub_fshelp_node root = {
.data = data,
.disk = disk,
.attr = GRUB_FAT_ATTR_DIRECTORY,
.file_size = 0,
.file_cluster = data->root_cluster,
.cur_cluster_num = ~0U,
.cur_cluster = 0,
#ifdef MODE_EXFAT
.is_contiguous = 0,
#endif
};
if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
goto fail;
}
err = grub_fshelp_find_file_lookup (name, &root, &found, lookup_file, NULL, GRUB_FSHELP_REG);
if (err)
goto fail;
file->data = data;
file->size = data->file_size;
file->data = found;
file->size = found->file_size;
return GRUB_ERR_NONE;
fail:
if (found != &root)
grub_free (found);
grub_free (data);
grub_dl_unref (my_mod);
@@ -1053,7 +1043,10 @@ grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
static grub_err_t
grub_fat_close (grub_file_t file)
{
grub_free (file->data);
grub_fshelp_node_t node = file->data;
grub_free (node->data);
grub_free (node);
grub_dl_unref (my_mod);
@@ -1066,20 +1059,29 @@ grub_fat_label (grub_device_t device, char **label)
{
struct grub_fat_dir_entry dir;
grub_ssize_t offset = -sizeof(dir);
struct grub_fat_data *data;
grub_disk_t disk = device->disk;
struct grub_fshelp_node root = {
.disk = disk,
.attr = GRUB_FAT_ATTR_DIRECTORY,
.file_size = 0,
.cur_cluster_num = ~0U,
.cur_cluster = 0,
.is_contiguous = 0,
};
data = grub_fat_mount (disk);
if (! data)
root.data = grub_fat_mount (disk);
if (! root.data)
return grub_errno;
root.file_cluster = root.data->root_cluster;
*label = NULL;
while (1)
{
offset += sizeof (dir);
if (grub_fat_read_data (disk, data, 0, 0,
if (grub_fat_read_data (disk, &root, 0, 0,
offset, sizeof (dir), (char *) &dir)
!= sizeof (dir))
break;
@@ -1099,7 +1101,7 @@ grub_fat_label (grub_device_t device, char **label)
* GRUB_MAX_UTF8_PER_UTF16 + 1);
if (!*label)
{
grub_free (data);
grub_free (root.data);
return grub_errno;
}
chc = dir.type_specific.volume_label.character_count;
@@ -1111,7 +1113,7 @@ grub_fat_label (grub_device_t device, char **label)
}
}
grub_free (data);
grub_free (root.data);
return grub_errno;
}
@@ -1120,30 +1122,32 @@ grub_fat_label (grub_device_t device, char **label)
static grub_err_t
grub_fat_label (grub_device_t device, char **label)
{
struct grub_fat_data *data;
grub_disk_t disk = device->disk;
grub_err_t err;
struct grub_fat_iterate_context ctxt;
struct grub_fshelp_node root = {
.disk = disk,
.attr = GRUB_FAT_ATTR_DIRECTORY,
.file_size = 0,
.cur_cluster_num = ~0U,
.cur_cluster = 0,
};
*label = 0;
grub_dl_ref (my_mod);
data = grub_fat_mount (disk);
if (! data)
root.data = grub_fat_mount (disk);
if (! root.data)
goto fail;
if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
return 0;
}
root.file_cluster = root.data->root_cluster;
err = grub_fat_iterate_init (&ctxt);
if (err)
goto fail;
while (!(err = grub_fat_iterate_dir_next (disk, data, &ctxt)))
while (!(err = grub_fat_iterate_dir_next (&root, &ctxt)))
if ((ctxt.dir.attr & ~GRUB_FAT_ATTR_ARCHIVE) == GRUB_FAT_ATTR_VOLUME_ID)
{
*label = grub_strdup (ctxt.filename);
@@ -1156,7 +1160,7 @@ grub_fat_label (grub_device_t device, char **label)
grub_dl_unref (my_mod);
grub_free (data);
grub_free (root.data);
return grub_errno;
}
+224 -107
View File
@@ -30,169 +30,287 @@ GRUB_MOD_LICENSE ("GPLv3+");
typedef int (*iterate_dir_func) (grub_fshelp_node_t dir,
grub_fshelp_iterate_dir_hook_t hook,
void *data);
typedef grub_err_t (*lookup_file_func) (grub_fshelp_node_t dir,
const char *name,
grub_fshelp_node_t *foundnode,
enum grub_fshelp_filetype *foundtype);
typedef char *(*read_symlink_func) (grub_fshelp_node_t node);
struct stack_element {
struct stack_element *parent;
grub_fshelp_node_t node;
enum grub_fshelp_filetype type;
};
/* Context for grub_fshelp_find_file. */
struct grub_fshelp_find_file_ctx
{
/* Inputs. */
const char *path;
grub_fshelp_node_t rootnode, currroot, currnode, oldnode;
enum grub_fshelp_filetype foundtype;
grub_fshelp_node_t rootnode;
/* Global options. */
int symlinknest;
const char *name;
const char *next;
enum grub_fshelp_filetype type;
/* Current file being traversed and its parents. */
struct stack_element *currnode;
};
/* 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)
if (node != ctx->rootnode)
grub_free (node);
}
static void
pop_element (struct grub_fshelp_find_file_ctx *ctx)
{
struct stack_element *el;
el = ctx->currnode;
ctx->currnode = el->parent;
free_node (el->node, ctx);
grub_free (el);
}
static void
free_stack (struct grub_fshelp_find_file_ctx *ctx)
{
while (ctx->currnode)
pop_element (ctx);
}
static void
go_up_a_level (struct grub_fshelp_find_file_ctx *ctx)
{
if (!ctx->currnode->parent)
return;
pop_element (ctx);
}
static grub_err_t
push_node (struct grub_fshelp_find_file_ctx *ctx, grub_fshelp_node_t node, enum grub_fshelp_filetype filetype)
{
struct stack_element *nst;
nst = grub_malloc (sizeof (*nst));
if (!nst)
return grub_errno;
nst->node = node;
nst->type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
nst->parent = ctx->currnode;
ctx->currnode = nst;
return GRUB_ERR_NONE;
}
static grub_err_t
go_to_root (struct grub_fshelp_find_file_ctx *ctx)
{
free_stack (ctx);
return push_node (ctx, ctx->rootnode, GRUB_FSHELP_DIR);
}
struct grub_fshelp_find_file_iter_ctx
{
const char *name;
grub_fshelp_node_t *foundnode;
enum grub_fshelp_filetype *foundtype;
};
/* 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;
struct grub_fshelp_find_file_iter_ctx *ctx = data;
if (filetype == GRUB_FSHELP_UNKNOWN ||
((filetype & GRUB_FSHELP_CASE_INSENSITIVE)
? grub_strncasecmp (ctx->name, filename, ctx->next - ctx->name)
: grub_strncmp (ctx->name, filename, ctx->next - ctx->name))
|| filename[ctx->next - ctx->name])
? grub_strcasecmp (ctx->name, filename)
: grub_strcmp (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;
*ctx->foundnode = node;
*ctx->foundtype = filetype;
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,
directory_find_file (grub_fshelp_node_t node, const char *name, grub_fshelp_node_t *foundnode,
enum grub_fshelp_filetype *foundtype, iterate_dir_func iterate_dir)
{
int found;
struct grub_fshelp_find_file_iter_ctx ctx = {
.foundnode = foundnode,
.foundtype = foundtype,
.name = name
};
found = iterate_dir (node, find_file_iter, &ctx);
if (! found)
{
if (grub_errno)
return grub_errno;
}
return GRUB_ERR_NONE;
}
static grub_err_t
find_file (char *currpath,
iterate_dir_func iterate_dir, lookup_file_func lookup_file,
read_symlink_func read_symlink,
struct grub_fshelp_find_file_ctx *ctx)
{
ctx->currroot = currroot;
ctx->name = currpath;
ctx->type = GRUB_FSHELP_DIR;
ctx->currnode = currroot;
ctx->oldnode = currroot;
for (;;)
char *name, *next;
grub_err_t err;
for (name = currpath; ; name = next)
{
int found;
char c;
grub_fshelp_node_t foundnode = NULL;
enum grub_fshelp_filetype foundtype = 0;
/* Remove all leading slashes. */
while (*ctx->name == '/')
ctx->name++;
while (*name == '/')
name++;
/* Found the node! */
if (! *ctx->name)
{
*currfound = ctx->currnode;
ctx->foundtype = ctx->type;
return 0;
}
if (! *name)
return 0;
/* Extract the actual part from the pathname. */
for (ctx->next = ctx->name; *ctx->next && *ctx->next != '/'; ctx->next++);
for (next = name; *next && *next != '/'; next++);
/* At this point it is expected that the current node is a
directory, check if this is true. */
if (ctx->type != GRUB_FSHELP_DIR)
if (ctx->currnode->type != GRUB_FSHELP_DIR)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
/* Don't rely on fs providing actual . in the listing. */
if (next - name == 1 && name[0] == '.')
continue;
/* Don't rely on fs providing actual .. in the listing. */
if (next - name == 2 && name[0] == '.' && name[1] == '.')
{
free_node (ctx->currnode, ctx);
ctx->currnode = 0;
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
go_up_a_level (ctx);
continue;
}
/* 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;
c = *next;
*next = '\0';
if (lookup_file)
err = lookup_file (ctx->currnode->node, name, &foundnode, &foundtype);
else
err = directory_find_file (ctx->currnode->node, name, &foundnode, &foundtype, iterate_dir);
*next = c;
break;
}
if (err)
return err;
if (!foundnode)
break;
push_node (ctx, foundnode, foundtype);
/* Read in the symlink and follow it. */
if (ctx->type == GRUB_FSHELP_SYMLINK)
if (ctx->currnode->type == GRUB_FSHELP_SYMLINK)
{
char *symlink;
const char *next;
/* Test if the symlink does not loop. */
if (++ctx->symlinknest == 8)
{
free_node (ctx->currnode, ctx);
free_node (ctx->oldnode, ctx);
ctx->currnode = 0;
ctx->oldnode = 0;
return grub_error (GRUB_ERR_SYMLINK_LOOP,
N_("too deep nesting of symlinks"));
}
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;
symlink = read_symlink (ctx->currnode->node);
if (!symlink)
{
free_node (ctx->oldnode, ctx);
ctx->oldnode = 0;
return grub_errno;
}
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;
err = go_to_root (ctx);
if (err)
return err;
}
else
{
/* Get from symlink to containing directory. */
go_up_a_level (ctx);
}
/* Lookup the node the symlink points to. */
next = ctx->next;
find_file (symlink, ctx->oldnode, &ctx->currnode,
iterate_dir, read_symlink, ctx);
ctx->next = next;
ctx->type = ctx->foundtype;
find_file (symlink, iterate_dir, lookup_file, read_symlink, ctx);
grub_free (symlink);
if (grub_errno)
{
free_node (ctx->oldnode, ctx);
ctx->oldnode = 0;
return grub_errno;
}
return grub_errno;
}
if (ctx->oldnode != ctx->currnode)
{
free_node (ctx->oldnode, ctx);
ctx->oldnode = 0;
}
ctx->name = ctx->next;
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
ctx->path);
}
static grub_err_t
grub_fshelp_find_file_real (const char *path, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode,
iterate_dir_func iterate_dir,
lookup_file_func lookup_file,
read_symlink_func read_symlink,
enum grub_fshelp_filetype expecttype)
{
struct grub_fshelp_find_file_ctx ctx = {
.path = path,
.rootnode = rootnode,
.symlinknest = 0,
.currnode = 0
};
grub_err_t err;
enum grub_fshelp_filetype foundtype;
char *duppath;
if (!path || path[0] != '/')
{
return grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path);
}
err = go_to_root (&ctx);
if (err)
return err;
duppath = grub_strdup (path);
if (!duppath)
return grub_errno;
err = find_file (duppath, iterate_dir, lookup_file, read_symlink, &ctx);
grub_free (duppath);
if (err)
{
free_stack (&ctx);
return err;
}
*foundnode = ctx.currnode->node;
foundtype = ctx.currnode->type;
/* Avoid the node being freed. */
ctx.currnode->node = 0;
free_stack (&ctx);
/* Check if the node that was found was of the expected type. */
if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
return 0;
}
/* 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
@@ -207,31 +325,23 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
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;
return grub_fshelp_find_file_real (path, rootnode, foundnode,
iterate_dir, NULL,
read_symlink, expecttype);
if (!path || path[0] != '/')
{
grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path);
return grub_errno;
}
}
err = find_file (path, rootnode, foundnode, iterate_dir, read_symlink, &ctx);
if (err)
return err;
grub_err_t
grub_fshelp_find_file_lookup (const char *path, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode,
lookup_file_func lookup_file,
read_symlink_func read_symlink,
enum grub_fshelp_filetype expecttype)
{
return grub_fshelp_find_file_real (path, rootnode, foundnode,
NULL, lookup_file,
read_symlink, expecttype);
/* Check if the node that was found was of the expected type. */
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 && ctx.foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
return 0;
}
/* Read LEN bytes from the file NODE on disk DISK into the buffer BUF,
@@ -252,6 +362,13 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
grub_disk_addr_t i, blockcnt;
int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
if (pos > filesize)
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("attempt to read past the end of file"));
return -1;
}
/* Adjust LEN so it we can't read past the end of the file. */
if (pos + len > filesize)
len = filesize - pos;
+100 -100
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+");
@@ -330,6 +331,7 @@ grub_hfs_mount (grub_disk_t disk)
/* Check if this is a HFS filesystem. */
if (grub_be_to_cpu16 (data->sblock.magic) != GRUB_HFS_MAGIC
|| data->sblock.blksz == 0
|| (data->sblock.blksz & grub_cpu_to_be32_compile_time (0xc00001ff)))
{
grub_error (GRUB_ERR_BAD_FS, "not an HFS filesystem");
@@ -367,9 +369,14 @@ grub_hfs_mount (grub_disk_t disk)
data->cat_root = grub_be_to_cpu32 (treehead.head.root_node);
data->cat_size = grub_be_to_cpu16 (treehead.head.node_size);
if (data->cat_size == 0
|| data->blksz < data->cat_size
|| data->blksz < data->ext_size)
goto fail;
/* Lookup the root directory node in the catalog tree using the
volume name. */
key.parent_dir = grub_cpu_to_be32 (1);
key.parent_dir = grub_cpu_to_be32_compile_time (1);
key.strlen = data->sblock.volname[0];
grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1));
@@ -686,6 +693,7 @@ grub_hfs_iterate_records (struct grub_hfs_data *data, int type, int idx,
int i;
struct grub_hfs_extent *dat;
int blk;
grub_uint16_t reccnt;
dat = (struct grub_hfs_extent *) (type == 0
? (&data->sblock.catalog_recs)
@@ -704,8 +712,12 @@ grub_hfs_iterate_records (struct grub_hfs_data *data, int type, int idx,
return grub_errno;
}
reccnt = grub_be_to_cpu16 (node->node.reccnt);
if (reccnt > (nodesize >> 1))
reccnt = (nodesize >> 1);
/* Iterate over all records in this node. */
for (i = 0; i < grub_be_to_cpu16 (node->node.reccnt); i++)
for (i = 0; i < reccnt; i++)
{
int pos = (nodesize >> 1) - 1 - i;
struct pointer
@@ -713,16 +725,19 @@ grub_hfs_iterate_records (struct grub_hfs_data *data, int type, int idx,
grub_uint8_t keylen;
grub_uint8_t key;
} GRUB_PACKED *pnt;
pnt = (struct pointer *) (grub_be_to_cpu16 (node->offsets[pos])
+ node->rawnode);
grub_uint16_t off = grub_be_to_cpu16 (node->offsets[pos]);
if (off > nodesize - sizeof(*pnt))
continue;
pnt = (struct pointer *) (off + node->rawnode);
if (nodesize < (grub_size_t) off + pnt->keylen + 1)
continue;
struct grub_hfs_record rec =
{
&pnt->key,
pnt->keylen,
&pnt->key + pnt->keylen +(pnt->keylen + 1) % 2,
nodesize - grub_be_to_cpu16 (node->offsets[pos])
- pnt->keylen - 1
nodesize - off - pnt->keylen - 1
};
if (node_hook (&node->node, &rec, hook_arg))
@@ -1111,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
@@ -1252,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);
@@ -1269,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);
@@ -1294,35 +1293,36 @@ 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);
if (grub_hfs_find_dir (data, name, &frec, 0))
if (!data)
{
grub_free (data);
grub_dl_unref (my_mod);
return grub_errno;
}
if (frec.type != GRUB_HFS_FILETYPE_FILE)
if (grub_hfs_find_dir (data, name, &found, GRUB_FSHELP_REG))
{
grub_free (data);
grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
grub_free (found);
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;
}
+18 -6
View File
@@ -336,6 +336,9 @@ grub_hfsplus_mount (grub_disk_t disk)
data->case_sensitive = ((magic == GRUB_HFSPLUSX_MAGIC) &&
(header.key_compare == GRUB_HFSPLUSX_BINARYCOMPARE));
if (data->catalog_tree.nodesize < 2)
goto fail;
if (grub_hfsplus_read_file (&data->extoverflow_tree.file, 0, 0,
sizeof (struct grub_hfsplus_btnode),
sizeof (header), (char *) &header) <= 0)
@@ -350,6 +353,9 @@ grub_hfsplus_mount (grub_disk_t disk)
data->extoverflow_tree.root = grub_be_to_cpu32 (header.root);
data->extoverflow_tree.nodesize = grub_be_to_cpu16 (header.nodesize);
if (data->extoverflow_tree.nodesize < 2)
goto fail;
if (grub_hfsplus_read_file (&data->attr_tree.file, 0, 0,
sizeof (struct grub_hfsplus_btnode),
sizeof (header), (char *) &header) <= 0)
@@ -723,7 +729,10 @@ list_nodes (void *record, void *hook_arg)
/* If the name is obviously invalid, skip this node. */
if (catkey->name[i] == 0)
return 0;
{
grub_free (filename);
return 0;
}
}
*grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name,
@@ -745,7 +754,10 @@ list_nodes (void *record, void *hook_arg)
callback function. */
node = grub_malloc (sizeof (*node));
if (!node)
return 1;
{
grub_free (filename);
return 1;
}
node->data = ctx->dir->data;
node->compressed = 0;
node->cbuf = 0;
@@ -780,8 +792,8 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
};
struct grub_hfsplus_key_internal intern;
struct grub_hfsplus_btnode *node;
grub_disk_addr_t ptr;
struct grub_hfsplus_btnode *node = NULL;
grub_disk_addr_t ptr = 0;
{
struct grub_fshelp_node *fsnode;
@@ -964,8 +976,8 @@ grub_hfsplus_label (grub_device_t device, char **label)
struct grub_hfsplus_catkey *catkey;
int i, label_len;
struct grub_hfsplus_key_internal intern;
struct grub_hfsplus_btnode *node;
grub_disk_addr_t ptr;
struct grub_hfsplus_btnode *node = NULL;
grub_disk_addr_t ptr = 0;
*label = 0;
+13 -3
View File
@@ -156,8 +156,12 @@ hfsplus_read_compressed_real (struct grub_hfsplus_file *node,
if (ts > node->size - (pos & ~(HFSPLUS_COMPRESS_BLOCK_SIZE)))
ts = node->size - (pos & ~(HFSPLUS_COMPRESS_BLOCK_SIZE));
if (grub_zlib_decompress (tmp_buf, sz, 0,
node->cbuf, ts) < 0)
node->cbuf, ts) != (grub_ssize_t) ts)
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"premature end of compressed");
grub_free (tmp_buf);
return -1;
}
@@ -288,8 +292,14 @@ hfsplus_open_compressed_real (struct grub_hfsplus_file *node)
if (grub_zlib_decompress ((char *) (cmp_head + 1),
grub_cpu_to_be64 (attr_head->size)
- sizeof (*cmp_head), 0,
node->cbuf, node->size) < 0)
return grub_errno;
node->cbuf, node->size)
!= (grub_ssize_t) node->size)
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"premature end of compressed");
return grub_errno;
}
node->compressed = 1;
return 0;
}
+5 -8
View File
@@ -750,19 +750,15 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
if (dir->data->joliet && !ctx.filename)
{
char *oldname, *semicolon;
char *semicolon;
oldname = name;
ctx.filename = grub_iso9660_convert_string
((grub_uint8_t *) oldname, dirent.namelen >> 1);
((grub_uint8_t *) name, dirent.namelen >> 1);
semicolon = grub_strrchr (ctx.filename, ';');
if (semicolon)
*semicolon = '\0';
if (ctx.filename_alloc)
grub_free (oldname);
ctx.filename_alloc = 1;
}
@@ -959,14 +955,15 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
{
struct grub_iso9660_data *data =
(struct grub_iso9660_data *) file->data;
grub_err_t err;
/* XXX: The file is stored in as a single extent. */
data->disk->read_hook = file->read_hook;
data->disk->read_hook_data = file->read_hook_data;
read_node (data->node, file->offset, len, buf);
err = read_node (data->node, file->offset, len, buf);
data->disk->read_hook = NULL;
if (grub_errno)
if (err || grub_errno)
return -1;
return len;
+48 -32
View File
@@ -65,7 +65,6 @@ typedef grub_uint16_t grub_minix_uintn_t;
#define grub_minix_to_cpu_n grub_minix_to_cpu16
#endif
#define GRUB_MINIX_INODE_BLKSZ(data) sizeof (grub_minix_uintn_t)
#ifdef MODE_MINIX3
typedef grub_uint32_t grub_minix_ino_t;
#define grub_minix_to_cpu_ino grub_minix_to_cpu32
@@ -83,19 +82,6 @@ typedef grub_uint16_t grub_minix_ino_t;
#define GRUB_MINIX_INODE_DINDIR_ZONE(data) (grub_minix_to_cpu_n \
(data->inode.double_indir_zone))
#ifndef MODE_MINIX3
#define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \
+ grub_minix_to_cpu16 (data->sblock.log2_zone_size))
#endif
#define GRUB_MINIX_ZONESZ ((grub_uint64_t) data->block_size << \
(GRUB_DISK_SECTOR_BITS + grub_minix_to_cpu16 (data->sblock.log2_zone_size)))
#ifdef MODE_MINIX3
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) * data->block_size)
#else
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << GRUB_MINIX_LOG2_ZONESZ)
#endif
#ifdef MODE_MINIX3
struct grub_minix_sblock
@@ -172,6 +158,7 @@ struct grub_minix_data
{
struct grub_minix_sblock sblock;
struct grub_minix_inode inode;
grub_uint32_t block_per_zone;
grub_minix_ino_t ino;
int linknest;
grub_disk_t disk;
@@ -184,15 +171,32 @@ static grub_dl_t my_mod;
static grub_err_t grub_minix_find_file (struct grub_minix_data *data,
const char *path);
#ifdef MODE_MINIX3
static inline grub_disk_addr_t
grub_minix_zone2sect (struct grub_minix_data *data, grub_minix_uintn_t zone)
{
return ((grub_disk_addr_t) zone) * data->block_size;
}
#else
static inline grub_disk_addr_t
grub_minix_zone2sect (struct grub_minix_data *data, grub_minix_uintn_t zone)
{
int log2_zonesz = (GRUB_MINIX_LOG2_BSIZE
+ grub_minix_to_cpu16 (data->sblock.log2_zone_size));
return (((grub_disk_addr_t) zone) << log2_zonesz);
}
#endif
/* Read the block pointer in ZONE, on the offset NUM. */
static grub_minix_uintn_t
grub_get_indir (struct grub_minix_data *data,
grub_get_indir (struct grub_minix_data *data,
grub_minix_uintn_t zone,
grub_minix_uintn_t num)
{
grub_minix_uintn_t indirn;
grub_disk_read (data->disk,
GRUB_MINIX_ZONE2SECT(zone),
grub_minix_zone2sect(data, zone),
sizeof (grub_minix_uintn_t) * num,
sizeof (grub_minix_uintn_t), (char *) &indirn);
return grub_minix_to_cpu_n (indirn);
@@ -202,8 +206,6 @@ static grub_minix_uintn_t
grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
{
grub_minix_uintn_t indir;
const grub_uint32_t block_per_zone = (GRUB_MINIX_ZONESZ
/ GRUB_MINIX_INODE_BLKSZ (data));
/* Direct block. */
if (blk < GRUB_MINIX_INODE_DIR_BLOCKS)
@@ -211,33 +213,33 @@ grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
/* Indirect block. */
blk -= GRUB_MINIX_INODE_DIR_BLOCKS;
if (blk < block_per_zone)
if (blk < data->block_per_zone)
{
indir = grub_get_indir (data, GRUB_MINIX_INODE_INDIR_ZONE (data), blk);
return indir;
}
/* Double indirect block. */
blk -= block_per_zone;
if (blk < block_per_zone * block_per_zone)
blk -= data->block_per_zone;
if (blk < (grub_uint64_t) data->block_per_zone * (grub_uint64_t) data->block_per_zone)
{
indir = grub_get_indir (data, GRUB_MINIX_INODE_DINDIR_ZONE (data),
blk / block_per_zone);
blk / data->block_per_zone);
indir = grub_get_indir (data, indir, blk % block_per_zone);
indir = grub_get_indir (data, indir, blk % data->block_per_zone);
return indir;
}
#if defined (MODE_MINIX3) || defined (MODE_MINIX2)
blk -= block_per_zone * block_per_zone;
if (blk < ((grub_uint64_t) block_per_zone * (grub_uint64_t) block_per_zone
* (grub_uint64_t) block_per_zone))
blk -= data->block_per_zone * data->block_per_zone;
if (blk < ((grub_uint64_t) data->block_per_zone * (grub_uint64_t) data->block_per_zone
* (grub_uint64_t) data->block_per_zone))
{
indir = grub_get_indir (data, grub_minix_to_cpu_n (data->inode.triple_indir_zone),
(blk / block_per_zone) / block_per_zone);
indir = grub_get_indir (data, indir, (blk / block_per_zone) % block_per_zone);
indir = grub_get_indir (data, indir, blk % block_per_zone);
(blk / data->block_per_zone) / data->block_per_zone);
indir = grub_get_indir (data, indir, (blk / data->block_per_zone) % data->block_per_zone);
indir = grub_get_indir (data, indir, blk % data->block_per_zone);
return indir;
}
@@ -262,6 +264,13 @@ grub_minix_read_file (struct grub_minix_data *data,
grub_uint32_t posblock;
grub_uint32_t blockoff;
if (pos > GRUB_MINIX_INODE_SIZE (data))
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("attempt to read past the end of file"));
return -1;
}
/* Adjust len so it we can't read past the end of the file. */
if (len + pos > GRUB_MINIX_INODE_SIZE (data))
len = GRUB_MINIX_INODE_SIZE (data) - pos;
@@ -278,7 +287,7 @@ grub_minix_read_file (struct grub_minix_data *data,
for (i = posblock; i < blockcnt; i++)
{
grub_disk_addr_t blknr;
grub_minix_uintn_t blknr;
grub_uint64_t blockend = data->block_size << GRUB_DISK_SECTOR_BITS;
grub_off_t skipfirst = 0;
@@ -307,7 +316,7 @@ grub_minix_read_file (struct grub_minix_data *data,
data->disk->read_hook = read_hook;
data->disk->read_hook_data = read_hook_data;
grub_disk_read (data->disk,
GRUB_MINIX_ZONE2SECT(blknr),
grub_minix_zone2sect(data, blknr),
skipfirst, blockend, buf);
data->disk->read_hook = 0;
if (grub_errno)
@@ -333,7 +342,8 @@ grub_minix_read_inode (struct grub_minix_data *data, grub_minix_ino_t ino)
/* The first inode in minix is inode 1. */
ino--;
block = GRUB_MINIX_ZONE2SECT (2 + grub_minix_to_cpu16 (sblock->inode_bmap_size)
block = grub_minix_zone2sect (data,
2 + grub_minix_to_cpu16 (sblock->inode_bmap_size)
+ grub_minix_to_cpu16 (sblock->zone_bmap_size));
block += ino / (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode));
int offs = (ino % (GRUB_DISK_SECTOR_SIZE
@@ -508,6 +518,12 @@ grub_minix_mount (grub_disk_t disk)
data->block_size = 2;
#endif
data->block_per_zone = (((grub_uint64_t) data->block_size << \
(GRUB_DISK_SECTOR_BITS + grub_minix_to_cpu16 (data->sblock.log2_zone_size)))
/ sizeof (grub_minix_uintn_t));
if (!data->block_per_zone)
goto fail;
return data;
fail:
+4
View File
@@ -724,6 +724,10 @@ grub_nilfs2_valid_sb (struct grub_nilfs2_super_block *sbp)
if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
return 0;
/* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
if (grub_le_to_cpu32 (sbp->s_log_block_size) > 20)
return 0;
return 1;
}
+8 -1
View File
@@ -618,7 +618,10 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
ustr = get_utf8 (np, ns);
if (ustr == NULL)
return 0;
{
grub_free (fdiro);
return 0;
}
if (namespace)
type |= GRUB_FSHELP_CASE_INSENSITIVE;
@@ -917,12 +920,16 @@ grub_ntfs_mount (grub_disk_t disk)
if (bpb.clusters_per_mft > 0)
data->mft_size = ((grub_disk_addr_t) bpb.clusters_per_mft) << data->log_spc;
else if (-bpb.clusters_per_mft < GRUB_NTFS_BLK_SHR || -bpb.clusters_per_mft >= 31)
goto fail;
else
data->mft_size = 1ULL << (-bpb.clusters_per_mft - GRUB_NTFS_BLK_SHR);
if (bpb.clusters_per_index > 0)
data->idx_size = (((grub_disk_addr_t) bpb.clusters_per_index)
<< data->log_spc);
else if (-bpb.clusters_per_index < GRUB_NTFS_BLK_SHR || -bpb.clusters_per_index >= 31)
goto fail;
else
data->idx_size = 1ULL << (-bpb.clusters_per_index - GRUB_NTFS_BLK_SHR);
+1 -1
View File
@@ -104,7 +104,7 @@ decomp_block (struct grub_ntfs_comp *cc, grub_uint8_t *dest)
if (tag & 1)
{
grub_uint32_t i, len, delta, code, lmask, dshift;
grub_uint16_t word;
grub_uint16_t word = 0;
if (decomp_get16 (cc, &word))
return grub_errno;
+57 -27
View File
@@ -22,6 +22,7 @@
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/archelp.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -74,6 +75,44 @@ grub_procdev_write (grub_disk_t disk __attribute ((unused)),
return GRUB_ERR_OUT_OF_RANGE;
}
struct grub_archelp_data
{
struct grub_procfs_entry *entry, *next_entry;
};
static void
grub_procfs_rewind (struct grub_archelp_data *data)
{
data->entry = NULL;
data->next_entry = grub_procfs_entries;
}
static grub_err_t
grub_procfs_find_file (struct grub_archelp_data *data, char **name,
grub_int32_t *mtime,
grub_uint32_t *mode)
{
data->entry = data->next_entry;
if (!data->entry)
{
*mode = GRUB_ARCHELP_ATTR_END;
return GRUB_ERR_NONE;
}
data->next_entry = data->entry->next;
*mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME;
*name = grub_strdup (data->entry->name);
*mtime = 0;
if (!*name)
return grub_errno;
return GRUB_ERR_NONE;
}
static struct grub_archelp_ops arcops =
{
.find_file = grub_procfs_find_file,
.rewind = grub_procfs_rewind
};
static grub_ssize_t
grub_procfs_read (grub_file_t file, char *buf, grub_size_t len)
{
@@ -99,44 +138,35 @@ static grub_err_t
grub_procfs_dir (grub_device_t device, const char *path,
grub_fs_dir_hook_t hook, void *hook_data)
{
const char *ptr;
struct grub_dirhook_info info;
struct grub_procfs_entry *entry;
grub_memset (&info, 0, sizeof (info));
struct grub_archelp_data data;
/* Check if the disk is our dummy disk. */
if (grub_strcmp (device->disk->name, "proc"))
return grub_error (GRUB_ERR_BAD_FS, "not a procfs");
for (ptr = path; *ptr == '/'; ptr++);
if (*ptr)
return 0;
FOR_LIST_ELEMENTS((entry), (grub_procfs_entries))
if (hook (entry->name, &info, hook_data))
return 0;
return 0;
grub_procfs_rewind (&data);
return grub_archelp_dir (&data, &arcops,
path, hook, hook_data);
}
static grub_err_t
grub_procfs_open (struct grub_file *file, const char *path)
{
const char *pathptr;
struct grub_procfs_entry *entry;
grub_err_t err;
struct grub_archelp_data data;
grub_size_t sz;
for (pathptr = path; *pathptr == '/'; pathptr++);
grub_procfs_rewind (&data);
FOR_LIST_ELEMENTS((entry), (grub_procfs_entries))
if (grub_strcmp (pathptr, entry->name) == 0)
{
grub_size_t sz;
file->data = entry->get_contents (&sz);
if (!file->data)
return grub_errno;
file->size = sz;
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), path);
err = grub_archelp_open (&data, &arcops, path);
if (err)
return err;
file->data = data.entry->get_contents (&sz);
if (!file->data)
return grub_errno;
file->size = sz;
return GRUB_ERR_NONE;
}
static struct grub_disk_dev grub_procfs_dev = {
+32 -11
View File
@@ -365,7 +365,7 @@ grub_reiserfs_set_key_offset (struct grub_reiserfs_key *key,
key->u.v1.offset = grub_cpu_to_le32 (value);
else
key->u.v2.offset_type \
= ((key->u.v2.offset_type & grub_cpu_to_le64 (15ULL << 60))
= ((key->u.v2.offset_type & grub_cpu_to_le64_compile_time (15ULL << 60))
| grub_cpu_to_le64 (value & (~0ULL >> 4)));
}
@@ -412,7 +412,7 @@ grub_reiserfs_set_key_type (struct grub_reiserfs_key *key,
key->u.v1.type = grub_cpu_to_le32 (type);
else
key->u.v2.offset_type
= ((key->u.v2.offset_type & grub_cpu_to_le64 (~0ULL >> 4))
= ((key->u.v2.offset_type & grub_cpu_to_le64_compile_time (~0ULL >> 4))
| grub_cpu_to_le64 ((grub_uint64_t) type << 60));
assert (grub_reiserfs_get_key_type (key) == grub_type);
@@ -783,12 +783,30 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
struct grub_reiserfs_key entry_key;
enum grub_fshelp_filetype entry_type;
char *entry_name;
char *entry_name_end = 0;
char c;
if (!(entry_state & GRUB_REISERFS_VISIBLE_MASK))
continue;
entry_name = (((char *) directory_headers)
+ grub_le_to_cpu16 (directory_header->location));
if (entry_number == 0)
{
entry_name_end = (char *) block_header
+ grub_le_to_cpu16 (item_headers[block_position].item_location)
+ grub_le_to_cpu16 (item_headers[block_position].item_size);
}
else
{
entry_name_end = (((char *) directory_headers)
+ grub_le_to_cpu16 (directory_headers[entry_number - 1].location));
}
if (entry_name_end < entry_name || entry_name_end > (char *) block_header + block_size)
{
entry_name_end = (char *) block_header + block_size;
}
entry_key.directory_id = directory_header->directory_id;
entry_key.object_id = directory_header->object_id;
entry_key.u.v2.offset_type = 0;
@@ -935,7 +953,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
else
{
/* Pseudo file ".." never has stat block. */
if (grub_strcmp (entry_name, ".."))
if (entry_name_end == entry_name + 2 && grub_memcmp (entry_name, "..", 2) != 0)
grub_dprintf ("reiserfs",
"Warning : %s has no stat block !\n",
entry_name);
@@ -943,18 +961,21 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
goto next;
}
}
c = *entry_name_end;
*entry_name_end = 0;
if (hook (entry_name, entry_type, entry_item, hook_data))
{
*entry_name_end = c;
grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
entry_name, entry_type);
ret = 1;
goto found;
}
*entry_name_end = c;
next:
*entry_name = 0; /* Make sure next entry name (which is just
before this one in disk order) stops before
the current one. */
;
}
if (next_offset == 0)
@@ -997,8 +1018,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name)
data = grub_reiserfs_mount (file->device->disk);
if (! data)
goto fail;
key.directory_id = grub_cpu_to_le32 (1);
key.object_id = grub_cpu_to_le32 (2);
key.directory_id = grub_cpu_to_le32_compile_time (1);
key.object_id = grub_cpu_to_le32_compile_time (2);
key.u.v2.offset_type = 0;
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECTORY, 2);
grub_reiserfs_set_key_offset (&key, 1);
@@ -1090,7 +1111,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
switch (found.type)
{
case GRUB_REISERFS_DIRECT:
block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
block = ((grub_disk_addr_t) found.block_number) * (block_size >> GRUB_DISK_SECTOR_BITS);
grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
if (initial_position < current_position + item_size)
{
@@ -1289,8 +1310,8 @@ grub_reiserfs_dir (grub_device_t device, const char *path,
data = grub_reiserfs_mount (device->disk);
if (! data)
goto fail;
root_key.directory_id = grub_cpu_to_le32 (1);
root_key.object_id = grub_cpu_to_le32 (2);
root_key.directory_id = grub_cpu_to_le32_compile_time (1);
root_key.object_id = grub_cpu_to_le32_compile_time (2);
root_key.u.v2.offset_type = 0;
grub_reiserfs_set_key_type (&root_key, GRUB_REISERFS_DIRECTORY, 2);
grub_reiserfs_set_key_offset (&root_key, 1);
+11 -6
View File
@@ -173,10 +173,11 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block,
struct grub_sfs_btree *tree;
int i;
grub_uint32_t next;
grub_size_t blocksize = GRUB_DISK_SECTOR_SIZE << data->log_blocksize;
treeblock = grub_malloc (GRUB_DISK_SECTOR_SIZE << data->log_blocksize);
if (!block)
return 0;
treeblock = grub_malloc (blocksize);
if (!treeblock)
return grub_errno;
next = grub_be_to_cpu32 (data->rblock.btree);
tree = (struct grub_sfs_btree *) treeblock;
@@ -184,17 +185,21 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block,
/* Handle this level in the btree. */
do
{
grub_uint16_t nnodes;
grub_disk_read (data->disk,
((grub_disk_addr_t) next) << data->log_blocksize,
0, GRUB_DISK_SECTOR_SIZE << data->log_blocksize,
treeblock);
0, blocksize, treeblock);
if (grub_errno)
{
grub_free (treeblock);
return grub_errno;
}
for (i = grub_be_to_cpu16 (tree->nodes) - 1; i >= 0; i--)
nnodes = grub_be_to_cpu16 (tree->nodes);
if (nnodes * (grub_uint32_t) (tree)->nodesize > blocksize)
break;
for (i = (int) nnodes - 1; i >= 0; i--)
{
#define EXTNODE(tree, index) \
+1
View File
@@ -986,6 +986,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
case 1:
if (ptr[1])
goto fail;
/* Fallthrough. */
case 2:
/* in 4 bytes. out: 1 byte. */
optr = out;
+10 -3
View File
@@ -394,7 +394,7 @@ grub_ufs_read_file (struct grub_ufs_data *data,
return -1;
}
else
grub_memset (buf, UFS_BLKSZ (sblock) - skipfirst, 0);
grub_memset (buf, 0, blockend);
buf += UFS_BLKSZ (sblock) - skipfirst;
}
@@ -465,7 +465,13 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
&& INODE_SIZE (data) <= sizeof (data->inode.symlink))
grub_strcpy (symlink, (char *) data->inode.symlink);
else
grub_ufs_read_file (data, 0, 0, 0, sz, symlink);
{
if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0)
{
grub_free(symlink);
return grub_errno;
}
}
symlink[sz] = '\0';
/* The symlink is an absolute path, go back to the root inode. */
@@ -604,7 +610,8 @@ grub_ufs_mount (grub_disk_t disk)
endiannesses. */
if (data->sblock.magic == grub_cpu_to_ufs32_compile_time (GRUB_UFS_MAGIC)
&& data->sblock.bsize != 0
&& ((data->sblock.bsize & (data->sblock.bsize - 1)) == 0))
&& ((data->sblock.bsize & (data->sblock.bsize - 1)) == 0)
&& data->sblock.ino_per_group != 0)
{
for (data->log2_blksz = 0;
(1U << data->log2_blksz) < grub_ufs_to_cpu32 (data->sblock.bsize);
+340 -124
View File
@@ -34,6 +34,50 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define XFS_INODE_FORMAT_EXT 2
#define XFS_INODE_FORMAT_BTREE 3
/* Superblock version field flags */
#define XFS_SB_VERSION_NUMBITS 0x000f
#define XFS_SB_VERSION_ATTRBIT 0x0010
#define XFS_SB_VERSION_NLINKBIT 0x0020
#define XFS_SB_VERSION_QUOTABIT 0x0040
#define XFS_SB_VERSION_ALIGNBIT 0x0080
#define XFS_SB_VERSION_DALIGNBIT 0x0100
#define XFS_SB_VERSION_LOGV2BIT 0x0400
#define XFS_SB_VERSION_SECTORBIT 0x0800
#define XFS_SB_VERSION_EXTFLGBIT 0x1000
#define XFS_SB_VERSION_DIRV2BIT 0x2000
#define XFS_SB_VERSION_MOREBITSBIT 0x8000
#define XFS_SB_VERSION_BITS_SUPPORTED \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_ATTRBIT | \
XFS_SB_VERSION_NLINKBIT | \
XFS_SB_VERSION_QUOTABIT | \
XFS_SB_VERSION_ALIGNBIT | \
XFS_SB_VERSION_DALIGNBIT | \
XFS_SB_VERSION_LOGV2BIT | \
XFS_SB_VERSION_SECTORBIT | \
XFS_SB_VERSION_EXTFLGBIT | \
XFS_SB_VERSION_DIRV2BIT | \
XFS_SB_VERSION_MOREBITSBIT)
/* Recognized xfs format versions */
#define XFS_SB_VERSION_4 4 /* Good old XFS filesystem */
#define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */
/* features2 field flags */
#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32-bit project ids */
#define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */
#define XFS_SB_VERSION2_BITS_SUPPORTED \
(XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
XFS_SB_VERSION2_ATTR2BIT | \
XFS_SB_VERSION2_PROJID32BIT | \
XFS_SB_VERSION2_FTYPE)
/* incompat feature flags */
#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
(XFS_SB_FEAT_INCOMPAT_FTYPE)
struct grub_xfs_sblock
{
@@ -45,7 +89,9 @@ struct grub_xfs_sblock
grub_uint64_t rootino;
grub_uint8_t unused3[20];
grub_uint32_t agsize;
grub_uint8_t unused4[20];
grub_uint8_t unused4[12];
grub_uint16_t version;
grub_uint8_t unused5[6];
grub_uint8_t label[12];
grub_uint8_t log2_bsize;
grub_uint8_t log2_sect;
@@ -54,12 +100,19 @@ struct grub_xfs_sblock
grub_uint8_t log2_agblk;
grub_uint8_t unused6[67];
grub_uint8_t log2_dirblk;
grub_uint8_t unused7[7];
grub_uint32_t features2;
grub_uint8_t unused8[4];
grub_uint32_t sb_features_compat;
grub_uint32_t sb_features_ro_compat;
grub_uint32_t sb_features_incompat;
grub_uint32_t sb_features_log_incompat;
} GRUB_PACKED;
struct grub_xfs_dir_header
{
grub_uint8_t count;
grub_uint8_t smallino;
grub_uint8_t largeino;
union
{
grub_uint32_t i4;
@@ -67,21 +120,29 @@ struct grub_xfs_dir_header
} GRUB_PACKED parent;
} GRUB_PACKED;
/* Structure for directory entry inlined in the inode */
struct grub_xfs_dir_entry
{
grub_uint8_t len;
grub_uint16_t offset;
char name[1];
/* Inode number follows, 32 bits. */
/* Inode number follows, 32 / 64 bits. */
} GRUB_PACKED;
/* Structure for directory entry in a block */
struct grub_xfs_dir2_entry
{
grub_uint64_t inode;
grub_uint8_t len;
} GRUB_PACKED;
typedef grub_uint32_t grub_xfs_extent[4];
struct grub_xfs_extent
{
/* This should be a bitfield but bietfields are unportable, so just have
a raw array and functions extracting useful info from it.
*/
grub_uint32_t raw[4];
} GRUB_PACKED;
struct grub_xfs_btree_node
{
@@ -90,21 +151,22 @@ struct grub_xfs_btree_node
grub_uint16_t numrecs;
grub_uint64_t left;
grub_uint64_t right;
grub_uint64_t keys[1];
} GRUB_PACKED;
/* In V5 here follow crc, uuid, etc. */
/* Then follow keys and block pointers */
} GRUB_PACKED;
struct grub_xfs_btree_root
{
grub_uint16_t level;
grub_uint16_t numrecs;
grub_uint64_t keys[1];
} GRUB_PACKED;
} GRUB_PACKED;
struct grub_xfs_time
{
grub_uint32_t sec;
grub_uint32_t nanosec;
} GRUB_PACKED;
} GRUB_PACKED;
struct grub_xfs_inode
{
@@ -123,19 +185,11 @@ struct grub_xfs_inode
grub_uint16_t unused3;
grub_uint8_t fork_offset;
grub_uint8_t unused4[17];
union
{
char raw[156];
struct dir
{
struct grub_xfs_dir_header dirhead;
struct grub_xfs_dir_entry direntry[1];
} dir;
grub_xfs_extent extents[XFS_INODE_EXTENTS];
struct grub_xfs_btree_root btree;
} GRUB_PACKED data;
} GRUB_PACKED;
#define XFS_V2_INODE_SIZE sizeof(struct grub_xfs_inode)
#define XFS_V3_INODE_SIZE (XFS_V2_INODE_SIZE + 76)
struct grub_xfs_dirblock_tail
{
grub_uint32_t leaf_count;
@@ -157,6 +211,8 @@ struct grub_xfs_data
int pos;
int bsize;
grub_uint32_t agsize;
unsigned int hasftype:1;
unsigned int hascrc:1;
struct grub_fshelp_node diropen;
};
@@ -164,6 +220,71 @@ static grub_dl_t my_mod;
static int grub_xfs_sb_hascrc(struct grub_xfs_data *data)
{
return (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5);
}
static int grub_xfs_sb_hasftype(struct grub_xfs_data *data)
{
if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5) &&
data->sblock.sb_features_incompat & grub_cpu_to_be32_compile_time(XFS_SB_FEAT_INCOMPAT_FTYPE))
return 1;
if (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) &&
data->sblock.features2 & grub_cpu_to_be32_compile_time(XFS_SB_VERSION2_FTYPE))
return 1;
return 0;
}
static int grub_xfs_sb_valid(struct grub_xfs_data *data)
{
grub_dprintf("xfs", "Validating superblock\n");
if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4)
|| data->sblock.log2_bsize < GRUB_DISK_SECTOR_BITS
|| ((int) data->sblock.log2_bsize
+ (int) data->sblock.log2_dirblk) >= 27)
{
grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem");
return 0;
}
if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5))
{
grub_dprintf("xfs", "XFS v5 superblock detected\n");
if (data->sblock.sb_features_incompat &
grub_cpu_to_be32_compile_time(~XFS_SB_FEAT_INCOMPAT_SUPPORTED))
{
grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported "
"incompatible features");
return 0;
}
return 1;
}
else if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
grub_cpu_to_be16_compile_time(XFS_SB_VERSION_4))
{
grub_dprintf("xfs", "XFS v4 superblock detected\n");
if (!(data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_DIRV2BIT)))
{
grub_error (GRUB_ERR_BAD_FS, "XFS filesystem without V2 directories "
"is unsupported");
return 0;
}
if (data->sblock.version & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION_BITS_SUPPORTED) ||
(data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) &&
data->sblock.features2 & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION2_BITS_SUPPORTED)))
{
grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported version "
"bits");
return 0;
}
return 1;
}
return 0;
}
/* Filetype information as used in inodes. */
#define FILETYPE_INO_MASK 0170000
#define FILETYPE_INO_REG 0100000
@@ -180,14 +301,14 @@ static inline grub_uint64_t
GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
grub_uint64_t ino)
{
return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
return (ino & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
}
static inline grub_uint64_t
GRUB_XFS_INO_AG (struct grub_xfs_data *data,
grub_uint64_t ino)
{
return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data));
return (ino >> GRUB_XFS_INO_AGBITS (data));
}
static inline grub_disk_addr_t
@@ -198,37 +319,25 @@ GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb)
}
static inline grub_uint64_t
GRUB_XFS_EXTENT_OFFSET (grub_xfs_extent *exts, int ex)
GRUB_XFS_EXTENT_OFFSET (struct grub_xfs_extent *exts, int ex)
{
return ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23
| grub_be_to_cpu32 (exts[ex][1]) >> 9);
return ((grub_be_to_cpu32 (exts[ex].raw[0]) & ~(1 << 31)) << 23
| grub_be_to_cpu32 (exts[ex].raw[1]) >> 9);
}
static inline grub_uint64_t
GRUB_XFS_EXTENT_BLOCK (grub_xfs_extent *exts, int ex)
GRUB_XFS_EXTENT_BLOCK (struct grub_xfs_extent *exts, int ex)
{
return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1])
return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex].raw[1])
& (0x1ff)) << 43
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11
| grub_be_to_cpu32 (exts[ex][3]) >> 21);
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex].raw[2]) << 11
| grub_be_to_cpu32 (exts[ex].raw[3]) >> 21);
}
static inline grub_uint64_t
GRUB_XFS_EXTENT_SIZE (grub_xfs_extent *exts, int ex)
GRUB_XFS_EXTENT_SIZE (struct grub_xfs_extent *exts, int ex)
{
return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 21) - 1));
}
static inline int
GRUB_XFS_ROUND_TO_DIRENT (int pos)
{
return ((((pos) + 8 - 1) / 8) * 8);
}
static inline int
GRUB_XFS_NEXT_DIRENT (int pos, int len)
{
return (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2);
return (grub_be_to_cpu32 (exts[ex].raw[3]) & ((1 << 21) - 1));
}
@@ -255,6 +364,109 @@ grub_xfs_inode_offset (struct grub_xfs_data *data,
data->sblock.log2_inode);
}
static inline grub_size_t
grub_xfs_inode_size(struct grub_xfs_data *data)
{
return (grub_size_t)1 << data->sblock.log2_inode;
}
/*
* Returns size occupied by XFS inode stored in memory - we store struct
* grub_fshelp_node there but on disk inode size may be actually larger than
* struct grub_xfs_inode so we need to account for that so that we can read
* from disk directly into in-memory structure.
*/
static inline grub_size_t
grub_xfs_fshelp_size(struct grub_xfs_data *data)
{
return sizeof (struct grub_fshelp_node) - sizeof (struct grub_xfs_inode)
+ grub_xfs_inode_size(data);
}
/* This should return void * but XFS code is error-prone with alignment, so
return char to retain cast-align.
*/
static char *
grub_xfs_inode_data(struct grub_xfs_inode *inode)
{
if (inode->version <= 2)
return ((char *)inode) + XFS_V2_INODE_SIZE;
return ((char *)inode) + XFS_V3_INODE_SIZE;
}
static struct grub_xfs_dir_entry *
grub_xfs_inline_de(struct grub_xfs_dir_header *head)
{
/*
With small inode numbers the header is 4 bytes smaller because of
smaller parent pointer
*/
return (struct grub_xfs_dir_entry *)
(((char *) head) + sizeof(struct grub_xfs_dir_header) -
(head->largeino ? 0 : sizeof(grub_uint32_t)));
}
static grub_uint8_t *
grub_xfs_inline_de_inopos(struct grub_xfs_data *data,
struct grub_xfs_dir_entry *de)
{
return ((grub_uint8_t *)(de + 1)) + de->len - 1 + (data->hasftype ? 1 : 0);
}
static struct grub_xfs_dir_entry *
grub_xfs_inline_next_de(struct grub_xfs_data *data,
struct grub_xfs_dir_header *head,
struct grub_xfs_dir_entry *de)
{
char *p = (char *)de + sizeof(struct grub_xfs_dir_entry) - 1 + de->len;
p += head->largeino ? sizeof(grub_uint64_t) : sizeof(grub_uint32_t);
if (data->hasftype)
p++;
return (struct grub_xfs_dir_entry *)p;
}
static struct grub_xfs_dirblock_tail *
grub_xfs_dir_tail(struct grub_xfs_data *data, void *dirblock)
{
int dirblksize = 1 << (data->sblock.log2_bsize + data->sblock.log2_dirblk);
return (struct grub_xfs_dirblock_tail *)
((char *)dirblock + dirblksize - sizeof (struct grub_xfs_dirblock_tail));
}
static struct grub_xfs_dir2_entry *
grub_xfs_first_de(struct grub_xfs_data *data, void *dirblock)
{
if (data->hascrc)
return (struct grub_xfs_dir2_entry *)((char *)dirblock + 64);
return (struct grub_xfs_dir2_entry *)((char *)dirblock + 16);
}
static struct grub_xfs_dir2_entry *
grub_xfs_next_de(struct grub_xfs_data *data, struct grub_xfs_dir2_entry *de)
{
int size = sizeof (struct grub_xfs_dir2_entry) + de->len + 2 /* Tag */;
if (data->hasftype)
size++; /* File type */
return (struct grub_xfs_dir2_entry *)(((char *)de) + ALIGN_UP(size, 8));
}
/* This should return void * but XFS code is error-prone with alignment, so
return char to retain cast-align.
*/
static char *
grub_xfs_btree_keys(struct grub_xfs_data *data,
struct grub_xfs_btree_node *leaf)
{
char *keys = (char *)(leaf + 1);
if (data->hascrc)
keys += 48; /* skip crc, uuid, ... */
return keys;
}
static grub_err_t
grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
@@ -263,9 +475,11 @@ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
grub_uint64_t block = grub_xfs_inode_block (data, ino);
int offset = grub_xfs_inode_offset (data, ino);
grub_dprintf("xfs", "Reading inode (%"PRIuGRUB_UINT64_T") - %"PRIuGRUB_UINT64_T", %d\n",
ino, block, offset);
/* Read the inode. */
if (grub_disk_read (data->disk, block, offset,
1 << data->sblock.log2_inode, inode))
if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data),
inode))
return grub_errno;
if (grub_strncmp ((char *) inode->magic, "IN", 2))
@@ -274,40 +488,47 @@ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
return 0;
}
static grub_uint64_t
get_fsb (const void *keys, int idx)
{
const char *p = (const char *) keys + sizeof(grub_uint64_t) * idx;
return grub_be_to_cpu64 (grub_get_unaligned64 (p));
}
static grub_disk_addr_t
grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
{
struct grub_xfs_btree_node *leaf = 0;
int ex, nrec;
grub_xfs_extent *exts;
struct grub_xfs_extent *exts;
grub_uint64_t ret = 0;
if (node->inode.format == XFS_INODE_FORMAT_BTREE)
{
const grub_uint64_t *keys;
struct grub_xfs_btree_root *root;
const char *keys;
int recoffset;
leaf = grub_malloc (node->data->bsize);
if (leaf == 0)
return 0;
nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
keys = &node->inode.data.btree.keys[0];
root = (struct grub_xfs_btree_root *) grub_xfs_inode_data(&node->inode);
nrec = grub_be_to_cpu16 (root->numrecs);
keys = (char *) &root->keys[0];
if (node->inode.fork_offset)
recoffset = (node->inode.fork_offset - 1) / 2;
else
recoffset = ((1 << node->data->sblock.log2_inode)
- ((char *) &node->inode.data.btree.keys
- (char *) &node->inode))
/ (2 * sizeof (grub_uint64_t));
recoffset = (grub_xfs_inode_size(node->data)
- ((char *) keys - (char *) &node->inode))
/ (2 * sizeof (grub_uint64_t));
do
{
int i;
for (i = 0; i < nrec; i++)
{
if (fileblock < grub_be_to_cpu64 (keys[i]))
if (fileblock < get_fsb(keys, i))
break;
}
@@ -317,12 +538,16 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
grub_free (leaf);
return 0;
}
if (grub_disk_read (node->data->disk,
GRUB_XFS_FSB_TO_BLOCK (node->data, grub_be_to_cpu64 (keys[i - 1 + recoffset])) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb (keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
0, node->data->bsize, leaf))
return 0;
if (grub_strncmp ((char *) leaf->magic, "BMAP", 4))
if ((!node->data->hascrc &&
grub_strncmp ((char *) leaf->magic, "BMAP", 4)) ||
(node->data->hascrc &&
grub_strncmp ((char *) leaf->magic, "BMA3", 4)))
{
grub_free (leaf);
grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node");
@@ -330,18 +555,18 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
}
nrec = grub_be_to_cpu16 (leaf->numrecs);
keys = &leaf->keys[0];
recoffset = ((node->data->bsize - ((char *) &leaf->keys
keys = grub_xfs_btree_keys(node->data, leaf);
recoffset = ((node->data->bsize - ((char *) keys
- (char *) leaf))
/ (2 * sizeof (grub_uint64_t)));
}
while (leaf->level);
exts = (grub_xfs_extent *) keys;
exts = (struct grub_xfs_extent *) keys;
}
else if (node->inode.format == XFS_INODE_FORMAT_EXT)
{
nrec = grub_be_to_cpu32 (node->inode.nextents);
exts = &node->inode.data.extents[0];
exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode);
}
else
{
@@ -379,13 +604,13 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
POS. Return the amount of read bytes in READ. */
static grub_ssize_t
grub_xfs_read_file (grub_fshelp_node_t node,
grub_disk_read_hook_t read_hook, void *read_hook_data,
grub_off_t pos, grub_size_t len, char *buf)
grub_disk_read_hook_t read_hook, void *read_hook_data,
grub_off_t pos, grub_size_t len, char *buf, grub_uint32_t header_size)
{
return grub_fshelp_read_file (node->data->disk, node,
read_hook, read_hook_data,
pos, len, buf, grub_xfs_read_block,
grub_be_to_cpu64 (node->inode.size),
grub_be_to_cpu64 (node->inode.size) + header_size,
node->data->sblock.log2_bsize
- GRUB_DISK_SECTOR_BITS, 0);
}
@@ -394,23 +619,34 @@ grub_xfs_read_file (grub_fshelp_node_t node,
static char *
grub_xfs_read_symlink (grub_fshelp_node_t node)
{
int size = grub_be_to_cpu64 (node->inode.size);
grub_ssize_t size = grub_be_to_cpu64 (node->inode.size);
if (size < 0)
{
grub_error (GRUB_ERR_BAD_FS, "invalid symlink");
return 0;
}
switch (node->inode.format)
{
case XFS_INODE_FORMAT_INO:
return grub_strndup (node->inode.data.raw, size);
return grub_strndup (grub_xfs_inode_data(&node->inode), size);
case XFS_INODE_FORMAT_EXT:
{
char *symlink;
grub_ssize_t numread;
int off = 0;
if (node->data->hascrc)
off = 56;
symlink = grub_malloc (size + 1);
if (!symlink)
return 0;
numread = grub_xfs_read_file (node, 0, 0, 0, size, symlink);
node->inode.size = grub_be_to_cpu64 (size + off);
numread = grub_xfs_read_file (node, 0, 0, off, size, symlink, off);
if (numread != size)
{
grub_free (symlink);
@@ -456,9 +692,7 @@ static int iterate_dir_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 << ctx->diro->data->sblock.log2_inode) + 1);
fdiro = grub_malloc (grub_xfs_fshelp_size(ctx->diro->data) + 1);
if (!fdiro)
{
grub_print_error ();
@@ -496,24 +730,18 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
{
case XFS_INODE_FORMAT_INO:
{
struct grub_xfs_dir_entry *de = &diro->inode.data.dir.direntry[0];
int smallino = !diro->inode.data.dir.dirhead.smallino;
struct grub_xfs_dir_header *head = (struct grub_xfs_dir_header *) grub_xfs_inode_data(&diro->inode);
struct grub_xfs_dir_entry *de = grub_xfs_inline_de(head);
int smallino = !head->largeino;
int i;
grub_uint64_t parent;
/* If small inode numbers are used to pack the direntry, the
parent inode number is small too. */
if (smallino)
{
parent = grub_be_to_cpu32 (diro->inode.data.dir.dirhead.parent.i4);
parent = grub_cpu_to_be64 (parent);
/* The header is a bit smaller than usual. */
de = (struct grub_xfs_dir_entry *) ((char *) de - 4);
}
parent = grub_be_to_cpu32 (head->parent.i4);
else
{
parent = diro->inode.data.dir.dirhead.parent.i8;
}
parent = grub_be_to_cpu64 (head->parent.i8);
/* Synthesize the direntries for `.' and `..'. */
if (iterate_dir_call_hook (diro->ino, ".", &ctx))
@@ -522,12 +750,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
if (iterate_dir_call_hook (parent, "..", &ctx))
return 1;
for (i = 0; i < diro->inode.data.dir.dirhead.count; i++)
for (i = 0; i < head->count; i++)
{
grub_uint64_t ino;
grub_uint8_t *inopos = (((grub_uint8_t *) de)
+ sizeof (struct grub_xfs_dir_entry)
+ de->len - 1);
grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
grub_uint8_t c;
/* inopos might be unaligned. */
@@ -545,18 +771,17 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
| (((grub_uint64_t) inopos[5]) << 16)
| (((grub_uint64_t) inopos[6]) << 8)
| (((grub_uint64_t) inopos[7]) << 0);
ino = grub_cpu_to_be64 (ino);
c = de->name[de->len];
de->name[de->len] = '\0';
if (iterate_dir_call_hook (ino, de->name, &ctx))
return 1;
{
de->name[de->len] = c;
return 1;
}
de->name[de->len] = c;
de = ((struct grub_xfs_dir_entry *)
(((char *) de)+ sizeof (struct grub_xfs_dir_entry) + de->len
+ ((smallino ? sizeof (grub_uint32_t)
: sizeof (grub_uint64_t))) - 1));
de = grub_xfs_inline_next_de(dir->data, head, de);
}
break;
}
@@ -583,19 +808,15 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
>> dirblk_log2);
blk++)
{
/* The header is skipped, the first direntry is stored
from byte 16. */
int pos = 16;
struct grub_xfs_dir2_entry *direntry =
grub_xfs_first_de(dir->data, dirblock);
int entries;
int tail_start = (dirblk_size
- sizeof (struct grub_xfs_dirblock_tail));
struct grub_xfs_dirblock_tail *tail;
tail = (struct grub_xfs_dirblock_tail *) &dirblock[tail_start];
struct grub_xfs_dirblock_tail *tail =
grub_xfs_dir_tail(dir->data, dirblock);
numread = grub_xfs_read_file (dir, 0, 0,
blk << dirblk_log2,
dirblk_size, dirblock);
dirblk_size, dirblock, 0);
if (numread != dirblk_size)
return 0;
@@ -603,14 +824,11 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
- grub_be_to_cpu32 (tail->leaf_stale));
/* Iterate over all entries within this block. */
while (pos < (dirblk_size
- (int) sizeof (struct grub_xfs_dir2_entry)))
while ((char *)direntry < (char *)tail)
{
struct grub_xfs_dir2_entry *direntry;
grub_uint8_t *freetag;
char *filename;
direntry = (struct grub_xfs_dir2_entry *) &dirblock[pos];
freetag = (grub_uint8_t *) direntry;
if (grub_get_unaligned16 (freetag) == 0XFFFF)
@@ -618,17 +836,20 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
grub_uint8_t *skip = (freetag + sizeof (grub_uint16_t));
/* This entry is not used, go to the next one. */
pos += grub_be_to_cpu16 (grub_get_unaligned16 (skip));
direntry = (struct grub_xfs_dir2_entry *)
(((char *)direntry) +
grub_be_to_cpu16 (grub_get_unaligned16 (skip)));
continue;
}
filename = &dirblock[pos + sizeof (*direntry)];
/* The byte after the filename is for the tag, which
is not used by GRUB. So it can be overwritten. */
filename = (char *)(direntry + 1);
/* The byte after the filename is for the filetype, padding, or
tag, which is not used by GRUB. So it can be overwritten. */
filename[direntry->len] = '\0';
if (iterate_dir_call_hook (direntry->inode, filename, &ctx))
if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode),
filename, &ctx))
{
grub_free (dirblock);
return 1;
@@ -641,8 +862,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
break;
/* Select the next directory entry. */
pos = GRUB_XFS_NEXT_DIRENT (pos, direntry->len);
pos = GRUB_XFS_ROUND_TO_DIRENT (pos);
direntry = grub_xfs_next_de(dir->data, direntry);
}
}
grub_free (dirblock);
@@ -667,36 +887,35 @@ grub_xfs_mount (grub_disk_t disk)
if (!data)
return 0;
grub_dprintf("xfs", "Reading sb\n");
/* Read the superblock. */
if (grub_disk_read (disk, 0, 0,
sizeof (struct grub_xfs_sblock), &data->sblock))
goto fail;
if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4)
|| data->sblock.log2_bsize < GRUB_DISK_SECTOR_BITS
|| ((int) data->sblock.log2_bsize
+ (int) data->sblock.log2_dirblk) >= 27)
{
grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem");
goto fail;
}
if (!grub_xfs_sb_valid(data))
goto fail;
data = grub_realloc (data,
sizeof (struct grub_xfs_data)
- sizeof (struct grub_xfs_inode)
+ (1 << data->sblock.log2_inode) + 1);
+ grub_xfs_inode_size(data) + 1);
if (! data)
goto fail;
data->diropen.data = data;
data->diropen.ino = data->sblock.rootino;
data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
data->diropen.inode_read = 1;
data->bsize = grub_be_to_cpu32 (data->sblock.bsize);
data->agsize = grub_be_to_cpu32 (data->sblock.agsize);
data->hasftype = grub_xfs_sb_hasftype(data);
data->hascrc = grub_xfs_sb_hascrc(data);
data->disk = disk;
data->pos = 0;
grub_dprintf("xfs", "Reading root ino %"PRIuGRUB_UINT64_T"\n",
grub_cpu_to_be64(data->sblock.rootino));
grub_xfs_read_inode (data, data->diropen.ino, &data->diropen.inode);
@@ -799,10 +1018,7 @@ grub_xfs_open (struct grub_file *file, const char *name)
if (fdiro != &data->diropen)
{
grub_memcpy (&data->diropen, fdiro,
sizeof (struct grub_fshelp_node)
- sizeof (struct grub_xfs_inode)
+ (1 << data->sblock.log2_inode));
grub_memcpy (&data->diropen, fdiro, grub_xfs_fshelp_size(data));
grub_free (fdiro);
}
@@ -832,7 +1048,7 @@ grub_xfs_read (grub_file_t file, char *buf, grub_size_t len)
return grub_xfs_read_file (&data->diropen,
file->read_hook, file->read_hook_data,
file->offset, len, buf);
file->offset, len, buf, 0);
}
+141 -51
View File
@@ -252,7 +252,6 @@ struct grub_zfs_data
uberblock_t current_uberblock;
int mounted;
grub_uint64_t guid;
};
@@ -281,21 +280,30 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key
*/
#define MAX_SUPPORTED_FEATURE_STRLEN 50
static const char *spa_feature_names[] = {
"org.illumos:lz4_compress",NULL
"org.illumos:lz4_compress",
"com.delphix:hole_birth",
"com.delphix:embedded_data",
"com.delphix:extensible_dataset",
"org.open-zfs:large_blocks",
NULL
};
static int
check_feature(const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx);
static int
static grub_err_t
check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data );
static grub_err_t
zlib_decompress (void *s, void *d,
grub_size_t slen, grub_size_t dlen)
{
if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
return grub_errno;
return GRUB_ERR_NONE;
if (grub_zlib_decompress (s, slen, 0, d, dlen) == (grub_ssize_t) dlen)
return GRUB_ERR_NONE;
if (!grub_errno)
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"premature end of compressed");
return grub_errno;
}
static grub_err_t
@@ -953,7 +961,7 @@ nvpair_value (const char *nvp,char **val,
static grub_err_t
check_pool_label (struct grub_zfs_data *data,
struct grub_zfs_device_desc *diskdesc,
int *inserted)
int *inserted, int original)
{
grub_uint64_t pool_state, txg = 0;
char *nvlist,*features;
@@ -1077,11 +1085,12 @@ check_pool_label (struct grub_zfs_data *data,
grub_dprintf ("zfs", "check 11 passed\n");
if (data->mounted && data->guid != poolguid)
return grub_error (GRUB_ERR_BAD_FS, "another zpool");
else
if (original)
data->guid = poolguid;
if (data->guid != poolguid)
return grub_error (GRUB_ERR_BAD_FS, "another zpool");
{
char *nv;
nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
@@ -1182,7 +1191,7 @@ scan_disk (grub_device_t dev, struct grub_zfs_data *data,
}
grub_dprintf ("zfs", "label ok %d\n", label);
err = check_pool_label (data, &desc, inserted);
err = check_pool_label (data, &desc, inserted, original);
if (err || !*inserted)
{
grub_errno = GRUB_ERR_NONE;
@@ -1497,6 +1506,9 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"raidz%d is not supported", desc->nparity);
if (desc->n_children <= desc->nparity || desc->n_children < 1)
return grub_error(GRUB_ERR_BAD_FS, "too little devices for given parity");
orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift)
+ (desc->n_children - desc->nparity) - 1);
s = orig_s;
@@ -1744,7 +1756,7 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
for (i = 0; i < SPA_GBH_NBLKPTRS; i++)
{
if (zio_gb->zg_blkptr[i].blk_birth == 0)
if (BP_IS_HOLE(&zio_gb->zg_blkptr[i]))
continue;
err = zio_read_data (&zio_gb->zg_blkptr[i], endian, buf, data);
@@ -1793,6 +1805,39 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
return err;
}
/*
* buf must be at least BPE_GET_PSIZE(bp) bytes long (which will never be
* more than BPE_PAYLOAD_SIZE bytes).
*/
static grub_err_t
decode_embedded_bp_compressed(const blkptr_t *bp, void *buf)
{
grub_size_t psize, i;
grub_uint8_t *buf8 = buf;
grub_uint64_t w = 0;
const grub_uint64_t *bp64 = (const grub_uint64_t *)bp;
psize = BPE_GET_PSIZE(bp);
/*
* Decode the words of the block pointer into the byte array.
* Low bits of first word are the first byte (little endian).
*/
for (i = 0; i < psize; i++)
{
if (i % sizeof (w) == 0)
{
/* beginning of a word */
w = *bp64;
bp64++;
if (!BPE_IS_PAYLOADWORD(bp, bp64))
bp64++;
}
buf8[i] = BF64_GET(w, (i % sizeof (w)) * 8, 8);
}
return GRUB_ERR_NONE;
}
/*
* Read in a block of data, verify its checksum, decompress if needed,
* and put the uncompressed data in buf.
@@ -1811,12 +1856,26 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
*buf = NULL;
checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff;
comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0x7f;
encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3);
lsize = (BP_IS_HOLE(bp) ? 0 :
(((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
<< SPA_MINBLOCKSHIFT));
psize = get_psize (bp, endian);
if (BP_IS_EMBEDDED(bp))
{
if (BPE_GET_ETYPE(bp) != BP_EMBEDDED_TYPE_DATA)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported embedded BP (type=%u)\n",
BPE_GET_ETYPE(bp));
lsize = BPE_GET_LSIZE(bp);
psize = BF64_GET_SB(grub_zfs_to_cpu64 ((bp)->blk_prop, endian), 25, 7, 0, 1);
}
else
{
lsize = (BP_IS_HOLE(bp) ? 0 :
(((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
<< SPA_MINBLOCKSHIFT));
psize = get_psize (bp, endian);
}
grub_dprintf("zfs", "zio_read: E %d: size %" PRIdGRUB_SSIZE "/%"
PRIdGRUB_SSIZE "\n", (int)BP_IS_EMBEDDED(bp), lsize, psize);
if (size)
*size = lsize;
@@ -1830,33 +1889,41 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
"compression algorithm %s not supported\n", decomp_table[comp].name);
if (comp != ZIO_COMPRESS_OFF)
{
/* It's not really necessary to align to 16, just for safety. */
compbuf = grub_malloc (ALIGN_UP (psize, 16));
if (! compbuf)
return grub_errno;
}
/* It's not really necessary to align to 16, just for safety. */
compbuf = grub_malloc (ALIGN_UP (psize, 16));
else
compbuf = *buf = grub_malloc (lsize);
if (! compbuf)
return grub_errno;
grub_dprintf ("zfs", "endian = %d\n", endian);
err = zio_read_data (bp, endian, compbuf, data);
if (BP_IS_EMBEDDED(bp))
err = decode_embedded_bp_compressed(bp, compbuf);
else
{
err = zio_read_data (bp, endian, compbuf, data);
/* FIXME is it really necessary? */
if (comp != ZIO_COMPRESS_OFF)
grub_memset (compbuf + psize, 0, ALIGN_UP (psize, 16) - psize);
}
if (err)
{
grub_free (compbuf);
*buf = NULL;
return err;
}
grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize);
err = zio_checksum_verify (zc, checksum, endian,
compbuf, psize);
if (err)
if (!BP_IS_EMBEDDED(bp))
{
grub_dprintf ("zfs", "incorrect checksum\n");
grub_free (compbuf);
*buf = NULL;
return err;
err = zio_checksum_verify (zc, checksum, endian,
compbuf, psize);
if (err)
{
grub_dprintf ("zfs", "incorrect checksum\n");
grub_free (compbuf);
*buf = NULL;
return err;
}
}
if (encrypted)
@@ -1968,7 +2035,7 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
dn->endian)
<< SPA_MINBLOCKSHIFT;
*buf = grub_malloc (size);
if (*buf)
if (!*buf)
{
err = grub_errno;
break;
@@ -2006,12 +2073,14 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
*/
static grub_err_t
mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
int objsize, const char *name, grub_uint64_t * value,
grub_uint32_t objsize, const char *name, grub_uint64_t * value,
int case_insensitive)
{
int i, chunks;
grub_uint32_t i, chunks;
mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
if (objsize < MZAP_ENT_LEN)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name);
chunks = objsize / MZAP_ENT_LEN - 1;
for (i = 0; i < chunks; i++)
{
@@ -2419,7 +2488,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val,
struct grub_zfs_data *data, int case_insensitive)
{
grub_uint64_t block_type;
int size;
grub_uint32_t size;
void *zapbuf;
grub_err_t err;
grub_zfs_endian_t endian;
@@ -2427,7 +2496,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val,
grub_dprintf ("zfs", "looking for '%s'\n", name);
/* Read in the first block of the zap object data. */
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
size = (grub_uint32_t) grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
zap_dnode->endian) << SPA_MINBLOCKSHIFT;
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
if (err)
@@ -2800,6 +2869,9 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
dnode_path->dn.endian)
<< SPA_MINBLOCKSHIFT);
if (blksz == 0)
return grub_error(GRUB_ERR_BAD_FS, "0-sized block");
sym_value = grub_malloc (sym_sz);
if (!sym_value)
return grub_errno;
@@ -2810,7 +2882,10 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
if (err)
return err;
{
grub_free (sym_value);
return err;
}
movesize = sym_sz - block * blksz;
if (movesize > blksz)
@@ -2825,6 +2900,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
if (!path_buf)
{
grub_free (oldpathbuf);
if (free_symval)
grub_free (sym_value);
return grub_errno;
}
grub_memcpy (path, sym_value, sym_sz);
@@ -3008,7 +3085,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
grub_dprintf ("zfs", "alive\n");
err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data);
err = dnode_get (mosmdn, objnum, 0, mdn, data);
if (err)
return err;
@@ -3041,7 +3118,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
if (err)
return err;
err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data);
err = dnode_get (mosmdn, objnum, 0, mdn, data);
if (err)
return err;
@@ -3055,7 +3132,7 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
{
void *osp;
blkptr_t *bp;
grub_size_t ospsize;
grub_size_t ospsize = 0;
grub_err_t err;
grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
@@ -3196,8 +3273,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn,
data);
err = dnode_get (&(data->mos), headobj, 0, &subvol->mdn, data);
if (err)
{
grub_free (fsname);
@@ -3593,8 +3669,13 @@ zfs_mount (grub_device_t dev)
if (ub->ub_version >= SPA_VERSION_FEATURES &&
check_mos_features(&((objset_phys_t *) osp)->os_meta_dnode,ub_endian,
data) != 0)
return NULL;
{
grub_error (GRUB_ERR_BAD_FS, "Unsupported features in pool");
grub_free (osp);
zfs_unmount (data);
return NULL;
}
/* Got the MOS. Save it at the memory addr MOS. */
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
DNODE_SIZE);
@@ -3602,8 +3683,6 @@ zfs_mount (grub_device_t dev)
ub_endian) >> 63) & 1;
grub_free (osp);
data->mounted = 1;
return data;
}
@@ -3794,6 +3873,12 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec,
data->dnode.endian) << SPA_MINBLOCKSHIFT;
if (blksz == 0)
{
grub_error (GRUB_ERR_BAD_FS, "0-sized block");
return -1;
}
/*
* Entire Dnode is too big to fit into the space available. We
* will need to read it in chunks. This could be optimized to
@@ -3887,7 +3972,7 @@ fill_fs_info (struct grub_dirhook_info *info,
{
headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian);
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &mdn, data);
err = dnode_get (&(data->mos), headobj, 0, &mdn, data);
if (err)
{
grub_dprintf ("zfs", "failed here\n");
@@ -3965,7 +4050,12 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx)
dnode_end_t dn;
grub_memset (&info, 0, sizeof (info));
dnode_get (&(ctx->data->subvol.mdn), val, 0, &dn, ctx->data);
err = dnode_get (&(ctx->data->subvol.mdn), val, 0, &dn, ctx->data);
if (err)
{
grub_print_error ();
return 0;
}
if (dn.dn.dn_bonustype == DMU_OT_SA)
{
@@ -4186,11 +4276,11 @@ check_feature (const char *name, grub_uint64_t val,
* errnum: Failure.
*/
static int
static grub_err_t
check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data )
{
grub_uint64_t objnum;
grub_uint8_t errnum = 0;
grub_err_t errnum = 0;
dnode_end_t dn,mosmdn;
mzap_phys_t* mzp;
grub_zfs_endian_t endianzap;
+2
View File
@@ -184,6 +184,8 @@ LZ4_uncompress_unknownOutputSize(const char *source,
}
}
/* copy literals */
if ((grub_addr_t) length > ~(grub_addr_t)op)
goto _output_error;
cpy = op + length;
if ((cpy > oend - COPYLENGTH) ||
(ip + length > iend - COPYLENGTH)) {
+12 -5
View File
@@ -238,7 +238,7 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize);
}
for (j = 0; j < 8; j++)
mac[15 - j] ^= ((psize * 8) >> (8 * j));
mac[15 - j] ^= ((((grub_uint64_t) psize) * 8) >> (8 * j));
grub_gcm_mul (mac, h);
if (mac_out)
@@ -354,6 +354,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
if (err)
{
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (cipher);
continue;
}
@@ -362,6 +363,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
if (err)
{
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (cipher);
continue;
}
@@ -372,6 +374,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
{
grub_dprintf ("zfs", "key loading failed\n");
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (cipher);
continue;
}
@@ -381,21 +384,25 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
{
grub_dprintf ("zfs", "key loading failed\n");
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (cipher);
continue;
}
ret = grub_crypto_cipher_open (GRUB_CIPHER_AES);
if (!ret)
{
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (cipher);
continue;
}
err = grub_crypto_cipher_set_key (ret, decrypted, keylen);
if (err)
{
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (ret);
continue;
}
grub_errno = GRUB_ERR_NONE;
grub_crypto_cipher_close (ret);
grub_crypto_cipher_close (cipher);
continue;
}
grub_crypto_cipher_close (cipher);
return ret;
}
return NULL;
+2
View File
@@ -130,10 +130,12 @@ print_vdev_info (char *nvlist, int tab)
grub_free (bootpath);
grub_free (devid);
grub_free (path);
grub_free (type);
return GRUB_ERR_NONE;
}
char is_mirror=(grub_strcmp(type,VDEV_TYPE_MIRROR) == 0);
char is_raidz=(grub_strcmp(type,VDEV_TYPE_RAIDZ) == 0);
grub_free (type);
if (is_mirror || is_raidz)
{