merge mainline into zfs
This commit is contained in:
commit
11e50e923a
553 changed files with 42706 additions and 8566 deletions
|
@ -26,6 +26,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* The affs bootblock. */
|
||||
struct grub_affs_bblock
|
||||
{
|
||||
|
@ -50,12 +52,20 @@ struct grub_affs_rblock
|
|||
grub_uint32_t hashtable[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_affs_time
|
||||
{
|
||||
grub_int32_t day;
|
||||
grub_uint32_t min;
|
||||
grub_uint32_t hz;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* The second part of a file header block. */
|
||||
struct grub_affs_file
|
||||
{
|
||||
grub_uint8_t unused1[12];
|
||||
grub_uint32_t size;
|
||||
grub_uint8_t unused2[104];
|
||||
grub_uint8_t unused2[92];
|
||||
struct grub_affs_time mtime;
|
||||
grub_uint8_t namelen;
|
||||
grub_uint8_t name[30];
|
||||
grub_uint8_t unused3[33];
|
||||
|
@ -85,9 +95,9 @@ struct grub_affs_file
|
|||
struct grub_fshelp_node
|
||||
{
|
||||
struct grub_affs_data *data;
|
||||
int block;
|
||||
int size;
|
||||
int parent;
|
||||
grub_disk_addr_t block;
|
||||
struct grub_fshelp_node *parent;
|
||||
struct grub_affs_file di;
|
||||
};
|
||||
|
||||
/* Information about a "mounted" affs filesystem. */
|
||||
|
@ -115,7 +125,7 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
int block = node->block;
|
||||
struct grub_affs_file file;
|
||||
struct grub_affs_data *data = node->data;
|
||||
grub_uint32_t mod;
|
||||
grub_uint64_t mod;
|
||||
|
||||
/* Find the block that points to the fileblock we are looking up by
|
||||
following the chain until the right table is reached. */
|
||||
|
@ -150,11 +160,11 @@ static grub_ssize_t
|
|||
grub_affs_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_affs_read_block,
|
||||
node->size, 0);
|
||||
grub_be_to_cpu32 (node->di.size), 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,7 +176,6 @@ grub_affs_mount (grub_disk_t disk)
|
|||
struct grub_affs_rblock *rblock;
|
||||
|
||||
int checksum = 0;
|
||||
int checksumr = 0;
|
||||
int blocksize = 0;
|
||||
|
||||
data = grub_malloc (sizeof (struct grub_affs_data));
|
||||
|
@ -208,7 +217,7 @@ grub_affs_mount (grub_disk_t disk)
|
|||
rblock = (struct grub_affs_rblock *) rootblock;
|
||||
|
||||
/* Read the rootblock. */
|
||||
grub_disk_read (disk, (disk->total_sectors >> 1) + blocksize, 0,
|
||||
grub_disk_read (disk, grub_be_to_cpu32 (data->bblock.rootblock), 0,
|
||||
GRUB_DISK_SECTOR_SIZE * 16, rootblock);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
@ -216,8 +225,6 @@ grub_affs_mount (grub_disk_t disk)
|
|||
/* The filesystem blocksize is not stored anywhere in the filesystem
|
||||
itself. One way to determine it is reading blocks for the
|
||||
rootblock until the checksum is correct. */
|
||||
checksumr = grub_be_to_cpu32 (rblock->checksum);
|
||||
rblock->checksum = 0;
|
||||
for (blocksize = 0; blocksize < 8; blocksize++)
|
||||
{
|
||||
grub_uint32_t *currblock = rootblock + GRUB_DISK_SECTOR_SIZE * blocksize;
|
||||
|
@ -226,10 +233,10 @@ grub_affs_mount (grub_disk_t disk)
|
|||
for (i = 0; i < GRUB_DISK_SECTOR_SIZE / sizeof (*currblock); i++)
|
||||
checksum += grub_be_to_cpu32 (currblock[i]);
|
||||
|
||||
if (checksumr == -checksum)
|
||||
if (checksum == 0)
|
||||
break;
|
||||
}
|
||||
if (-checksum != checksumr)
|
||||
if (checksum != 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined");
|
||||
goto fail;
|
||||
|
@ -240,7 +247,9 @@ grub_affs_mount (grub_disk_t disk)
|
|||
data->disk = disk;
|
||||
data->htsize = grub_be_to_cpu32 (rblock->htsize);
|
||||
data->diropen.data = data;
|
||||
data->diropen.block = (disk->total_sectors >> 1);
|
||||
data->diropen.block = grub_be_to_cpu32 (data->bblock.rootblock);
|
||||
data->diropen.parent = NULL;
|
||||
grub_memcpy (&data->diropen.di, rootblock, sizeof (data->diropen.di));
|
||||
|
||||
grub_free (rootblock);
|
||||
|
||||
|
@ -291,12 +300,15 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
struct grub_affs_data *data = dir->data;
|
||||
grub_uint32_t *hashtable;
|
||||
|
||||
auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, int block,
|
||||
int size, int type);
|
||||
auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
||||
grub_disk_addr_t block,
|
||||
const struct grub_affs_file *fil);
|
||||
|
||||
int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, int block,
|
||||
int size, int type)
|
||||
int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
||||
grub_disk_addr_t block,
|
||||
const struct grub_affs_file *fil)
|
||||
{
|
||||
int type;
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (!node)
|
||||
{
|
||||
|
@ -304,10 +316,19 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if ((int) grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
|
||||
type = GRUB_FSHELP_REG;
|
||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
|
||||
type = GRUB_FSHELP_DIR;
|
||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_SYMLINK)
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
else
|
||||
type = GRUB_FSHELP_UNKNOWN;
|
||||
|
||||
node->data = data;
|
||||
node->size = size;
|
||||
node->block = block;
|
||||
node->parent = grub_be_to_cpu32 (file.parent);
|
||||
node->di = *fil;
|
||||
node->parent = dir;
|
||||
|
||||
if (hook (name, type, node))
|
||||
{
|
||||
|
@ -317,6 +338,24 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Create the directory entries for `.' and `..'. */
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (!node)
|
||||
return 1;
|
||||
|
||||
*node = *dir;
|
||||
if (hook (".", GRUB_FSHELP_DIR, node))
|
||||
return 1;
|
||||
if (dir->parent)
|
||||
{
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (!node)
|
||||
return 1;
|
||||
*node = *dir->parent;
|
||||
if (hook ("..", GRUB_FSHELP_DIR, node))
|
||||
return 1;
|
||||
}
|
||||
|
||||
hashtable = grub_malloc (data->htsize * sizeof (*hashtable));
|
||||
if (!hashtable)
|
||||
return 1;
|
||||
|
@ -326,16 +365,8 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
/* Create the directory entries for `.' and `..'. */
|
||||
if (grub_affs_create_node (".", dir->block, dir->size, GRUB_FSHELP_DIR))
|
||||
return 1;
|
||||
if (grub_affs_create_node ("..", dir->parent ? dir->parent : dir->block,
|
||||
dir->size, GRUB_FSHELP_DIR))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < data->htsize; i++)
|
||||
{
|
||||
enum grub_fshelp_filetype type;
|
||||
grub_uint64_t next;
|
||||
|
||||
if (!hashtable[i])
|
||||
|
@ -356,17 +387,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
|
||||
file.name[file.namelen] = '\0';
|
||||
|
||||
if ((int) grub_be_to_cpu32 (file.type) == GRUB_AFFS_FILETYPE_DIR)
|
||||
type = GRUB_FSHELP_REG;
|
||||
else if (grub_be_to_cpu32 (file.type) == GRUB_AFFS_FILETYPE_REG)
|
||||
type = GRUB_FSHELP_DIR;
|
||||
else if (grub_be_to_cpu32 (file.type) == GRUB_AFFS_FILETYPE_SYMLINK)
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
else
|
||||
type = GRUB_FSHELP_UNKNOWN;
|
||||
|
||||
if (grub_affs_create_node ((char *) (file.name), next,
|
||||
grub_be_to_cpu32 (file.size), type))
|
||||
if (grub_affs_create_node ((char *) (file.name), next, &file))
|
||||
return 1;
|
||||
|
||||
next = grub_be_to_cpu32 (file.next);
|
||||
|
@ -401,7 +422,7 @@ grub_affs_open (struct grub_file *file, const char *name)
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
file->size = fdiro->size;
|
||||
file->size = grub_be_to_cpu32 (fdiro->di.size);
|
||||
data->diropen = *fdiro;
|
||||
grub_free (fdiro);
|
||||
|
||||
|
@ -465,6 +486,11 @@ grub_affs_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_be_to_cpu32 (node->di.mtime.day) * 86400
|
||||
+ grub_be_to_cpu32 (node->di.mtime.min) * 60
|
||||
+ grub_be_to_cpu32 (node->di.mtime.hz) / 50
|
||||
+ 8 * 365 * 86400 + 86400 * 2;
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
@ -507,7 +533,7 @@ grub_affs_label (grub_device_t device, char **label)
|
|||
{
|
||||
/* The rootblock maps quite well on a file header block, it's
|
||||
something we can use here. */
|
||||
grub_disk_read (data->disk, disk->total_sectors >> 1,
|
||||
grub_disk_read (data->disk, grub_be_to_cpu32 (data->bblock.rootblock),
|
||||
data->blocksize * (GRUB_DISK_SECTOR_SIZE
|
||||
- GRUB_AFFS_FILE_LOCATION),
|
||||
sizeof (file), &file);
|
||||
|
@ -535,6 +561,9 @@ static struct grub_fs grub_affs_fs =
|
|||
.read = grub_affs_read,
|
||||
.close = grub_affs_close,
|
||||
.label = grub_affs_label,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 0,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#ifdef MODE_BIGENDIAN
|
||||
#define GRUB_AFS_FSNAME_SUFFIX "_be"
|
||||
#else
|
||||
|
@ -334,7 +336,7 @@ static grub_ssize_t
|
|||
grub_afs_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_afs_read_block,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,6 +23,8 @@
|
|||
#include <grub/disk.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#ifndef MODE_USTAR
|
||||
/* cpio support */
|
||||
#define MAGIC_BCPIO 070707
|
||||
|
@ -69,76 +71,102 @@ struct head
|
|||
struct grub_cpio_data
|
||||
{
|
||||
grub_disk_t disk;
|
||||
grub_uint32_t hofs;
|
||||
grub_uint32_t dofs;
|
||||
grub_uint32_t size;
|
||||
grub_off_t hofs;
|
||||
grub_off_t dofs;
|
||||
grub_off_t size;
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
static inline void
|
||||
canonicalize (char *name)
|
||||
{
|
||||
char *iptr, *optr;
|
||||
for (iptr = name, optr = name; *iptr; )
|
||||
{
|
||||
while (*iptr == '/')
|
||||
iptr++;
|
||||
if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
|
||||
{
|
||||
iptr += 2;
|
||||
continue;
|
||||
}
|
||||
while (*iptr && *iptr != '/')
|
||||
*optr++ = *iptr++;
|
||||
if (*iptr)
|
||||
*optr++ = *iptr++;
|
||||
}
|
||||
*optr = 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cpio_find_file (struct grub_cpio_data *data, char **name,
|
||||
grub_uint32_t * ofs)
|
||||
grub_int32_t *mtime, grub_disk_addr_t * ofs)
|
||||
{
|
||||
#ifndef MODE_USTAR
|
||||
struct head hd;
|
||||
struct head hd;
|
||||
|
||||
if (grub_disk_read
|
||||
(data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
|
||||
if (hd.magic != MAGIC_BCPIO)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
|
||||
if (hd.magic != MAGIC_BCPIO)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
|
||||
|
||||
data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
|
||||
data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
|
||||
if (mtime)
|
||||
*mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2;
|
||||
|
||||
if (hd.namesize & 1)
|
||||
hd.namesize++;
|
||||
if (hd.namesize & 1)
|
||||
hd.namesize++;
|
||||
|
||||
if ((*name = grub_malloc (hd.namesize)) == NULL)
|
||||
return grub_errno;
|
||||
if ((*name = grub_malloc (hd.namesize)) == NULL)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
|
||||
hd.namesize, *name))
|
||||
{
|
||||
grub_free (*name);
|
||||
return grub_errno;
|
||||
}
|
||||
if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
|
||||
hd.namesize, *name))
|
||||
{
|
||||
grub_free (*name);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
|
||||
&& ! grub_memcmp(*name, "TRAILER!!!", 11))
|
||||
{
|
||||
*ofs = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
|
||||
&& ! grub_memcmp(*name, "TRAILER!!!", 11))
|
||||
{
|
||||
*ofs = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
data->dofs = data->hofs + sizeof (hd) + hd.namesize;
|
||||
*ofs = data->dofs + data->size;
|
||||
if (data->size & 1)
|
||||
(*ofs)++;
|
||||
canonicalize (*name);
|
||||
|
||||
data->dofs = data->hofs + sizeof (hd) + hd.namesize;
|
||||
*ofs = data->dofs + data->size;
|
||||
if (data->size & 1)
|
||||
(*ofs)++;
|
||||
#else
|
||||
struct head hd;
|
||||
struct head hd;
|
||||
|
||||
if (grub_disk_read
|
||||
(data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
|
||||
if (!hd.name[0])
|
||||
{
|
||||
*ofs = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (!hd.name[0])
|
||||
{
|
||||
*ofs = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
|
||||
if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
|
||||
|
||||
if ((*name = grub_strdup (hd.name)) == NULL)
|
||||
return grub_errno;
|
||||
if ((*name = grub_strdup (hd.name)) == NULL)
|
||||
return grub_errno;
|
||||
|
||||
data->size = grub_strtoul (hd.size, NULL, 8);
|
||||
data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
|
||||
*ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
|
||||
~(GRUB_DISK_SECTOR_SIZE - 1));
|
||||
data->size = grub_strtoull (hd.size, NULL, 8);
|
||||
data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
|
||||
*ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
|
||||
~(GRUB_DISK_SECTOR_SIZE - 1));
|
||||
if (mtime)
|
||||
*mtime = grub_strtoul (hd.mtime, NULL, 8);
|
||||
canonicalize (*name);
|
||||
#endif
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -185,10 +213,10 @@ grub_cpio_dir (grub_device_t device, const char *path,
|
|||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
struct grub_cpio_data *data;
|
||||
grub_uint32_t ofs;
|
||||
grub_disk_addr_t ofs;
|
||||
char *prev, *name;
|
||||
const char *np;
|
||||
int len;
|
||||
grub_size_t len;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
|
@ -204,7 +232,9 @@ grub_cpio_dir (grub_device_t device, const char *path,
|
|||
data->hofs = 0;
|
||||
while (1)
|
||||
{
|
||||
if (grub_cpio_find_file (data, &name, &ofs))
|
||||
grub_int32_t mtime;
|
||||
|
||||
if (grub_cpio_find_file (data, &name, &mtime, &ofs))
|
||||
goto fail;
|
||||
|
||||
if (!ofs)
|
||||
|
@ -222,15 +252,16 @@ grub_cpio_dir (grub_device_t device, const char *path,
|
|||
if (p)
|
||||
*p = 0;
|
||||
|
||||
if ((!prev) || (grub_strcmp (prev, name) != 0))
|
||||
if (((!prev) || (grub_strcmp (prev, name) != 0)) && name[len] != 0)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = (p != NULL);
|
||||
info.mtime = mtime;
|
||||
info.mtimeset = 1;
|
||||
|
||||
hook (name + len, &info);
|
||||
if (prev)
|
||||
grub_free (prev);
|
||||
grub_free (prev);
|
||||
prev = name;
|
||||
}
|
||||
else
|
||||
|
@ -241,11 +272,8 @@ grub_cpio_dir (grub_device_t device, const char *path,
|
|||
|
||||
fail:
|
||||
|
||||
if (prev)
|
||||
grub_free (prev);
|
||||
|
||||
if (data)
|
||||
grub_free (data);
|
||||
grub_free (prev);
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -256,7 +284,7 @@ static grub_err_t
|
|||
grub_cpio_open (grub_file_t file, const char *name)
|
||||
{
|
||||
struct grub_cpio_data *data;
|
||||
grub_uint32_t ofs;
|
||||
grub_disk_addr_t ofs;
|
||||
char *fn;
|
||||
int i, j;
|
||||
|
||||
|
@ -269,7 +297,7 @@ grub_cpio_open (grub_file_t file, const char *name)
|
|||
data->hofs = 0;
|
||||
while (1)
|
||||
{
|
||||
if (grub_cpio_find_file (data, &fn, &ofs))
|
||||
if (grub_cpio_find_file (data, &fn, NULL, &ofs))
|
||||
goto fail;
|
||||
|
||||
if (!ofs)
|
||||
|
@ -316,8 +344,7 @@ grub_cpio_open (grub_file_t file, const char *name)
|
|||
|
||||
fail:
|
||||
|
||||
if (data)
|
||||
grub_free (data);
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -354,6 +381,9 @@ static struct grub_fs grub_cpio_fs = {
|
|||
.open = grub_cpio_open,
|
||||
.read = grub_cpio_read,
|
||||
.close = grub_cpio_close,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef MODE_USTAR
|
||||
|
|
2
grub-core/fs/exfat.c
Normal file
2
grub-core/fs/exfat.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define MODE_EXFAT 1
|
||||
#include "fat.c"
|
|
@ -51,6 +51,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* Log2 size of ext2 block in 512 blocks. */
|
||||
#define LOG2_EXT2_BLOCK_SIZE(data) \
|
||||
(grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
|
||||
|
@ -555,7 +557,7 @@ grub_ext2_read_inode (struct grub_ext2_data *data,
|
|||
|
||||
/* Read the inode. */
|
||||
if (grub_disk_read (data->disk,
|
||||
((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
|
||||
(((grub_disk_addr_t) grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
|
||||
<< LOG2_EXT2_BLOCK_SIZE (data)),
|
||||
EXT2_INODE_SIZE (data) * blkoff,
|
||||
sizeof (struct grub_ext2_inode), inode))
|
||||
|
|
|
@ -26,75 +26,121 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/charset.h>
|
||||
#include <grub/fat.h>
|
||||
|
||||
#define GRUB_FAT_DIR_ENTRY_SIZE 32
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_FAT_ATTR_READ_ONLY 0x01
|
||||
#define GRUB_FAT_ATTR_HIDDEN 0x02
|
||||
#define GRUB_FAT_ATTR_SYSTEM 0x04
|
||||
#define GRUB_FAT_ATTR_VOLUME_ID 0x08
|
||||
#define GRUB_FAT_ATTR_DIRECTORY 0x10
|
||||
#define GRUB_FAT_ATTR_ARCHIVE 0x20
|
||||
enum
|
||||
{
|
||||
GRUB_FAT_ATTR_READ_ONLY = 0x01,
|
||||
GRUB_FAT_ATTR_HIDDEN = 0x02,
|
||||
GRUB_FAT_ATTR_SYSTEM = 0x04,
|
||||
#ifndef MODE_EXFAT
|
||||
GRUB_FAT_ATTR_VOLUME_ID = 0x08,
|
||||
#endif
|
||||
GRUB_FAT_ATTR_DIRECTORY = 0x10,
|
||||
GRUB_FAT_ATTR_ARCHIVE = 0x20,
|
||||
|
||||
#define GRUB_FAT_MAXFILE 256
|
||||
#ifndef MODE_EXFAT
|
||||
GRUB_FAT_ATTR_LONG_NAME = (GRUB_FAT_ATTR_READ_ONLY
|
||||
| GRUB_FAT_ATTR_HIDDEN
|
||||
| GRUB_FAT_ATTR_SYSTEM
|
||||
| GRUB_FAT_ATTR_VOLUME_ID),
|
||||
#endif
|
||||
GRUB_FAT_ATTR_VALID = (GRUB_FAT_ATTR_READ_ONLY
|
||||
| GRUB_FAT_ATTR_HIDDEN
|
||||
| GRUB_FAT_ATTR_SYSTEM
|
||||
| GRUB_FAT_ATTR_DIRECTORY
|
||||
| GRUB_FAT_ATTR_ARCHIVE
|
||||
#ifndef MODE_EXFAT
|
||||
| GRUB_FAT_ATTR_VOLUME_ID
|
||||
#endif
|
||||
)
|
||||
};
|
||||
|
||||
#define GRUB_FAT_ATTR_LONG_NAME (GRUB_FAT_ATTR_READ_ONLY \
|
||||
| GRUB_FAT_ATTR_HIDDEN \
|
||||
| GRUB_FAT_ATTR_SYSTEM \
|
||||
| GRUB_FAT_ATTR_VOLUME_ID)
|
||||
#define GRUB_FAT_ATTR_VALID (GRUB_FAT_ATTR_READ_ONLY \
|
||||
| GRUB_FAT_ATTR_HIDDEN \
|
||||
| GRUB_FAT_ATTR_SYSTEM \
|
||||
| GRUB_FAT_ATTR_DIRECTORY \
|
||||
| GRUB_FAT_ATTR_ARCHIVE \
|
||||
| GRUB_FAT_ATTR_VOLUME_ID)
|
||||
|
||||
struct grub_fat_bpb
|
||||
#ifdef MODE_EXFAT
|
||||
struct grub_exfat_bpb
|
||||
{
|
||||
grub_uint8_t jmp_boot[3];
|
||||
grub_uint8_t oem_name[8];
|
||||
grub_uint16_t bytes_per_sector;
|
||||
grub_uint8_t sectors_per_cluster;
|
||||
grub_uint16_t num_reserved_sectors;
|
||||
grub_uint8_t mbz[53];
|
||||
grub_uint64_t num_hidden_sectors;
|
||||
grub_uint64_t num_total_sectors;
|
||||
grub_uint32_t num_reserved_sectors;
|
||||
grub_uint32_t sectors_per_fat;
|
||||
grub_uint32_t cluster_offset;
|
||||
grub_uint32_t cluster_count;
|
||||
grub_uint32_t root_cluster;
|
||||
grub_uint32_t num_serial;
|
||||
grub_uint16_t fs_revision;
|
||||
grub_uint16_t volume_flags;
|
||||
grub_uint8_t bytes_per_sector_shift;
|
||||
grub_uint8_t sectors_per_cluster_shift;
|
||||
grub_uint8_t num_fats;
|
||||
grub_uint16_t num_root_entries;
|
||||
grub_uint16_t num_total_sectors_16;
|
||||
grub_uint8_t media;
|
||||
grub_uint16_t sectors_per_fat_16;
|
||||
grub_uint16_t sectors_per_track;
|
||||
grub_uint16_t num_heads;
|
||||
grub_uint32_t num_hidden_sectors;
|
||||
grub_uint32_t num_total_sectors_32;
|
||||
grub_uint8_t num_ph_drive;
|
||||
grub_uint8_t reserved[8];
|
||||
} __attribute__ ((packed));
|
||||
typedef struct grub_exfat_bpb grub_current_fat_bpb_t;
|
||||
#else
|
||||
typedef struct grub_fat_bpb grub_current_fat_bpb_t;
|
||||
#endif
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
struct grub_fat_dir_entry
|
||||
{
|
||||
grub_uint8_t entry_type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
grub_uint8_t num_ph_drive;
|
||||
grub_uint8_t reserved;
|
||||
grub_uint8_t boot_sig;
|
||||
grub_uint32_t num_serial;
|
||||
grub_uint8_t label[11];
|
||||
grub_uint8_t fstype[8];
|
||||
} __attribute__ ((packed)) fat12_or_fat16;
|
||||
struct
|
||||
{
|
||||
grub_uint32_t sectors_per_fat_32;
|
||||
grub_uint16_t extended_flags;
|
||||
grub_uint16_t fs_version;
|
||||
grub_uint32_t root_cluster;
|
||||
grub_uint16_t fs_info;
|
||||
grub_uint16_t backup_boot_sector;
|
||||
grub_uint8_t reserved[12];
|
||||
grub_uint8_t num_ph_drive;
|
||||
grub_uint8_t placeholder[31];
|
||||
struct {
|
||||
grub_uint8_t secondary_count;
|
||||
grub_uint16_t checksum;
|
||||
grub_uint16_t attr;
|
||||
grub_uint16_t reserved1;
|
||||
grub_uint32_t c_time;
|
||||
grub_uint32_t m_time;
|
||||
grub_uint32_t a_time;
|
||||
grub_uint8_t c_time_tenth;
|
||||
grub_uint8_t m_time_tenth;
|
||||
grub_uint8_t a_time_tenth;
|
||||
grub_uint8_t reserved2[9];
|
||||
} __attribute__ ((packed)) file;
|
||||
struct {
|
||||
grub_uint8_t flags;
|
||||
grub_uint8_t reserved1;
|
||||
grub_uint8_t boot_sig;
|
||||
grub_uint32_t num_serial;
|
||||
grub_uint8_t label[11];
|
||||
grub_uint8_t fstype[8];
|
||||
} __attribute__ ((packed)) fat32;
|
||||
} __attribute__ ((packed)) version_specific;
|
||||
grub_uint8_t name_length;
|
||||
grub_uint16_t name_hash;
|
||||
grub_uint16_t reserved2;
|
||||
grub_uint64_t valid_size;
|
||||
grub_uint32_t reserved3;
|
||||
grub_uint32_t first_cluster;
|
||||
grub_uint64_t file_size;
|
||||
} __attribute__ ((packed)) stream_extension;
|
||||
struct {
|
||||
grub_uint8_t flags;
|
||||
grub_uint16_t str[15];
|
||||
} __attribute__ ((packed)) file_name;
|
||||
struct {
|
||||
grub_uint8_t character_count;
|
||||
grub_uint16_t str[11];
|
||||
grub_uint8_t reserved[8];
|
||||
} __attribute__ ((packed)) volume_label;
|
||||
} __attribute__ ((packed)) type_specific;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_fat_dir_node
|
||||
{
|
||||
grub_uint32_t attr;
|
||||
grub_uint32_t first_cluster;
|
||||
grub_uint64_t file_size;
|
||||
grub_uint64_t valid_size;
|
||||
int have_stream;
|
||||
int is_label;
|
||||
};
|
||||
|
||||
typedef struct grub_fat_dir_node grub_fat_dir_node_t;
|
||||
|
||||
#else
|
||||
struct grub_fat_dir_entry
|
||||
{
|
||||
grub_uint8_t name[11];
|
||||
|
@ -123,6 +169,10 @@ struct grub_fat_long_name_entry
|
|||
grub_uint16_t name3[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct grub_fat_dir_entry grub_fat_dir_node_t;
|
||||
|
||||
#endif
|
||||
|
||||
struct grub_fat_data
|
||||
{
|
||||
int logical_sector_bits;
|
||||
|
@ -133,8 +183,10 @@ struct grub_fat_data
|
|||
int fat_size;
|
||||
|
||||
grub_uint32_t root_cluster;
|
||||
#ifndef MODE_EXFAT
|
||||
grub_uint32_t root_sector;
|
||||
grub_uint32_t num_root_sectors;
|
||||
#endif
|
||||
|
||||
int cluster_bits;
|
||||
grub_uint32_t cluster_eof_mark;
|
||||
|
@ -152,6 +204,7 @@ struct grub_fat_data
|
|||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
static int
|
||||
fat_log2 (unsigned x)
|
||||
{
|
||||
|
@ -168,11 +221,12 @@ fat_log2 (unsigned x)
|
|||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct grub_fat_data *
|
||||
grub_fat_mount (grub_disk_t disk)
|
||||
{
|
||||
struct grub_fat_bpb bpb;
|
||||
grub_current_fat_bpb_t bpb;
|
||||
struct grub_fat_data *data = 0;
|
||||
grub_uint32_t first_fat, magic;
|
||||
|
||||
|
@ -187,20 +241,35 @@ grub_fat_mount (grub_disk_t disk)
|
|||
if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
|
||||
goto fail;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ",
|
||||
sizeof (bpb.oem_name)) != 0)
|
||||
goto fail;
|
||||
#else
|
||||
if (grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT12", 5)
|
||||
&& grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT16", 5)
|
||||
&& grub_strncmp((const char *) bpb.version_specific.fat32.fstype, "FAT32", 5))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* Get the sizes of logical sectors and clusters. */
|
||||
#ifdef MODE_EXFAT
|
||||
data->logical_sector_bits = bpb.bytes_per_sector_shift;
|
||||
#else
|
||||
data->logical_sector_bits =
|
||||
fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
|
||||
if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS)
|
||||
#endif
|
||||
if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS
|
||||
|| data->logical_sector_bits >= 16)
|
||||
goto fail;
|
||||
data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
data->cluster_bits = bpb.sectors_per_cluster_shift;
|
||||
#else
|
||||
data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
|
||||
if (data->cluster_bits < 0)
|
||||
#endif
|
||||
if (data->cluster_bits < 0 || data->cluster_bits > 25)
|
||||
goto fail;
|
||||
data->cluster_bits += data->logical_sector_bits;
|
||||
|
||||
|
@ -210,18 +279,28 @@ grub_fat_mount (grub_disk_t disk)
|
|||
if (data->fat_sector == 0)
|
||||
goto fail;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
data->sectors_per_fat = (grub_le_to_cpu32 (bpb.sectors_per_fat)
|
||||
<< data->logical_sector_bits);
|
||||
#else
|
||||
data->sectors_per_fat = ((bpb.sectors_per_fat_16
|
||||
? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
|
||||
: grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
|
||||
<< data->logical_sector_bits);
|
||||
#endif
|
||||
if (data->sectors_per_fat == 0)
|
||||
goto fail;
|
||||
|
||||
/* Get the number of sectors in this volume. */
|
||||
#ifdef MODE_EXFAT
|
||||
data->num_sectors = ((grub_le_to_cpu64 (bpb.num_total_sectors))
|
||||
<< data->logical_sector_bits);
|
||||
#else
|
||||
data->num_sectors = ((bpb.num_total_sectors_16
|
||||
? grub_le_to_cpu16 (bpb.num_total_sectors_16)
|
||||
: grub_le_to_cpu32 (bpb.num_total_sectors_32))
|
||||
<< data->logical_sector_bits);
|
||||
#endif
|
||||
if (data->num_sectors == 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -229,22 +308,44 @@ grub_fat_mount (grub_disk_t disk)
|
|||
if (bpb.num_fats == 0)
|
||||
goto fail;
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
|
||||
data->num_root_sectors
|
||||
= ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
|
||||
* GRUB_FAT_DIR_ENTRY_SIZE
|
||||
* sizeof (struct grub_fat_dir_entry)
|
||||
+ grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
|
||||
>> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
|
||||
<< (data->logical_sector_bits));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset)
|
||||
<< data->logical_sector_bits);
|
||||
data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count)
|
||||
<< data->logical_sector_bits);
|
||||
#else
|
||||
data->cluster_sector = data->root_sector + data->num_root_sectors;
|
||||
data->num_clusters = (((data->num_sectors - data->cluster_sector)
|
||||
>> (data->cluster_bits + data->logical_sector_bits))
|
||||
+ 2);
|
||||
#endif
|
||||
|
||||
if (data->num_clusters <= 2)
|
||||
goto fail;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
{
|
||||
/* exFAT. */
|
||||
grub_uint16_t flags = grub_le_to_cpu16 (bpb.volume_flags);
|
||||
|
||||
data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster);
|
||||
data->fat_size = 32;
|
||||
data->cluster_eof_mark = 0xffffffff;
|
||||
|
||||
if ((flags & 0x1) && bpb.num_fats > 1)
|
||||
data->fat_sector += data->sectors_per_fat;
|
||||
}
|
||||
#else
|
||||
if (! bpb.sectors_per_fat_16)
|
||||
{
|
||||
/* FAT32. */
|
||||
|
@ -286,6 +387,7 @@ grub_fat_mount (grub_disk_t disk)
|
|||
data->cluster_eof_mark = 0xfff8;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* More sanity checks. */
|
||||
if (data->num_sectors <= data->fat_sector)
|
||||
|
@ -317,17 +419,25 @@ grub_fat_mount (grub_disk_t disk)
|
|||
}
|
||||
|
||||
/* Serial number. */
|
||||
#ifdef MODE_EXFAT
|
||||
data->uuid = grub_le_to_cpu32 (bpb.num_serial);
|
||||
#else
|
||||
if (bpb.sectors_per_fat_16)
|
||||
data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
|
||||
else
|
||||
data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
|
||||
#endif
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
/* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
|
||||
descriptor, even if it is a so-called superfloppy (e.g. an USB key).
|
||||
The check may be too strict for this kind of stupid BIOSes, as
|
||||
they overwrite the media descriptor. */
|
||||
if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
|
||||
goto fail;
|
||||
#else
|
||||
(void) magic;
|
||||
#endif
|
||||
|
||||
/* Start from the root directory. */
|
||||
data->file_cluster = data->root_cluster;
|
||||
|
@ -354,6 +464,7 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
|
|||
grub_ssize_t ret = 0;
|
||||
unsigned long sector;
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
/* This is a special case. FAT12 and FAT16 doesn't have the root directory
|
||||
in clusters. */
|
||||
if (data->file_cluster == ~0U)
|
||||
|
@ -367,13 +478,14 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate the logical cluster number and offset. */
|
||||
logical_cluster_bits = (data->cluster_bits
|
||||
+ data->logical_sector_bits
|
||||
+ GRUB_DISK_SECTOR_BITS);
|
||||
logical_cluster = offset >> logical_cluster_bits;
|
||||
offset &= (1 << logical_cluster_bits) - 1;
|
||||
offset &= (1ULL << logical_cluster_bits) - 1;
|
||||
|
||||
if (logical_cluster < data->cur_cluster_num)
|
||||
{
|
||||
|
@ -465,13 +577,116 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
static grub_err_t
|
||||
grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
||||
int (*hook) (const char *filename,
|
||||
grub_fat_dir_node_t *node))
|
||||
{
|
||||
struct grub_fat_dir_entry dir;
|
||||
grub_ssize_t offset = -sizeof(dir);
|
||||
grub_uint16_t *unibuf;
|
||||
char *filename;
|
||||
|
||||
unibuf = grub_malloc (15 * 256 * 2);
|
||||
filename = grub_malloc (15 * 256 * 4 + 1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
offset += sizeof (dir);
|
||||
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir))
|
||||
break;
|
||||
|
||||
if (dir.entry_type == 0)
|
||||
break;
|
||||
if (!(dir.entry_type & 0x80))
|
||||
continue;
|
||||
|
||||
if (dir.entry_type == 0x85)
|
||||
{
|
||||
unsigned i, nsec, slots = 0;
|
||||
grub_fat_dir_node_t node;
|
||||
|
||||
nsec = dir.type_specific.file.secondary_count;
|
||||
|
||||
node.attr = grub_cpu_to_le32 (dir.type_specific.file.attr);
|
||||
node.have_stream = 0;
|
||||
for (i = 0; i < nsec; i++)
|
||||
{
|
||||
struct grub_fat_dir_entry sec;
|
||||
offset += sizeof (sec);
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (sec), (char *) &sec)
|
||||
!= sizeof (sec))
|
||||
break;
|
||||
if (!(sec.entry_type & 0x80))
|
||||
continue;
|
||||
if (!(sec.entry_type & 0x40))
|
||||
break;
|
||||
switch (sec.entry_type)
|
||||
{
|
||||
case 0xc0:
|
||||
node.first_cluster = grub_cpu_to_le32 (sec.type_specific.stream_extension.first_cluster);
|
||||
node.valid_size
|
||||
= grub_cpu_to_le64 (sec.type_specific.stream_extension.valid_size);
|
||||
node.file_size
|
||||
= grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size);
|
||||
node.have_stream = 1;
|
||||
break;
|
||||
case 0xc1:
|
||||
grub_memcpy (unibuf + slots * 15,
|
||||
sec.type_specific.file_name.str, 30);
|
||||
slots++;
|
||||
break;
|
||||
default:
|
||||
grub_dprintf ("exfat", "unknown secondary type 0x%02x\n",
|
||||
sec.entry_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (i != nsec)
|
||||
{
|
||||
offset -= sizeof (dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
|
||||
slots * 15) = '\0';
|
||||
|
||||
if (hook (filename, &node))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
/* Allocation bitmap. */
|
||||
if (dir.entry_type == 0x81)
|
||||
continue;
|
||||
/* Upcase table. */
|
||||
if (dir.entry_type == 0x82)
|
||||
continue;
|
||||
/* Volume label. */
|
||||
if (dir.entry_type == 0x83)
|
||||
continue;
|
||||
grub_dprintf ("exfat", "unknown primary type 0x%02x\n", dir.entry_type);
|
||||
}
|
||||
grub_free (filename);
|
||||
grub_free (unibuf);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
||||
int (*hook) (const char *filename,
|
||||
struct grub_fat_dir_entry *dir))
|
||||
{
|
||||
struct grub_fat_dir_entry dir;
|
||||
char *filename, *filep = 0;
|
||||
char *filename;
|
||||
char *filep = 0;
|
||||
grub_uint16_t *unibuf;
|
||||
int slot = -1, slots = -1;
|
||||
int checksum = -1;
|
||||
|
@ -498,10 +713,11 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
offset += sizeof (dir);
|
||||
|
||||
/* Read a directory entry. */
|
||||
if ((grub_fat_read_data (disk, data, 0,
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir) || dir.name[0] == 0))
|
||||
!= sizeof (dir) || dir.name[0] == 0)
|
||||
break;
|
||||
|
||||
/* Handle long name entries. */
|
||||
if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
|
||||
{
|
||||
|
@ -586,7 +802,6 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
filep++;
|
||||
}
|
||||
*filep = '\0';
|
||||
|
||||
if (hook (filename, &dir))
|
||||
break;
|
||||
}
|
||||
|
@ -596,7 +811,7 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
#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.
|
||||
|
@ -608,11 +823,12 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
char *dirname, *dirp;
|
||||
char *origpath = NULL;
|
||||
int call_hook;
|
||||
int found = 0;
|
||||
|
||||
auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
|
||||
int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
|
||||
auto int iter_hook (const char *filename, grub_fat_dir_node_t *dir);
|
||||
int iter_hook (const char *filename, grub_fat_dir_node_t *dir)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
|
@ -620,8 +836,13 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
info.dir = !! (dir->attr & GRUB_FAT_ATTR_DIRECTORY);
|
||||
info.case_insensitive = 1;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
if (!dir->have_stream)
|
||||
return 0;
|
||||
#else
|
||||
if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
|
||||
return 0;
|
||||
#endif
|
||||
if (*dirname == '\0' && call_hook)
|
||||
return hook (filename, &info);
|
||||
|
||||
|
@ -629,9 +850,14 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
{
|
||||
found = 1;
|
||||
data->attr = dir->attr;
|
||||
#ifdef MODE_EXFAT
|
||||
data->file_size = dir->file_size;
|
||||
data->file_cluster = dir->first_cluster;
|
||||
#else
|
||||
data->file_size = grub_le_to_cpu32 (dir->file_size);
|
||||
data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
|
||||
| grub_le_to_cpu16 (dir->first_cluster_low));
|
||||
#endif
|
||||
data->cur_cluster_num = ~0U;
|
||||
|
||||
if (call_hook)
|
||||
|
@ -648,6 +874,10 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
origpath = grub_strdup (path);
|
||||
if (!origpath)
|
||||
return 0;
|
||||
|
||||
/* Extract a directory name. */
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
@ -659,7 +889,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
dirname = grub_malloc (len + 1);
|
||||
if (! dirname)
|
||||
return 0;
|
||||
goto fail;
|
||||
|
||||
grub_memcpy (dirname, path, len);
|
||||
dirname[len] = '\0';
|
||||
|
@ -672,9 +902,11 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
grub_fat_iterate_dir (disk, data, iter_hook);
|
||||
if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
|
||||
fail:
|
||||
grub_free (dirname);
|
||||
grub_free (origpath);
|
||||
|
||||
return found ? dirp : 0;
|
||||
}
|
||||
|
@ -781,14 +1013,63 @@ grub_fat_close (grub_file_t file)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
static grub_err_t
|
||||
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;
|
||||
|
||||
data = grub_fat_mount (disk);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
*label = NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
offset += sizeof (dir);
|
||||
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir))
|
||||
break;
|
||||
|
||||
if (dir.entry_type == 0)
|
||||
break;
|
||||
if (!(dir.entry_type & 0x80))
|
||||
continue;
|
||||
|
||||
/* Volume label. */
|
||||
if (dir.entry_type == 0x83)
|
||||
{
|
||||
grub_size_t chc;
|
||||
*label = grub_malloc (11 * 4 + 1);
|
||||
if (!*label)
|
||||
return grub_errno;
|
||||
chc = dir.type_specific.volume_label.character_count;
|
||||
if (chc > ARRAY_SIZE (dir.type_specific.volume_label.str))
|
||||
chc = ARRAY_SIZE (dir.type_specific.volume_label.str);
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) *label,
|
||||
dir.type_specific.volume_label.str, chc) = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_label (grub_device_t device, char **label)
|
||||
{
|
||||
struct grub_fat_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
|
||||
auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
|
||||
int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
|
||||
auto int iter_hook (const char *filename, grub_fat_dir_node_t *dir);
|
||||
int iter_hook (const char *filename, grub_fat_dir_node_t *dir)
|
||||
{
|
||||
if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
|
||||
{
|
||||
|
@ -823,6 +1104,8 @@ grub_fat_label (grub_device_t device, char **label)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_uuid (grub_device_t device, char **uuid)
|
||||
{
|
||||
|
@ -834,9 +1117,12 @@ grub_fat_uuid (grub_device_t device, char **uuid)
|
|||
data = grub_fat_mount (disk);
|
||||
if (data)
|
||||
{
|
||||
char *ptr;
|
||||
*uuid = grub_xasprintf ("%04x-%04x",
|
||||
(grub_uint16_t) (data->uuid >> 16),
|
||||
(grub_uint16_t) data->uuid);
|
||||
for (ptr = *uuid; ptr && *ptr; ptr++)
|
||||
*ptr = grub_toupper (*ptr);
|
||||
}
|
||||
else
|
||||
*uuid = NULL;
|
||||
|
@ -850,7 +1136,11 @@ grub_fat_uuid (grub_device_t device, char **uuid)
|
|||
|
||||
static struct grub_fs grub_fat_fs =
|
||||
{
|
||||
#ifdef MODE_EXFAT
|
||||
.name = "exfat",
|
||||
#else
|
||||
.name = "fat",
|
||||
#endif
|
||||
.dir = grub_fat_dir,
|
||||
.open = grub_fat_open,
|
||||
.read = grub_fat_read,
|
||||
|
@ -858,18 +1148,31 @@ static struct grub_fs grub_fat_fs =
|
|||
.label = grub_fat_label,
|
||||
.uuid = grub_fat_uuid,
|
||||
#ifdef GRUB_UTIL
|
||||
#ifdef MODE_EXFAT
|
||||
/* ExFAT BPB is 30 larger than FAT32 one. */
|
||||
.reserved_first_sector = 0,
|
||||
#else
|
||||
.reserved_first_sector = 1,
|
||||
#endif
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
GRUB_MOD_INIT(exfat)
|
||||
#else
|
||||
GRUB_MOD_INIT(fat)
|
||||
#endif
|
||||
{
|
||||
COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32);
|
||||
grub_fs_register (&grub_fat_fs);
|
||||
my_mod = mod;
|
||||
}
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
GRUB_MOD_FINI(exfat)
|
||||
#else
|
||||
GRUB_MOD_FINI(fat)
|
||||
#endif
|
||||
{
|
||||
grub_fs_unregister (&grub_fat_fs);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/fshelp.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* Lookup the node PATH. The node ROOTNODE describes the root of the
|
||||
directory tree. The node found is returned in FOUNDNODE, which is
|
||||
|
@ -59,7 +61,6 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
|
|||
char fpath[grub_strlen (currpath) + 1];
|
||||
char *name = fpath;
|
||||
char *next;
|
||||
// unsigned int pos = 0;
|
||||
enum grub_fshelp_filetype type = GRUB_FSHELP_DIR;
|
||||
grub_fshelp_node_t currnode = currroot;
|
||||
grub_fshelp_node_t oldnode = currroot;
|
||||
|
@ -195,7 +196,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
|
|||
name = next;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
}
|
||||
|
||||
if (!path || path[0] != '/')
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/hfs.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_HFS_SBLOCK 2
|
||||
#define GRUB_HFS_EMBED_HFSPLUS_SIG 0x482B
|
||||
|
||||
|
@ -131,6 +133,8 @@ struct grub_hfs_dirrec
|
|||
grub_uint8_t type;
|
||||
grub_uint8_t unused[5];
|
||||
grub_uint32_t dirid;
|
||||
grub_uint32_t ctime;
|
||||
grub_uint32_t mtime;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Information about a file. */
|
||||
|
@ -142,7 +146,9 @@ struct grub_hfs_filerec
|
|||
grub_uint32_t fileid;
|
||||
grub_uint8_t unused2[2];
|
||||
grub_uint32_t size;
|
||||
grub_uint8_t unused3[44];
|
||||
grub_uint8_t unused3[18];
|
||||
grub_uint32_t mtime;
|
||||
grub_uint8_t unused4[22];
|
||||
|
||||
/* The first 3 extents of the file. The other extents can be found
|
||||
in the extent overflow file. */
|
||||
|
@ -238,22 +244,24 @@ static grub_ssize_t
|
|||
grub_hfs_read_file (struct grub_hfs_data *data,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
int i;
|
||||
int blockcnt;
|
||||
grub_off_t i;
|
||||
grub_off_t blockcnt;
|
||||
|
||||
blockcnt = ((len + pos)
|
||||
+ data->blksz - 1) / data->blksz;
|
||||
blockcnt = grub_divmod64 (((len + pos)
|
||||
+ data->blksz - 1), data->blksz, 0);
|
||||
|
||||
for (i = pos / data->blksz; i < blockcnt; i++)
|
||||
for (i = grub_divmod64 (pos, data->blksz, 0); i < blockcnt; i++)
|
||||
{
|
||||
int blknr;
|
||||
int blockoff = pos % data->blksz;
|
||||
int blockend = data->blksz;
|
||||
grub_disk_addr_t blknr;
|
||||
grub_off_t blockoff;
|
||||
grub_off_t blockend = data->blksz;
|
||||
|
||||
int skipfirst = 0;
|
||||
|
||||
grub_divmod64 (pos, data->blksz, &blockoff);
|
||||
|
||||
blknr = grub_hfs_block (data, data->extents, data->fileid, i, 1);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
@ -261,7 +269,7 @@ grub_hfs_read_file (struct grub_hfs_data *data,
|
|||
/* Last block. */
|
||||
if (i == blockcnt - 1)
|
||||
{
|
||||
blockend = (len + pos) % data->blksz;
|
||||
grub_divmod64 ((len + pos), data->blksz, &blockend);
|
||||
|
||||
/* The last portion is exactly EXT2_BLOCK_SIZE (data). */
|
||||
if (! blockend)
|
||||
|
@ -269,7 +277,7 @@ grub_hfs_read_file (struct grub_hfs_data *data,
|
|||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == pos / data->blksz)
|
||||
if (i == grub_divmod64 (pos, data->blksz, 0))
|
||||
{
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
|
@ -915,7 +923,7 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
|
|||
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, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -951,19 +959,29 @@ grub_hfs_dir (grub_device_t device, const char *path,
|
|||
int dir_hook (struct grub_hfs_record *rec)
|
||||
{
|
||||
char fname[32] = { 0 };
|
||||
char *filetype = rec->data;
|
||||
struct grub_hfs_dirrec *drec = rec->data;
|
||||
struct grub_hfs_filerec *frec = rec->data;
|
||||
struct grub_hfs_catalog_key *ckey = rec->key;
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
|
||||
grub_strncpy (fname, (char *) (ckey->str), ckey->strlen);
|
||||
|
||||
if (*filetype == GRUB_HFS_FILETYPE_DIR
|
||||
|| *filetype == GRUB_HFS_FILETYPE_FILE)
|
||||
if (drec->type == GRUB_HFS_FILETYPE_DIR)
|
||||
{
|
||||
info.dir = (*filetype == GRUB_HFS_FILETYPE_DIR);
|
||||
info.dir = 1;
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800;
|
||||
return hook (fname, &info);
|
||||
}
|
||||
if (frec->type == GRUB_HFS_FILETYPE_FILE)
|
||||
{
|
||||
info.dir = 0;
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800;
|
||||
return hook (fname, &info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1072,6 +1090,22 @@ grub_hfs_label (grub_device_t device, char **label)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_hfs_mtime (grub_device_t device, grub_int32_t *tm)
|
||||
{
|
||||
struct grub_hfs_data *data;
|
||||
|
||||
data = grub_hfs_mount (device->disk);
|
||||
|
||||
if (data)
|
||||
*tm = grub_be_to_cpu32 (data->sblock.mtime) - 2082844800;
|
||||
else
|
||||
*tm = 0;
|
||||
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_hfs_uuid (grub_device_t device, char **uuid)
|
||||
{
|
||||
|
@ -1107,6 +1141,7 @@ static struct grub_fs grub_hfs_fs =
|
|||
.close = grub_hfs_close,
|
||||
.label = grub_hfs_label,
|
||||
.uuid = grub_hfs_uuid,
|
||||
.mtime = grub_hfs_mtime,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <grub/hfs.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_HFSPLUS_MAGIC 0x482B
|
||||
#define GRUB_HFSPLUSX_MAGIC 0x4858
|
||||
#define GRUB_HFSPLUS_SBLOCK 2
|
||||
|
@ -178,7 +180,7 @@ enum grub_hfsplus_filetype
|
|||
/* Internal representation of a catalog key. */
|
||||
struct grub_hfsplus_catkey_internal
|
||||
{
|
||||
int parent;
|
||||
grub_uint32_t parent;
|
||||
char *name;
|
||||
};
|
||||
|
||||
|
@ -212,7 +214,7 @@ struct grub_fshelp_node
|
|||
struct grub_hfsplus_btree
|
||||
{
|
||||
grub_uint32_t root;
|
||||
int nodesize;
|
||||
grub_size_t nodesize;
|
||||
|
||||
/* Catalog file node. */
|
||||
struct grub_fshelp_node file;
|
||||
|
@ -234,7 +236,7 @@ struct grub_hfsplus_data
|
|||
|
||||
/* This is the offset into the physical disk for an embedded HFS+
|
||||
filesystem (one inside a plain HFS wrapper). */
|
||||
int embedded_offset;
|
||||
grub_disk_addr_t embedded_offset;
|
||||
int case_sensitive;
|
||||
};
|
||||
|
||||
|
@ -243,7 +245,7 @@ static grub_dl_t my_mod;
|
|||
|
||||
/* Return the offset of the record with the index INDEX, in the node
|
||||
NODE which is part of the B+ tree BTREE. */
|
||||
static inline unsigned int
|
||||
static inline grub_off_t
|
||||
grub_hfsplus_btree_recoffset (struct grub_hfsplus_btree *btree,
|
||||
struct grub_hfsplus_btnode *node, int index)
|
||||
{
|
||||
|
@ -261,7 +263,7 @@ grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree,
|
|||
struct grub_hfsplus_btnode *node, int index)
|
||||
{
|
||||
char *cnode = (char *) node;
|
||||
unsigned int offset;
|
||||
grub_off_t offset;
|
||||
offset = grub_hfsplus_btree_recoffset (btree, node, index);
|
||||
return (struct grub_hfsplus_key *) &cnode[offset];
|
||||
}
|
||||
|
@ -270,12 +272,12 @@ grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree,
|
|||
/* Find the extent that points to FILEBLOCK. If it is not in one of
|
||||
the 8 extents described by EXTENT, return -1. In that case set
|
||||
FILEBLOCK to the next block. */
|
||||
static int
|
||||
static grub_disk_addr_t
|
||||
grub_hfsplus_find_block (struct grub_hfsplus_extent *extent,
|
||||
int *fileblock)
|
||||
grub_disk_addr_t *fileblock)
|
||||
{
|
||||
int i;
|
||||
grub_size_t blksleft = *fileblock;
|
||||
grub_disk_addr_t blksleft = *fileblock;
|
||||
|
||||
/* First lookup the file in the given extents. */
|
||||
for (i = 0; i < 8; i++)
|
||||
|
@ -286,7 +288,7 @@ grub_hfsplus_find_block (struct grub_hfsplus_extent *extent,
|
|||
}
|
||||
|
||||
*fileblock = blksleft;
|
||||
return -1;
|
||||
return 0xffffffffffffffffULL;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
@ -294,7 +296,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
struct grub_hfsplus_key_internal *key,
|
||||
int (*compare_keys) (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb),
|
||||
struct grub_hfsplus_btnode **matchnode, int *keyoffset);
|
||||
struct grub_hfsplus_btnode **matchnode,
|
||||
grub_off_t *keyoffset);
|
||||
|
||||
static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb);
|
||||
|
@ -305,15 +308,15 @@ static grub_disk_addr_t
|
|||
grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||
{
|
||||
struct grub_hfsplus_btnode *nnode = 0;
|
||||
int blksleft = fileblock;
|
||||
grub_disk_addr_t blksleft = fileblock;
|
||||
struct grub_hfsplus_extent *extents = &node->extents[0];
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct grub_hfsplus_extkey *key;
|
||||
struct grub_hfsplus_extkey_internal extoverflow;
|
||||
int blk;
|
||||
int ptr;
|
||||
grub_disk_addr_t blk;
|
||||
grub_off_t ptr;
|
||||
|
||||
/* Try to find this block in the current set of extents. */
|
||||
blk = grub_hfsplus_find_block (extents, &blksleft);
|
||||
|
@ -323,7 +326,7 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
grub_free (nnode);
|
||||
nnode = 0;
|
||||
|
||||
if (blk != -1)
|
||||
if (blk != 0xffffffffffffffffULL)
|
||||
return (blk
|
||||
+ (node->data->embedded_offset >> (node->data->log2blksize
|
||||
- GRUB_DISK_SECTOR_BITS)));
|
||||
|
@ -374,7 +377,7 @@ static grub_ssize_t
|
|||
grub_hfsplus_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_hfsplus_read_block,
|
||||
|
@ -409,9 +412,9 @@ grub_hfsplus_mount (grub_disk_t disk)
|
|||
data->embedded_offset = 0;
|
||||
if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC)
|
||||
{
|
||||
int extent_start;
|
||||
int ablk_size;
|
||||
int ablk_start;
|
||||
grub_disk_addr_t extent_start;
|
||||
grub_disk_addr_t ablk_size;
|
||||
grub_disk_addr_t ablk_start;
|
||||
|
||||
/* See if there's an embedded HFS+ filesystem. */
|
||||
if (grub_be_to_cpu16 (volheader.hfs.embed_sig) != GRUB_HFSPLUS_MAGIC)
|
||||
|
@ -520,9 +523,12 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya,
|
|||
int i;
|
||||
int diff;
|
||||
|
||||
diff = grub_be_to_cpu32 (catkey_a->parent) - catkey_b->parent;
|
||||
if (diff)
|
||||
return diff;
|
||||
/* Safe unsigned comparison */
|
||||
grub_uint32_t aparent = grub_be_to_cpu32 (catkey_a->parent);
|
||||
if (aparent > catkey_b->parent)
|
||||
return 1;
|
||||
if (aparent < catkey_b->parent)
|
||||
return -1;
|
||||
|
||||
/* Change the filename in keya so the endianness is correct. */
|
||||
for (i = 0; i < grub_be_to_cpu16 (catkey_a->namelen); i++)
|
||||
|
@ -547,6 +553,25 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya,
|
|||
return diff;
|
||||
}
|
||||
|
||||
/* Compare the on disk catalog key KEYA with the catalog key we are
|
||||
looking for (KEYB). */
|
||||
static int
|
||||
grub_hfsplus_cmp_catkey_id (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb)
|
||||
{
|
||||
struct grub_hfsplus_catkey *catkey_a = &keya->catkey;
|
||||
struct grub_hfsplus_catkey_internal *catkey_b = &keyb->catkey;
|
||||
|
||||
/* Safe unsigned comparison */
|
||||
grub_uint32_t aparent = grub_be_to_cpu32 (catkey_a->parent);
|
||||
if (aparent > catkey_b->parent)
|
||||
return 1;
|
||||
if (aparent < catkey_b->parent)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare the on disk extent overflow key KEYA with the extent
|
||||
overflow key we are looking for (KEYB). */
|
||||
static int
|
||||
|
@ -555,15 +580,21 @@ grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya,
|
|||
{
|
||||
struct grub_hfsplus_extkey *extkey_a = &keya->extkey;
|
||||
struct grub_hfsplus_extkey_internal *extkey_b = &keyb->extkey;
|
||||
int diff;
|
||||
grub_uint32_t akey;
|
||||
|
||||
diff = grub_be_to_cpu32 (extkey_a->fileid) - extkey_b->fileid;
|
||||
|
||||
if (diff)
|
||||
return diff;
|
||||
|
||||
diff = grub_be_to_cpu32 (extkey_a->start) - extkey_b->start;
|
||||
return diff;
|
||||
/* Safe unsigned comparison */
|
||||
akey = grub_be_to_cpu32 (extkey_a->fileid);
|
||||
if (akey > extkey_b->fileid)
|
||||
return 1;
|
||||
if (akey < extkey_b->fileid)
|
||||
return -1;
|
||||
|
||||
akey = grub_be_to_cpu32 (extkey_a->start);
|
||||
if (akey > extkey_b->start)
|
||||
return 1;
|
||||
if (akey < extkey_b->start)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -590,10 +621,10 @@ grub_hfsplus_read_symlink (grub_fshelp_node_t node)
|
|||
static int
|
||||
grub_hfsplus_btree_iterate_node (struct grub_hfsplus_btree *btree,
|
||||
struct grub_hfsplus_btnode *first_node,
|
||||
int first_rec,
|
||||
grub_disk_addr_t first_rec,
|
||||
int (*hook) (void *record))
|
||||
{
|
||||
int rec;
|
||||
grub_disk_addr_t rec;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
@ -631,12 +662,13 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
struct grub_hfsplus_key_internal *key,
|
||||
int (*compare_keys) (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb),
|
||||
struct grub_hfsplus_btnode **matchnode, int *keyoffset)
|
||||
struct grub_hfsplus_btnode **matchnode,
|
||||
grub_off_t *keyoffset)
|
||||
{
|
||||
grub_uint64_t currnode;
|
||||
char *node;
|
||||
struct grub_hfsplus_btnode *nodedesc;
|
||||
int rec;
|
||||
grub_disk_addr_t rec;
|
||||
|
||||
node = grub_malloc (btree->nodesize);
|
||||
if (! node)
|
||||
|
@ -649,7 +681,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
|
||||
/* Read a node. */
|
||||
if (grub_hfsplus_read_file (&btree->file, 0,
|
||||
(long)currnode * (long)btree->nodesize,
|
||||
(grub_disk_addr_t) currnode
|
||||
* (grub_disk_addr_t) btree->nodesize,
|
||||
btree->nodesize, (char *) node) <= 0)
|
||||
{
|
||||
grub_free (node);
|
||||
|
@ -814,7 +847,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
|
||||
struct grub_hfsplus_key_internal intern;
|
||||
struct grub_hfsplus_btnode *node;
|
||||
int ptr;
|
||||
grub_disk_addr_t ptr;
|
||||
|
||||
/* Create a key that points to the first entry in the directory. */
|
||||
intern.catkey.parent = dir->fileid;
|
||||
|
@ -883,7 +916,6 @@ grub_hfsplus_close (grub_file_t file)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/* Read LEN bytes data from FILE into BUF. */
|
||||
static grub_ssize_t
|
||||
grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
|
@ -891,13 +923,10 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
struct grub_hfsplus_data *data =
|
||||
(struct grub_hfsplus_data *) file->data;
|
||||
|
||||
int size = grub_hfsplus_read_file (&data->opened_file, file->read_hook,
|
||||
return grub_hfsplus_read_file (&data->opened_file, file->read_hook,
|
||||
file->offset, len, buf);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_hfsplus_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
|
@ -952,13 +981,66 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
|
|||
|
||||
|
||||
static grub_err_t
|
||||
grub_hfsplus_label (grub_device_t device __attribute__((unused))
|
||||
, char **label __attribute__((unused)))
|
||||
grub_hfsplus_label (grub_device_t device, char **label)
|
||||
{
|
||||
/* XXX: It's not documented how to read a label. */
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"reading the label of a HFS+ "
|
||||
"partition is not implemented");
|
||||
struct grub_hfsplus_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
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;
|
||||
|
||||
*label = 0;
|
||||
|
||||
data = grub_hfsplus_mount (disk);
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
/* Create a key that points to the label. */
|
||||
intern.catkey.parent = 1;
|
||||
intern.catkey.name = "";
|
||||
|
||||
/* First lookup the first entry. */
|
||||
if (grub_hfsplus_btree_search (&data->catalog_tree, &intern,
|
||||
grub_hfsplus_cmp_catkey_id, &node, &ptr))
|
||||
{
|
||||
grub_free (data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
catkey = (struct grub_hfsplus_catkey *)
|
||||
grub_hfsplus_btree_recptr (&data->catalog_tree, node, 0);
|
||||
|
||||
label_len = grub_be_to_cpu16 (catkey->namelen);
|
||||
for (i = 0; i < label_len; i++)
|
||||
{
|
||||
catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]);
|
||||
|
||||
/* If the name is obviously invalid, skip this node. */
|
||||
if (catkey->name[i] == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*label = grub_malloc (label_len + 1);
|
||||
if (! *label)
|
||||
return grub_errno;
|
||||
|
||||
if (! grub_utf16_to_utf8 ((grub_uint8_t *) (*label), catkey->name,
|
||||
label_len))
|
||||
{
|
||||
grub_free (node);
|
||||
grub_free (*label);
|
||||
grub_free (data);
|
||||
*label = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
(*label)[label_len] = '\0';
|
||||
|
||||
grub_free (node);
|
||||
grub_free (data);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Get mtime. */
|
||||
|
|
|
@ -1,641 +0,0 @@
|
|||
/* pxe.c - Driver to provide access to the pxe filesystem */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/bufio.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
#include <grub/machine/pxe.h>
|
||||
#include <grub/machine/int.h>
|
||||
#include <grub/machine/memory.h>
|
||||
|
||||
#define SEGMENT(x) ((x) >> 4)
|
||||
#define OFFSET(x) ((x) & 0xF)
|
||||
#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x))
|
||||
#define LINEAR(x) (void *) (((x >> 16) <<4) + (x & 0xFFFF))
|
||||
|
||||
struct grub_pxe_disk_data
|
||||
{
|
||||
grub_uint32_t server_ip;
|
||||
grub_uint32_t gateway_ip;
|
||||
};
|
||||
|
||||
struct grub_pxe_bangpxe *grub_pxe_pxenv;
|
||||
static grub_uint32_t grub_pxe_your_ip;
|
||||
static grub_uint32_t grub_pxe_default_server_ip;
|
||||
static grub_uint32_t grub_pxe_default_gateway_ip;
|
||||
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
|
||||
|
||||
static grub_file_t curr_file = 0;
|
||||
|
||||
struct grub_pxe_data
|
||||
{
|
||||
grub_uint32_t packet_number;
|
||||
grub_uint32_t block_size;
|
||||
char filename[0];
|
||||
};
|
||||
|
||||
static grub_uint32_t pxe_rm_entry = 0;
|
||||
|
||||
static struct grub_pxe_bangpxe *
|
||||
grub_pxe_scan (void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
struct grub_pxenv *pxenv;
|
||||
struct grub_pxe_bangpxe *bangpxe;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
|
||||
regs.ebx = 0;
|
||||
regs.ecx = 0;
|
||||
regs.eax = 0x5650;
|
||||
regs.es = 0;
|
||||
|
||||
grub_bios_interrupt (0x1a, ®s);
|
||||
|
||||
if ((regs.eax & 0xffff) != 0x564e)
|
||||
return NULL;
|
||||
|
||||
pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
|
||||
if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
|
||||
sizeof (pxenv->signature))
|
||||
!= 0)
|
||||
return NULL;
|
||||
|
||||
if (pxenv->version < 0x201)
|
||||
return NULL;
|
||||
|
||||
bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
|
||||
+ (pxenv->pxe_ptr & 0xffff));
|
||||
|
||||
if (!bangpxe)
|
||||
return NULL;
|
||||
|
||||
if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
|
||||
sizeof (bangpxe->signature)) != 0)
|
||||
return NULL;
|
||||
|
||||
pxe_rm_entry = bangpxe->rm_entry;
|
||||
|
||||
return bangpxe;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_pxe_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
if (hook ("pxe"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
|
||||
{
|
||||
grub_uint32_t newip = 0;
|
||||
unsigned long t;
|
||||
int i;
|
||||
const char *ptr = val;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
t = grub_strtoul (ptr, (char **) &ptr, 0);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
if (t & ~0xff)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
|
||||
newip >>= 8;
|
||||
newip |= (t << 24);
|
||||
if (i != 3 && *ptr != '.')
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
|
||||
ptr++;
|
||||
}
|
||||
*ip = newip;
|
||||
if (rest)
|
||||
*rest = ptr - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxe_open (const char *name, grub_disk_t disk)
|
||||
{
|
||||
struct grub_pxe_disk_data *data;
|
||||
|
||||
if (grub_strcmp (name, "pxe") != 0
|
||||
&& grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
|
||||
|
||||
data = grub_malloc (sizeof (*data));
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
|
||||
{
|
||||
const char *ptr;
|
||||
grub_err_t err;
|
||||
|
||||
ptr = name + sizeof ("pxe:") - 1;
|
||||
err = parse_ip (ptr, &(data->server_ip), &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
if (*ptr == ':')
|
||||
{
|
||||
err = parse_ip (ptr + 1, &(data->gateway_ip), 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
else
|
||||
data->gateway_ip = grub_pxe_default_gateway_ip;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->server_ip = grub_pxe_default_server_ip;
|
||||
data->gateway_ip = grub_pxe_default_gateway_ip;
|
||||
}
|
||||
|
||||
disk->total_sectors = 0;
|
||||
disk->id = (unsigned long) data;
|
||||
|
||||
disk->data = data;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_pxe_close (grub_disk_t disk)
|
||||
{
|
||||
grub_free (disk->data);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxe_read (grub_disk_t disk __attribute((unused)),
|
||||
grub_disk_addr_t sector __attribute((unused)),
|
||||
grub_size_t size __attribute((unused)),
|
||||
char *buf __attribute((unused)))
|
||||
{
|
||||
return GRUB_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxe_write (grub_disk_t disk __attribute((unused)),
|
||||
grub_disk_addr_t sector __attribute((unused)),
|
||||
grub_size_t size __attribute((unused)),
|
||||
const char *buf __attribute((unused)))
|
||||
{
|
||||
return GRUB_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_pxe_dev =
|
||||
{
|
||||
.name = "pxe",
|
||||
.id = GRUB_DISK_DEVICE_PXE_ID,
|
||||
.iterate = grub_pxe_iterate,
|
||||
.open = grub_pxe_open,
|
||||
.close = grub_pxe_close,
|
||||
.read = grub_pxe_read,
|
||||
.write = grub_pxe_write,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_dir (grub_device_t device,
|
||||
const char *path __attribute__ ((unused)),
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info)
|
||||
__attribute__ ((unused)))
|
||||
{
|
||||
if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
|
||||
return grub_error (GRUB_ERR_IO, "not a pxe disk");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_open (struct grub_file *file, const char *name)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct grub_pxenv_tftp_get_fsize c1;
|
||||
struct grub_pxenv_tftp_open c2;
|
||||
} c;
|
||||
struct grub_pxe_data *data;
|
||||
struct grub_pxe_disk_data *disk_data = file->device->disk->data;
|
||||
grub_file_t file_int, bufio;
|
||||
|
||||
if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
|
||||
return grub_error (GRUB_ERR_IO, "not a pxe disk");
|
||||
|
||||
if (curr_file != 0)
|
||||
{
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2, pxe_rm_entry);
|
||||
curr_file = 0;
|
||||
}
|
||||
|
||||
c.c1.server_ip = disk_data->server_ip;
|
||||
c.c1.gateway_ip = disk_data->gateway_ip;
|
||||
grub_strcpy ((char *)&c.c1.filename[0], name);
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry);
|
||||
if (c.c1.status)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
|
||||
file->size = c.c1.file_size;
|
||||
|
||||
c.c2.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
|
||||
c.c2.packet_size = grub_pxe_blksize;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry);
|
||||
if (c.c2.status)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "open fails");
|
||||
|
||||
data = grub_zalloc (sizeof (struct grub_pxe_data) + grub_strlen (name) + 1);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
data->block_size = c.c2.packet_size;
|
||||
grub_strcpy (data->filename, name);
|
||||
|
||||
file_int = grub_malloc (sizeof (*file_int));
|
||||
if (! file_int)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
file->data = data;
|
||||
file->not_easly_seekable = 1;
|
||||
grub_memcpy (file_int, file, sizeof (struct grub_file));
|
||||
curr_file = file_int;
|
||||
|
||||
bufio = grub_bufio_open (file_int, data->block_size);
|
||||
if (! bufio)
|
||||
{
|
||||
grub_free (file_int);
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_memcpy (file, bufio, sizeof (struct grub_file));
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_pxenv_tftp_read c;
|
||||
struct grub_pxe_data *data;
|
||||
struct grub_pxe_disk_data *disk_data = file->device->disk->data;
|
||||
grub_uint32_t pn, r;
|
||||
|
||||
data = file->data;
|
||||
|
||||
pn = grub_divmod64 (file->offset, data->block_size, &r);
|
||||
if (r)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS,
|
||||
"read access must be aligned to packet size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((curr_file != file) || (data->packet_number > pn))
|
||||
{
|
||||
struct grub_pxenv_tftp_open o;
|
||||
|
||||
if (curr_file != 0)
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry);
|
||||
|
||||
o.server_ip = disk_data->server_ip;
|
||||
o.gateway_ip = disk_data->gateway_ip;
|
||||
grub_strcpy ((char *)&o.filename[0], data->filename);
|
||||
o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
|
||||
o.packet_size = data->block_size;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry);
|
||||
if (o.status)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "open fails");
|
||||
return -1;
|
||||
}
|
||||
data->block_size = o.packet_size;
|
||||
data->packet_number = 0;
|
||||
curr_file = file;
|
||||
}
|
||||
|
||||
c.buffer = SEGOFS (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
|
||||
while (pn >= data->packet_number)
|
||||
{
|
||||
c.buffer_size = data->block_size;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_READ, &c, pxe_rm_entry);
|
||||
if (c.status)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "read fails");
|
||||
return -1;
|
||||
}
|
||||
data->packet_number++;
|
||||
}
|
||||
|
||||
grub_memcpy (buf, (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_close (grub_file_t file)
|
||||
{
|
||||
struct grub_pxenv_tftp_close c;
|
||||
|
||||
if (curr_file == file)
|
||||
{
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c, pxe_rm_entry);
|
||||
curr_file = 0;
|
||||
}
|
||||
|
||||
grub_free (file->data);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_label (grub_device_t device __attribute ((unused)),
|
||||
char **label __attribute ((unused)))
|
||||
{
|
||||
*label = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_fs grub_pxefs_fs =
|
||||
{
|
||||
.name = "pxefs",
|
||||
.dir = grub_pxefs_dir,
|
||||
.open = grub_pxefs_open,
|
||||
.read = grub_pxefs_read,
|
||||
.close = grub_pxefs_close,
|
||||
.label = grub_pxefs_label,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
static char *
|
||||
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val __attribute__ ((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len)
|
||||
{
|
||||
char buf[(sizeof ("XX:") - 1) * mac_len + 1];
|
||||
char *ptr = buf;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < mac_len; i++)
|
||||
{
|
||||
grub_snprintf (ptr, sizeof (buf) - (ptr - buf),
|
||||
"%02x:", mac_addr[i] & 0xff);
|
||||
ptr += (sizeof ("XX:") - 1);
|
||||
}
|
||||
if (mac_len)
|
||||
*(ptr - 1) = 0;
|
||||
else
|
||||
buf[0] = 0;
|
||||
|
||||
grub_env_set ("net_pxe_mac", buf);
|
||||
/* XXX: Is it possible to change MAC in PXE? */
|
||||
grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly);
|
||||
}
|
||||
|
||||
static void
|
||||
set_env_limn_ro (const char *varname, char *value, grub_size_t len)
|
||||
{
|
||||
char c;
|
||||
c = value[len];
|
||||
value[len] = 0;
|
||||
grub_env_set (varname, value);
|
||||
value[len] = c;
|
||||
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_dhcp_vendor (void *vend, int limit)
|
||||
{
|
||||
grub_uint8_t *ptr, *ptr0;
|
||||
|
||||
ptr = ptr0 = vend;
|
||||
|
||||
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363)
|
||||
return;
|
||||
ptr = ptr + sizeof (grub_uint32_t);
|
||||
while (ptr - ptr0 < limit)
|
||||
{
|
||||
grub_uint8_t tagtype;
|
||||
grub_uint8_t taglength;
|
||||
|
||||
tagtype = *ptr++;
|
||||
|
||||
/* Pad tag. */
|
||||
if (tagtype == 0)
|
||||
continue;
|
||||
|
||||
/* End tag. */
|
||||
if (tagtype == 0xff)
|
||||
return;
|
||||
|
||||
taglength = *ptr++;
|
||||
|
||||
switch (tagtype)
|
||||
{
|
||||
case 12:
|
||||
set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 17:
|
||||
set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
/* If you need any other options please contact GRUB
|
||||
developpement team. */
|
||||
}
|
||||
|
||||
ptr += taglength;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_pxe_detect (void)
|
||||
{
|
||||
struct grub_pxe_bangpxe *pxenv;
|
||||
struct grub_pxenv_get_cached_info ci;
|
||||
struct grub_pxenv_boot_player *bp;
|
||||
|
||||
pxenv = grub_pxe_scan ();
|
||||
if (! pxenv)
|
||||
return;
|
||||
|
||||
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
|
||||
ci.buffer = 0;
|
||||
ci.buffer_size = 0;
|
||||
grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
|
||||
if (ci.status)
|
||||
return;
|
||||
|
||||
bp = LINEAR (ci.buffer);
|
||||
|
||||
grub_pxe_your_ip = bp->your_ip;
|
||||
grub_pxe_default_server_ip = bp->server_ip;
|
||||
grub_pxe_default_gateway_ip = bp->gateway_ip;
|
||||
set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len
|
||||
: sizeof (bp->mac_addr));
|
||||
set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file,
|
||||
sizeof (bp->boot_file));
|
||||
set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name,
|
||||
sizeof (bp->server_name));
|
||||
parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor));
|
||||
grub_pxe_pxenv = pxenv;
|
||||
}
|
||||
|
||||
void
|
||||
grub_pxe_unload (void)
|
||||
{
|
||||
if (grub_pxe_pxenv)
|
||||
{
|
||||
grub_fs_unregister (&grub_pxefs_fs);
|
||||
grub_disk_dev_unregister (&grub_pxe_dev);
|
||||
|
||||
grub_pxe_pxenv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_ip_env (char *varname, grub_uint32_t ip)
|
||||
{
|
||||
char buf[sizeof ("XXX.XXX.XXX.XXX")];
|
||||
|
||||
grub_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff),
|
||||
(ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
|
||||
grub_env_set (varname, buf);
|
||||
}
|
||||
|
||||
static char *
|
||||
write_ip_env (grub_uint32_t *ip, const char *val)
|
||||
{
|
||||
char *buf;
|
||||
grub_err_t err;
|
||||
grub_uint32_t newip;
|
||||
|
||||
err = parse_ip (val, &newip, 0);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
/* Normalize the IP. */
|
||||
buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff,
|
||||
(newip >> 16) & 0xff, (newip >> 24) & 0xff);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
*ip = newip;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_env_write_pxe_default_server (struct grub_env_var *var
|
||||
__attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
return write_ip_env (&grub_pxe_default_server_ip, val);
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_env_write_pxe_default_gateway (struct grub_env_var *var
|
||||
__attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
return write_ip_env (&grub_pxe_default_gateway_ip, val);
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
unsigned size;
|
||||
char *buf;
|
||||
|
||||
size = grub_strtoul (val, 0, 0);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
||||
if (size < GRUB_PXE_MIN_BLKSIZE)
|
||||
size = GRUB_PXE_MIN_BLKSIZE;
|
||||
else if (size > GRUB_PXE_MAX_BLKSIZE)
|
||||
size = GRUB_PXE_MAX_BLKSIZE;
|
||||
|
||||
buf = grub_xasprintf ("%d", size);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
grub_pxe_blksize = size;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
GRUB_MOD_INIT(pxe)
|
||||
{
|
||||
grub_pxe_detect ();
|
||||
if (grub_pxe_pxenv)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = grub_xasprintf ("%d", grub_pxe_blksize);
|
||||
if (buf)
|
||||
grub_env_set ("pxe_blksize", buf);
|
||||
grub_free (buf);
|
||||
|
||||
set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
|
||||
set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip);
|
||||
set_ip_env ("net_pxe_ip", grub_pxe_your_ip);
|
||||
grub_register_variable_hook ("pxe_default_server", 0,
|
||||
grub_env_write_pxe_default_server);
|
||||
grub_register_variable_hook ("pxe_default_gateway", 0,
|
||||
grub_env_write_pxe_default_gateway);
|
||||
|
||||
/* XXX: Is it possible to change IP in PXE? */
|
||||
grub_register_variable_hook ("net_pxe_ip", 0,
|
||||
grub_env_write_readonly);
|
||||
grub_register_variable_hook ("pxe_blksize", 0,
|
||||
grub_env_write_pxe_blocksize);
|
||||
grub_disk_dev_register (&grub_pxe_dev);
|
||||
grub_fs_register (&grub_pxefs_fs);
|
||||
}
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(pxe)
|
||||
{
|
||||
grub_pxe_unload ();
|
||||
}
|
|
@ -27,6 +27,9 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
#include <grub/charset.h>
|
||||
#include <grub/datetime.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_ISO9660_FSTYPE_DIR 0040000
|
||||
#define GRUB_ISO9660_FSTYPE_REG 0100000
|
||||
|
@ -53,6 +56,17 @@ struct grub_iso9660_voldesc
|
|||
grub_uint8_t version;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_iso9660_date2
|
||||
{
|
||||
grub_uint8_t year;
|
||||
grub_uint8_t month;
|
||||
grub_uint8_t day;
|
||||
grub_uint8_t hour;
|
||||
grub_uint8_t minute;
|
||||
grub_uint8_t second;
|
||||
grub_uint8_t offset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* A directory entry. */
|
||||
struct grub_iso9660_dir
|
||||
{
|
||||
|
@ -62,7 +76,7 @@ struct grub_iso9660_dir
|
|||
grub_uint32_t first_sector_be;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t size_be;
|
||||
grub_uint8_t unused1[7];
|
||||
struct grub_iso9660_date2 mtime;
|
||||
grub_uint8_t flags;
|
||||
grub_uint8_t unused2[6];
|
||||
grub_uint8_t namelen;
|
||||
|
@ -135,53 +149,148 @@ struct grub_iso9660_data
|
|||
{
|
||||
struct grub_iso9660_primary_voldesc voldesc;
|
||||
grub_disk_t disk;
|
||||
unsigned int first_sector;
|
||||
int rockridge;
|
||||
int susp_skip;
|
||||
int joliet;
|
||||
struct grub_fshelp_node *node;
|
||||
};
|
||||
|
||||
struct grub_fshelp_node
|
||||
{
|
||||
struct grub_iso9660_data *data;
|
||||
unsigned int size;
|
||||
unsigned int blk;
|
||||
unsigned int dir_blk;
|
||||
unsigned int dir_off;
|
||||
grub_size_t have_dirents, alloc_dirents;
|
||||
char *symlink;
|
||||
struct grub_iso9660_dir dirents[8];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_TYPE_PLAIN = 0,
|
||||
FLAG_TYPE_DIR = 2,
|
||||
FLAG_TYPE = 3,
|
||||
FLAG_MORE_EXTENTS = 0x80
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
|
||||
static grub_err_t
|
||||
iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix)
|
||||
{
|
||||
struct grub_datetime datetime;
|
||||
|
||||
if (! i->year[0] && ! i->year[1]
|
||||
&& ! i->year[2] && ! i->year[3]
|
||||
&& ! i->month[0] && ! i->month[1]
|
||||
&& ! i->day[0] && ! i->day[1]
|
||||
&& ! i->hour[0] && ! i->hour[1]
|
||||
&& ! i->minute[0] && ! i->minute[1]
|
||||
&& ! i->second[0] && ! i->second[1]
|
||||
&& ! i->hundredth[0] && ! i->hundredth[1])
|
||||
return grub_error (GRUB_ERR_BAD_NUMBER, "empty date");
|
||||
datetime.year = (i->year[0] - '0') * 1000 + (i->year[1] - '0') * 100
|
||||
+ (i->year[2] - '0') * 10 + (i->year[3] - '0');
|
||||
datetime.month = (i->month[0] - '0') * 10 + (i->month[1] - '0');
|
||||
datetime.day = (i->day[0] - '0') * 10 + (i->day[1] - '0');
|
||||
datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0');
|
||||
datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0');
|
||||
datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0');
|
||||
|
||||
if (!grub_datetime2unixtime (&datetime, nix))
|
||||
return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date");
|
||||
*nix -= i->offset * 60 * 15;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix)
|
||||
{
|
||||
struct grub_datetime datetime;
|
||||
|
||||
datetime.year = i->year + 1900;
|
||||
datetime.month = i->month;
|
||||
datetime.day = i->day;
|
||||
datetime.hour = i->hour;
|
||||
datetime.minute = i->minute;
|
||||
datetime.second = i->second;
|
||||
|
||||
if (!grub_datetime2unixtime (&datetime, nix))
|
||||
return 0;
|
||||
*nix -= i->offset * 60 * 15;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf)
|
||||
{
|
||||
grub_size_t i = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
grub_size_t toread;
|
||||
grub_err_t err;
|
||||
while (i < node->have_dirents
|
||||
&& off >= grub_le_to_cpu32 (node->dirents[i].size))
|
||||
{
|
||||
off -= grub_le_to_cpu32 (node->dirents[i].size);
|
||||
i++;
|
||||
}
|
||||
if (i == node->have_dirents)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range");
|
||||
toread = grub_le_to_cpu32 (node->dirents[i].size);
|
||||
if (toread > len)
|
||||
toread = len;
|
||||
err = grub_disk_read (node->data->disk,
|
||||
((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ,
|
||||
off, toread, buf);
|
||||
if (err)
|
||||
return err;
|
||||
len -= toread;
|
||||
off += toread;
|
||||
buf += toread;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Iterate over the susp entries, starting with block SUA_BLOCK on the
|
||||
offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for
|
||||
every entry. */
|
||||
static grub_err_t
|
||||
grub_iso9660_susp_iterate (struct grub_iso9660_data *data,
|
||||
int sua_block, int sua_pos, int sua_size,
|
||||
grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
|
||||
grub_ssize_t sua_size,
|
||||
grub_err_t (*hook)
|
||||
(struct grub_iso9660_susp_entry *entry))
|
||||
{
|
||||
char *sua;
|
||||
struct grub_iso9660_susp_entry *entry;
|
||||
grub_disk_addr_t ce_block;
|
||||
int is_ce = 0;
|
||||
|
||||
auto grub_err_t load_sua (void);
|
||||
|
||||
/* Load a part of the System Usage Area. */
|
||||
grub_err_t load_sua (void)
|
||||
{
|
||||
grub_err_t err;
|
||||
sua = grub_malloc (sua_size);
|
||||
if (!sua)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_disk_read (data->disk, sua_block, sua_pos,
|
||||
sua_size, sua))
|
||||
return grub_errno;
|
||||
if (is_ce)
|
||||
err = grub_disk_read (node->data->disk, ce_block, off,
|
||||
sua_size, sua);
|
||||
else
|
||||
err = read_node (node, off, sua_size, sua);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
entry = (struct grub_iso9660_susp_entry *) sua;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sua_size <= 0)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
if (load_sua ())
|
||||
return grub_errno;
|
||||
|
||||
|
@ -198,10 +307,11 @@ grub_iso9660_susp_iterate (struct grub_iso9660_data *data,
|
|||
{
|
||||
struct grub_iso9660_susp_ce *ce;
|
||||
|
||||
is_ce = 1;
|
||||
ce = (struct grub_iso9660_susp_ce *) entry;
|
||||
sua_size = grub_le_to_cpu32 (ce->len);
|
||||
sua_pos = grub_le_to_cpu32 (ce->off);
|
||||
sua_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
|
||||
off = grub_le_to_cpu32 (ce->off);
|
||||
ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
|
||||
|
||||
grub_free (sua);
|
||||
if (load_sua ())
|
||||
|
@ -322,6 +432,9 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
+ (rootdir.namelen % 2) - 1);
|
||||
sua_size = rootdir.len - sua_pos;
|
||||
|
||||
if (!sua_size)
|
||||
return data;
|
||||
|
||||
sua = grub_malloc (sua_size);
|
||||
if (! sua)
|
||||
goto fail;
|
||||
|
@ -339,6 +452,14 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
/* Test if the SUSP protocol is used on this filesystem. */
|
||||
if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
|
||||
{
|
||||
struct grub_fshelp_node rootnode;
|
||||
|
||||
rootnode.data = data;
|
||||
rootnode.alloc_dirents = 0;
|
||||
rootnode.have_dirents = 1;
|
||||
rootnode.symlink = 0;
|
||||
rootnode.dirents[0] = data->voldesc.rootdir;
|
||||
|
||||
/* The 2nd data byte stored how many bytes are skipped every time
|
||||
to get to the SUA (System Usage Area). */
|
||||
data->susp_skip = entry->data[2];
|
||||
|
@ -346,9 +467,7 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
|
||||
/* Iterate over the entries in the SUA area to detect
|
||||
extensions. */
|
||||
if (grub_iso9660_susp_iterate (data,
|
||||
(grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
|
||||
<< GRUB_ISO9660_LOG2_BLKSZ),
|
||||
if (grub_iso9660_susp_iterate (&rootnode,
|
||||
sua_pos, sua_size, susp_iterate))
|
||||
goto fail;
|
||||
}
|
||||
|
@ -364,109 +483,19 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
static char *
|
||||
grub_iso9660_read_symlink (grub_fshelp_node_t node)
|
||||
{
|
||||
struct grub_iso9660_dir dirent;
|
||||
int sua_off;
|
||||
int sua_size;
|
||||
char *symlink = 0;
|
||||
int addslash = 0;
|
||||
|
||||
auto void add_part (const char *part, int len);
|
||||
auto grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *);
|
||||
|
||||
/* Extend the symlink. */
|
||||
void add_part (const char *part, int len)
|
||||
{
|
||||
int size = grub_strlen (symlink);
|
||||
|
||||
symlink = grub_realloc (symlink, size + len + 1);
|
||||
if (! symlink)
|
||||
return;
|
||||
|
||||
grub_strncat (symlink, part, len);
|
||||
}
|
||||
|
||||
/* Read in a symlink. */
|
||||
grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *entry)
|
||||
{
|
||||
if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
|
||||
{
|
||||
unsigned int pos = 1;
|
||||
|
||||
/* The symlink is not stored as a POSIX symlink, translate it. */
|
||||
while (pos < grub_le_to_cpu32 (entry->len))
|
||||
{
|
||||
if (addslash)
|
||||
{
|
||||
add_part ("/", 1);
|
||||
addslash = 0;
|
||||
}
|
||||
|
||||
/* The current position is the `Component Flag'. */
|
||||
switch (entry->data[pos] & 30)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/* The data on pos + 2 is the actual data, pos + 1
|
||||
is the length. Both are part of the `Component
|
||||
Record'. */
|
||||
add_part ((char *) &entry->data[pos + 2],
|
||||
entry->data[pos + 1]);
|
||||
if ((entry->data[pos] & 1))
|
||||
addslash = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
add_part ("./", 2);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
add_part ("../", 3);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
add_part ("/", 1);
|
||||
break;
|
||||
}
|
||||
/* In pos + 1 the length of the `Component Record' is
|
||||
stored. */
|
||||
pos += entry->data[pos + 1] + 2;
|
||||
}
|
||||
|
||||
/* Check if `grub_realloc' failed. */
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grub_disk_read (node->data->disk, node->dir_blk, node->dir_off,
|
||||
sizeof (dirent), (char *) &dirent))
|
||||
return 0;
|
||||
|
||||
sua_off = (sizeof (dirent) + dirent.namelen + 1 - (dirent.namelen % 2)
|
||||
+ node->data->susp_skip);
|
||||
sua_size = dirent.len - sua_off;
|
||||
|
||||
symlink = grub_malloc (1);
|
||||
if (!symlink)
|
||||
return 0;
|
||||
|
||||
*symlink = '\0';
|
||||
|
||||
if (grub_iso9660_susp_iterate (node->data, node->dir_blk,
|
||||
node->dir_off + sua_off,
|
||||
sua_size, susp_iterate_sl))
|
||||
{
|
||||
grub_free (symlink);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return symlink;
|
||||
return node->symlink ? grub_strdup (node->symlink) : grub_strdup ("");
|
||||
}
|
||||
|
||||
static grub_off_t
|
||||
get_node_size (grub_fshelp_node_t node)
|
||||
{
|
||||
grub_off_t ret = 0;
|
||||
grub_size_t i;
|
||||
|
||||
for (i = 0; i < node->have_dirents; i++)
|
||||
ret += grub_le_to_cpu32 (node->dirents[i].size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
||||
|
@ -476,10 +505,28 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
grub_fshelp_node_t node))
|
||||
{
|
||||
struct grub_iso9660_dir dirent;
|
||||
unsigned int offset = 0;
|
||||
grub_off_t offset = 0;
|
||||
char *filename;
|
||||
int filename_alloc = 0;
|
||||
enum grub_fshelp_filetype type;
|
||||
grub_off_t len;
|
||||
char *symlink = 0;
|
||||
int addslash = 0;
|
||||
|
||||
auto void add_part (const char *part, int len);
|
||||
|
||||
/* Extend the symlink. */
|
||||
void add_part (const char *part, int len2)
|
||||
{
|
||||
int size = symlink ? grub_strlen (symlink) : 0;
|
||||
|
||||
symlink = grub_realloc (symlink, size + len2 + 1);
|
||||
if (! symlink)
|
||||
return;
|
||||
|
||||
symlink[size] = 0;
|
||||
grub_strncat (symlink, part, len2);
|
||||
}
|
||||
|
||||
auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *);
|
||||
|
||||
|
@ -537,17 +584,68 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
type = GRUB_FSHELP_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
|
||||
{
|
||||
unsigned int pos = 1;
|
||||
|
||||
/* The symlink is not stored as a POSIX symlink, translate it. */
|
||||
while (pos + sizeof (*entry) < grub_le_to_cpu32 (entry->len))
|
||||
{
|
||||
if (addslash)
|
||||
{
|
||||
add_part ("/", 1);
|
||||
addslash = 0;
|
||||
}
|
||||
|
||||
/* The current position is the `Component Flag'. */
|
||||
switch (entry->data[pos] & 30)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/* The data on pos + 2 is the actual data, pos + 1
|
||||
is the length. Both are part of the `Component
|
||||
Record'. */
|
||||
add_part ((char *) &entry->data[pos + 2],
|
||||
entry->data[pos + 1]);
|
||||
if ((entry->data[pos] & 1))
|
||||
addslash = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
add_part ("./", 2);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
add_part ("../", 3);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
add_part ("/", 1);
|
||||
break;
|
||||
}
|
||||
/* In pos + 1 the length of the `Component Record' is
|
||||
stored. */
|
||||
pos += entry->data[pos + 1] + 2;
|
||||
}
|
||||
|
||||
/* Check if `grub_realloc' failed. */
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (offset < dir->size)
|
||||
len = get_node_size (dir);
|
||||
|
||||
for (; offset < len; offset += dirent.len)
|
||||
{
|
||||
if (grub_disk_read (dir->data->disk,
|
||||
(dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ offset / GRUB_DISK_SECTOR_SIZE,
|
||||
offset % GRUB_DISK_SECTOR_SIZE,
|
||||
sizeof (dirent), (char *) &dirent))
|
||||
symlink = 0;
|
||||
addslash = 0;
|
||||
|
||||
if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
|
||||
return 0;
|
||||
|
||||
/* The end of the block, skip to the next one. */
|
||||
|
@ -572,39 +670,30 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
type = GRUB_FSHELP_UNKNOWN;
|
||||
|
||||
if (dir->data->rockridge
|
||||
&& grub_iso9660_susp_iterate (dir->data,
|
||||
(dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ (sua_off
|
||||
/ GRUB_DISK_SECTOR_SIZE),
|
||||
sua_off % GRUB_DISK_SECTOR_SIZE,
|
||||
sua_size, susp_iterate_dir))
|
||||
&& grub_iso9660_susp_iterate (dir, sua_off, sua_size,
|
||||
susp_iterate_dir))
|
||||
return 0;
|
||||
|
||||
/* Read the name. */
|
||||
if (grub_disk_read (dir->data->disk,
|
||||
(dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ nameoffset / GRUB_DISK_SECTOR_SIZE,
|
||||
nameoffset % GRUB_DISK_SECTOR_SIZE,
|
||||
dirent.namelen, (char *) name))
|
||||
if (read_node (dir, nameoffset, dirent.namelen, (char *) name))
|
||||
return 0;
|
||||
|
||||
node = grub_malloc (sizeof (struct grub_fshelp_node));
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
node->alloc_dirents = ARRAY_SIZE (node->dirents);
|
||||
node->have_dirents = 1;
|
||||
|
||||
/* Setup a new node. */
|
||||
node->data = dir->data;
|
||||
node->size = grub_le_to_cpu32 (dirent.size);
|
||||
node->blk = grub_le_to_cpu32 (dirent.first_sector);
|
||||
node->dir_blk = ((dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ offset / GRUB_DISK_SECTOR_SIZE);
|
||||
node->dir_off = offset % GRUB_DISK_SECTOR_SIZE;
|
||||
node->symlink = symlink;
|
||||
|
||||
/* If the filetype was not stored using rockridge, use
|
||||
whatever is stored in the iso9660 filesystem. */
|
||||
if (type == GRUB_FSHELP_UNKNOWN)
|
||||
{
|
||||
if ((dirent.flags & 3) == 2)
|
||||
if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
|
||||
type = GRUB_FSHELP_DIR;
|
||||
else
|
||||
type = GRUB_FSHELP_REG;
|
||||
|
@ -619,10 +708,12 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (filename)
|
||||
*filename = '\0';
|
||||
|
||||
if (dirent.namelen == 1 && name[0] == 0)
|
||||
filename = ".";
|
||||
else if (dirent.namelen == 1 && name[0] == 1)
|
||||
filename = "..";
|
||||
/* . and .. */
|
||||
if (dirent.namelen == 1 && (name[0] == 0 || name[0] == 1))
|
||||
{
|
||||
grub_free (node);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
filename = name;
|
||||
}
|
||||
|
@ -645,6 +736,35 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
filename_alloc = 1;
|
||||
}
|
||||
|
||||
node->dirents[0] = dirent;
|
||||
while (dirent.flags & FLAG_MORE_EXTENTS)
|
||||
{
|
||||
offset += dirent.len;
|
||||
if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
|
||||
{
|
||||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
grub_free (node);
|
||||
return 0;
|
||||
}
|
||||
if (node->have_dirents >= node->alloc_dirents)
|
||||
{
|
||||
struct grub_fshelp_node *new_node;
|
||||
node->alloc_dirents *= 2;
|
||||
new_node = grub_malloc (sizeof (struct grub_fshelp_node)
|
||||
+ ((node->alloc_dirents
|
||||
- ARRAY_SIZE (node->dirents))
|
||||
* sizeof (node->dirents[0])));
|
||||
if (!new_node)
|
||||
{
|
||||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
grub_free (node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
node->dirents[node->have_dirents++] = dirent;
|
||||
}
|
||||
if (hook (filename, type, node))
|
||||
{
|
||||
if (filename_alloc)
|
||||
|
@ -654,8 +774,6 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
}
|
||||
|
||||
offset += dirent.len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -683,6 +801,8 @@ grub_iso9660_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
|
||||
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
@ -694,8 +814,10 @@ grub_iso9660_dir (grub_device_t device, const char *path,
|
|||
goto fail;
|
||||
|
||||
rootnode.data = data;
|
||||
rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector);
|
||||
rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size);
|
||||
rootnode.alloc_dirents = 0;
|
||||
rootnode.have_dirents = 1;
|
||||
rootnode.symlink = 0;
|
||||
rootnode.dirents[0] = data->voldesc.rootdir;
|
||||
|
||||
/* Use the fshelp function to traverse the path. */
|
||||
if (grub_fshelp_find_file (path, &rootnode,
|
||||
|
@ -735,8 +857,10 @@ grub_iso9660_open (struct grub_file *file, const char *name)
|
|||
goto fail;
|
||||
|
||||
rootnode.data = data;
|
||||
rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector);
|
||||
rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size);
|
||||
rootnode.alloc_dirents = 0;
|
||||
rootnode.have_dirents = 1;
|
||||
rootnode.symlink = 0;
|
||||
rootnode.dirents[0] = data->voldesc.rootdir;
|
||||
|
||||
/* Use the fshelp function to traverse the path. */
|
||||
if (grub_fshelp_find_file (name, &rootnode,
|
||||
|
@ -746,10 +870,9 @@ grub_iso9660_open (struct grub_file *file, const char *name)
|
|||
GRUB_FSHELP_REG))
|
||||
goto fail;
|
||||
|
||||
data->first_sector = foundnode->blk;
|
||||
|
||||
data->node = foundnode;
|
||||
file->data = data;
|
||||
file->size = foundnode->size;
|
||||
file->size = get_node_size (foundnode);
|
||||
file->offset = 0;
|
||||
|
||||
return 0;
|
||||
|
@ -771,10 +894,7 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
|
||||
/* XXX: The file is stored in as a single extent. */
|
||||
data->disk->read_hook = file->read_hook;
|
||||
grub_disk_read (data->disk,
|
||||
data->first_sector << GRUB_ISO9660_LOG2_BLKSZ,
|
||||
file->offset,
|
||||
len, buf);
|
||||
read_node (data->node, file->offset, len, buf);
|
||||
data->disk->read_hook = NULL;
|
||||
|
||||
if (grub_errno)
|
||||
|
@ -787,7 +907,10 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
static grub_err_t
|
||||
grub_iso9660_close (grub_file_t file)
|
||||
{
|
||||
grub_free (file->data);
|
||||
struct grub_iso9660_data *data =
|
||||
(struct grub_iso9660_data *) file->data;
|
||||
grub_free (data->node);
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -808,6 +931,15 @@ grub_iso9660_label (grub_device_t device, char **label)
|
|||
((grub_uint16_t *) &data->voldesc.volname, 16);
|
||||
else
|
||||
*label = grub_strndup ((char *) data->voldesc.volname, 32);
|
||||
if (*label)
|
||||
{
|
||||
char *ptr;
|
||||
for (ptr = *label; *ptr;ptr++);
|
||||
ptr--;
|
||||
while (ptr >= *label && *ptr == ' ')
|
||||
*ptr-- = 0;
|
||||
}
|
||||
|
||||
grub_free (data);
|
||||
}
|
||||
else
|
||||
|
@ -871,6 +1003,32 @@ grub_iso9660_uuid (grub_device_t device, char **uuid)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Get writing time of filesystem. */
|
||||
static grub_err_t
|
||||
grub_iso9660_mtime (grub_device_t device, grub_int32_t *timebuf)
|
||||
{
|
||||
struct grub_iso9660_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
grub_err_t err;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
data = grub_iso9660_mount (disk);
|
||||
if (!data)
|
||||
{
|
||||
grub_dl_unref (my_mod);
|
||||
return grub_errno;
|
||||
}
|
||||
err = iso9660_to_unixtime (&data->voldesc.modified, timebuf);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
grub_free (data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static struct grub_fs grub_iso9660_fs =
|
||||
|
@ -882,6 +1040,7 @@ static struct grub_fs grub_iso9660_fs =
|
|||
.close = grub_iso9660_close,
|
||||
.label = grub_iso9660_label,
|
||||
.uuid = grub_iso9660_uuid,
|
||||
.mtime = grub_iso9660_mtime,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_JFS_MAX_SYMLNK_CNT 8
|
||||
#define GRUB_JFS_FILETYPE_MASK 0170000
|
||||
#define GRUB_JFS_FILETYPE_REG 0100000
|
||||
|
@ -50,9 +52,9 @@ struct grub_jfs_sblock
|
|||
grub_uint32_t blksz;
|
||||
grub_uint16_t log2_blksz;
|
||||
|
||||
grub_uint8_t unused[71];
|
||||
grub_uint8_t unused[79];
|
||||
grub_uint8_t volname[11];
|
||||
grub_uint8_t unused2[32];
|
||||
grub_uint8_t unused2[24];
|
||||
grub_uint8_t uuid[16];
|
||||
};
|
||||
|
||||
|
@ -153,6 +155,12 @@ struct grub_jfs_leaf_next_dirent
|
|||
grub_uint16_t namepart[15];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_jfs_time
|
||||
{
|
||||
grub_int32_t sec;
|
||||
grub_int32_t nanosec;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_jfs_inode
|
||||
{
|
||||
grub_uint32_t stamp;
|
||||
|
@ -162,7 +170,10 @@ struct grub_jfs_inode
|
|||
grub_uint64_t size;
|
||||
grub_uint8_t unused2[20];
|
||||
grub_uint32_t mode;
|
||||
grub_uint8_t unused3[72];
|
||||
struct grub_jfs_time atime;
|
||||
struct grub_jfs_time ctime;
|
||||
struct grub_jfs_time mtime;
|
||||
grub_uint8_t unused3[48];
|
||||
grub_uint8_t unused4[96];
|
||||
|
||||
union
|
||||
|
@ -217,12 +228,12 @@ struct grub_jfs_diropen
|
|||
struct grub_jfs_tree_dir header;
|
||||
struct grub_jfs_leaf_dirent dirent[0];
|
||||
struct grub_jfs_leaf_next_dirent next_dirent[0];
|
||||
char sorted[0];
|
||||
grub_uint8_t sorted[0];
|
||||
} *dirpage __attribute__ ((packed));
|
||||
struct grub_jfs_data *data;
|
||||
struct grub_jfs_inode *inode;
|
||||
int count;
|
||||
char *sorted;
|
||||
grub_uint8_t *sorted;
|
||||
struct grub_jfs_leaf_dirent *leaf;
|
||||
struct grub_jfs_leaf_next_dirent *next_leaf;
|
||||
|
||||
|
@ -234,19 +245,19 @@ struct grub_jfs_diropen
|
|||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino);
|
||||
static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino);
|
||||
|
||||
/* Get the block number for the block BLK in the node INODE in the
|
||||
mounted filesystem DATA. */
|
||||
static int
|
||||
static grub_int64_t
|
||||
grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
||||
unsigned int blk)
|
||||
grub_uint64_t blk)
|
||||
{
|
||||
auto int getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents);
|
||||
auto grub_int64_t getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents);
|
||||
|
||||
int getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents)
|
||||
grub_int64_t getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents)
|
||||
{
|
||||
int found = -1;
|
||||
int i;
|
||||
|
@ -258,7 +269,7 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
|||
/* Read the leafnode. */
|
||||
if (grub_le_to_cpu32 (extents[i].offset2) <= blk
|
||||
&& ((grub_le_to_cpu16 (extents[i].extent.length))
|
||||
+ (extents[i].extent.length2 << 8)
|
||||
+ (extents[i].extent.length2 << 16)
|
||||
+ grub_le_to_cpu32 (extents[i].offset2)) > blk)
|
||||
return (blk - grub_le_to_cpu32 (extents[i].offset2)
|
||||
+ grub_le_to_cpu32 (extents[i].extent.blk2));
|
||||
|
@ -277,7 +288,7 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
|||
} tree;
|
||||
|
||||
if (grub_disk_read (data->disk,
|
||||
grub_le_to_cpu32 (extents[found].extent.blk2)
|
||||
((grub_disk_addr_t) grub_le_to_cpu32 (extents[found].extent.blk2))
|
||||
<< (grub_le_to_cpu16 (data->sblock.log2_blksz)
|
||||
- GRUB_DISK_SECTOR_BITS), 0,
|
||||
sizeof (tree), (char *) &tree))
|
||||
|
@ -294,15 +305,15 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
|||
|
||||
|
||||
static grub_err_t
|
||||
grub_jfs_read_inode (struct grub_jfs_data *data, int ino,
|
||||
grub_jfs_read_inode (struct grub_jfs_data *data, grub_uint32_t ino,
|
||||
struct grub_jfs_inode *inode)
|
||||
{
|
||||
struct grub_jfs_iag iag;
|
||||
int iagnum = ino / 4096;
|
||||
int inoext = (ino % 4096) / 32;
|
||||
int inonum = (ino % 4096) % 32;
|
||||
grub_uint32_t iagblk;
|
||||
grub_uint32_t inoblk;
|
||||
grub_uint32_t iagnum = ino / 4096;
|
||||
unsigned inoext = (ino % 4096) / 32;
|
||||
unsigned inonum = (ino % 4096) % 32;
|
||||
grub_uint64_t iagblk;
|
||||
grub_uint64_t inoblk;
|
||||
|
||||
iagblk = grub_jfs_blkno (data, &data->fileset, iagnum + 1);
|
||||
if (grub_errno)
|
||||
|
@ -348,6 +359,13 @@ grub_jfs_mount (grub_disk_t disk)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (grub_le_to_cpu32 (data->sblock.blksz)
|
||||
!= (1U << grub_le_to_cpu16 (data->sblock.log2_blksz)))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a JFS filesystem");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data->disk = disk;
|
||||
data->pos = 0;
|
||||
data->linknest = 0;
|
||||
|
@ -374,7 +392,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode)
|
|||
{
|
||||
struct grub_jfs_internal_dirent *de;
|
||||
struct grub_jfs_diropen *diro;
|
||||
int blk;
|
||||
grub_disk_addr_t blk;
|
||||
|
||||
de = (struct grub_jfs_internal_dirent *) inode->dir.dirents;
|
||||
|
||||
|
@ -397,7 +415,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode)
|
|||
{
|
||||
diro->leaf = inode->dir.dirents;
|
||||
diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de;
|
||||
diro->sorted = (char *) (inode->dir.header.sorted);
|
||||
diro->sorted = inode->dir.header.sorted;
|
||||
diro->count = inode->dir.header.count;
|
||||
|
||||
return diro;
|
||||
|
@ -475,7 +493,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro)
|
|||
/* The last node, read in more. */
|
||||
if (diro->index == diro->count)
|
||||
{
|
||||
unsigned int next;
|
||||
grub_disk_addr_t next;
|
||||
|
||||
/* If the inode contains the entry tree or if this was the last
|
||||
node, there is nothing to read. */
|
||||
|
@ -499,7 +517,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro)
|
|||
diro->index = 0;
|
||||
}
|
||||
|
||||
leaf = &diro->leaf[(int) diro->sorted[diro->index]];
|
||||
leaf = &diro->leaf[diro->sorted[diro->index]];
|
||||
next_leaf = &diro->next_leaf[diro->index];
|
||||
|
||||
len = leaf->len;
|
||||
|
@ -540,21 +558,21 @@ static grub_ssize_t
|
|||
grub_jfs_read_file (struct grub_jfs_data *data,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
int i;
|
||||
int blockcnt;
|
||||
grub_off_t i;
|
||||
grub_off_t blockcnt;
|
||||
|
||||
blockcnt = ((len + pos + grub_le_to_cpu32 (data->sblock.blksz) - 1)
|
||||
/ grub_le_to_cpu32 (data->sblock.blksz));
|
||||
blockcnt = (len + pos + grub_le_to_cpu32 (data->sblock.blksz) - 1)
|
||||
>> grub_le_to_cpu16 (data->sblock.log2_blksz);
|
||||
|
||||
for (i = pos / grub_le_to_cpu32 (data->sblock.blksz); i < blockcnt; i++)
|
||||
for (i = pos >> grub_le_to_cpu16 (data->sblock.log2_blksz); i < blockcnt; i++)
|
||||
{
|
||||
int blknr;
|
||||
int blockoff = pos % grub_le_to_cpu32 (data->sblock.blksz);
|
||||
int blockend = grub_le_to_cpu32 (data->sblock.blksz);
|
||||
grub_disk_addr_t blknr;
|
||||
grub_uint32_t blockoff = pos & (grub_le_to_cpu32 (data->sblock.blksz) - 1);
|
||||
grub_uint32_t blockend = grub_le_to_cpu32 (data->sblock.blksz);
|
||||
|
||||
int skipfirst = 0;
|
||||
grub_uint64_t skipfirst = 0;
|
||||
|
||||
blknr = grub_jfs_blkno (data, &data->currinode, i);
|
||||
if (grub_errno)
|
||||
|
@ -563,14 +581,14 @@ grub_jfs_read_file (struct grub_jfs_data *data,
|
|||
/* Last block. */
|
||||
if (i == blockcnt - 1)
|
||||
{
|
||||
blockend = (len + pos) % grub_le_to_cpu32 (data->sblock.blksz);
|
||||
blockend = (len + pos) & (grub_le_to_cpu32 (data->sblock.blksz) - 1);
|
||||
|
||||
if (!blockend)
|
||||
blockend = grub_le_to_cpu32 (data->sblock.blksz);
|
||||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == (pos / (int) grub_le_to_cpu32 (data->sblock.blksz)))
|
||||
if (i == (pos >> grub_le_to_cpu16 (data->sblock.log2_blksz)))
|
||||
{
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
|
@ -596,7 +614,8 @@ grub_jfs_read_file (struct grub_jfs_data *data,
|
|||
/* Find the file with the pathname PATH on the filesystem described by
|
||||
DATA. */
|
||||
static grub_err_t
|
||||
grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
||||
grub_jfs_find_file (struct grub_jfs_data *data, const char *path,
|
||||
grub_uint32_t start_ino)
|
||||
{
|
||||
char fpath[grub_strlen (path)];
|
||||
char *name = fpath;
|
||||
|
@ -605,7 +624,7 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
|||
|
||||
grub_strncpy (fpath, path, grub_strlen (path) + 1);
|
||||
|
||||
if (grub_jfs_read_inode (data, GRUB_JFS_AGGR_INODE, &data->currinode))
|
||||
if (grub_jfs_read_inode (data, start_ino, &data->currinode))
|
||||
return grub_errno;
|
||||
|
||||
/* Skip the first slashes. */
|
||||
|
@ -642,8 +661,8 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
|||
pathname. */
|
||||
if (!grub_strcmp (name, diro->name))
|
||||
{
|
||||
int ino = diro->ino;
|
||||
int dirino = grub_le_to_cpu32 (data->currinode.inode);
|
||||
grub_uint32_t ino = diro->ino;
|
||||
grub_uint32_t dirino = grub_le_to_cpu32 (data->currinode.inode);
|
||||
|
||||
grub_jfs_closedir (diro);
|
||||
diro = 0;
|
||||
|
@ -681,15 +700,15 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
|||
}
|
||||
|
||||
grub_jfs_closedir (diro);
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino)
|
||||
grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino)
|
||||
{
|
||||
int size = grub_le_to_cpu64 (data->currinode.size);
|
||||
grub_uint64_t size = grub_le_to_cpu64 (data->currinode.size);
|
||||
char symlink[size + 1];
|
||||
|
||||
if (++data->linknest > GRUB_JFS_MAX_SYMLNK_CNT)
|
||||
|
@ -706,11 +725,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino)
|
|||
if (symlink[0] == '/')
|
||||
ino = 2;
|
||||
|
||||
/* Now load in the old inode. */
|
||||
if (grub_jfs_read_inode (data, ino, &data->currinode))
|
||||
return grub_errno;
|
||||
|
||||
grub_jfs_find_file (data, symlink);
|
||||
grub_jfs_find_file (data, symlink, ino);
|
||||
if (grub_errno)
|
||||
grub_error (grub_errno, "cannot follow symlink `%s'", symlink);
|
||||
|
||||
|
@ -732,7 +747,7 @@ grub_jfs_dir (grub_device_t device, const char *path,
|
|||
if (!data)
|
||||
goto fail;
|
||||
|
||||
if (grub_jfs_find_file (data, path))
|
||||
if (grub_jfs_find_file (data, path, GRUB_JFS_AGGR_INODE))
|
||||
goto fail;
|
||||
|
||||
diro = grub_jfs_opendir (data, &data->currinode);
|
||||
|
@ -751,6 +766,8 @@ grub_jfs_dir (grub_device_t device, const char *path,
|
|||
|
||||
info.dir = (grub_le_to_cpu32 (inode.mode)
|
||||
& GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_le_to_cpu32 (inode.mtime.sec);
|
||||
if (hook (diro->name, &info))
|
||||
goto fail;
|
||||
}
|
||||
|
@ -781,7 +798,7 @@ grub_jfs_open (struct grub_file *file, const char *name)
|
|||
if (!data)
|
||||
goto fail;
|
||||
|
||||
grub_jfs_find_file (data, name);
|
||||
grub_jfs_find_file (data, name, GRUB_JFS_AGGR_INODE);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -25,14 +25,19 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
#ifdef MODE_MINIX2
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#ifdef MODE_MINIX3
|
||||
#define GRUB_MINIX_MAGIC 0x4D5A
|
||||
#elif defined(MODE_MINIX2)
|
||||
#define GRUB_MINIX_MAGIC 0x2468
|
||||
#define GRUB_MINIX_MAGIC_30 0x2478
|
||||
#else
|
||||
#define GRUB_MINIX_MAGIC 0x137F
|
||||
#define GRUB_MINIX_MAGIC_30 0x138F
|
||||
#endif
|
||||
#define GRUB_MINIX_BSIZE 1024U
|
||||
|
||||
#define GRUB_MINIX_INODE_DIR_BLOCKS 7
|
||||
#define GRUB_MINIX_LOG2_BSIZE 1
|
||||
#define GRUB_MINIX_ROOT_INODE 1
|
||||
#define GRUB_MINIX_MAX_SYMLNK_CNT 8
|
||||
|
@ -41,7 +46,7 @@
|
|||
#define GRUB_MINIX_IFDIR 0040000U
|
||||
#define GRUB_MINIX_IFLNK 0120000U
|
||||
|
||||
#ifdef MODE_MINIX2
|
||||
#if defined(MODE_MINIX2) || defined(MODE_MINIX3)
|
||||
typedef grub_uint32_t grub_minix_uintn_t;
|
||||
#define grub_minix_le_to_cpu_n grub_le_to_cpu32
|
||||
#else
|
||||
|
@ -50,8 +55,15 @@ typedef grub_uint16_t grub_minix_uintn_t;
|
|||
#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_le_to_cpu_ino grub_le_to_cpu32
|
||||
#else
|
||||
typedef grub_uint16_t grub_minix_ino_t;
|
||||
#define grub_minix_le_to_cpu_ino grub_le_to_cpu16
|
||||
#endif
|
||||
|
||||
#define GRUB_MINIX_INODE_SIZE(data) (grub_minix_le_to_cpu_n (data->inode.size))
|
||||
#define GRUB_MINIX_INODE_SIZE(data) (grub_le_to_cpu32 (data->inode.size))
|
||||
#define GRUB_MINIX_INODE_MODE(data) (grub_le_to_cpu16 (data->inode.mode))
|
||||
#define GRUB_MINIX_INODE_DIR_ZONES(data,blk) (grub_minix_le_to_cpu_n \
|
||||
(data->inode.dir_zones[blk]))
|
||||
|
@ -60,11 +72,39 @@ typedef grub_uint16_t grub_minix_uintn_t;
|
|||
#define GRUB_MINIX_INODE_DINDIR_ZONE(data) (grub_minix_le_to_cpu_n \
|
||||
(data->inode.double_indir_zone))
|
||||
|
||||
#ifndef MODE_MINIX3
|
||||
#define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \
|
||||
+ grub_le_to_cpu16 (sblock->log2_zone_size))
|
||||
#define GRUB_MINIX_ZONESZ (GRUB_MINIX_BSIZE \
|
||||
<< grub_le_to_cpu16 (sblock->log2_zone_size))
|
||||
+ grub_le_to_cpu16 (data->sblock.log2_zone_size))
|
||||
#endif
|
||||
#define GRUB_MINIX_ZONESZ (data->block_size \
|
||||
<< grub_le_to_cpu16 (data->sblock.log2_zone_size))
|
||||
|
||||
#ifdef MODE_MINIX3
|
||||
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) * (data->block_size / GRUB_DISK_SECTOR_SIZE))
|
||||
#else
|
||||
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << GRUB_MINIX_LOG2_ZONESZ)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODE_MINIX3
|
||||
struct grub_minix_sblock
|
||||
{
|
||||
grub_uint32_t inode_cnt;
|
||||
grub_uint16_t zone_cnt;
|
||||
grub_uint16_t inode_bmap_size;
|
||||
grub_uint16_t zone_bmap_size;
|
||||
grub_uint16_t first_data_zone;
|
||||
grub_uint16_t log2_zone_size;
|
||||
grub_uint16_t pad;
|
||||
grub_uint32_t max_file_size;
|
||||
grub_uint32_t zones;
|
||||
grub_uint16_t magic;
|
||||
|
||||
grub_uint16_t pad2;
|
||||
grub_uint16_t block_size;
|
||||
grub_uint8_t disk_version;
|
||||
};
|
||||
#else
|
||||
struct grub_minix_sblock
|
||||
{
|
||||
grub_uint16_t inode_cnt;
|
||||
|
@ -76,23 +116,9 @@ struct grub_minix_sblock
|
|||
grub_uint32_t max_file_size;
|
||||
grub_uint16_t magic;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef MODE_MINIX2
|
||||
struct grub_minix_inode
|
||||
{
|
||||
grub_uint16_t mode;
|
||||
grub_uint16_t uid;
|
||||
grub_uint16_t size;
|
||||
grub_uint32_t ctime;
|
||||
grub_uint8_t gid;
|
||||
grub_uint8_t nlinks;
|
||||
grub_uint16_t dir_zones[7];
|
||||
grub_uint16_t indir_zone;
|
||||
grub_uint16_t double_indir_zone;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#if defined(MODE_MINIX3) || defined(MODE_MINIX2)
|
||||
struct grub_minix_inode
|
||||
{
|
||||
grub_uint16_t mode;
|
||||
|
@ -106,8 +132,20 @@ struct grub_minix_inode
|
|||
grub_uint32_t dir_zones[7];
|
||||
grub_uint32_t indir_zone;
|
||||
grub_uint32_t double_indir_zone;
|
||||
grub_uint32_t unused;
|
||||
|
||||
grub_uint32_t triple_indir_zone;
|
||||
};
|
||||
#else
|
||||
struct grub_minix_inode
|
||||
{
|
||||
grub_uint16_t mode;
|
||||
grub_uint16_t uid;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t mtime;
|
||||
grub_uint8_t gid;
|
||||
grub_uint8_t nlinks;
|
||||
grub_uint16_t dir_zones[7];
|
||||
grub_uint16_t indir_zone;
|
||||
grub_uint16_t double_indir_zone;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -121,6 +159,7 @@ struct grub_minix_data
|
|||
int linknest;
|
||||
grub_disk_t disk;
|
||||
int filename_size;
|
||||
grub_size_t block_size;
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
@ -128,50 +167,66 @@ static grub_dl_t my_mod;
|
|||
static grub_err_t grub_minix_find_file (struct grub_minix_data *data,
|
||||
const char *path);
|
||||
|
||||
static int
|
||||
static grub_minix_uintn_t
|
||||
grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
|
||||
{
|
||||
struct grub_minix_sblock *sblock = &data->sblock;
|
||||
int indir;
|
||||
grub_minix_uintn_t indir;
|
||||
const grub_uint32_t block_per_zone = (GRUB_MINIX_ZONESZ
|
||||
/ GRUB_MINIX_INODE_BLKSZ (data));
|
||||
|
||||
auto int grub_get_indir (int, int);
|
||||
auto grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t,
|
||||
grub_minix_uintn_t);
|
||||
|
||||
/* Read the block pointer in ZONE, on the offset NUM. */
|
||||
int grub_get_indir (int zone, int num)
|
||||
grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t zone,
|
||||
grub_minix_uintn_t num)
|
||||
{
|
||||
grub_minix_uintn_t indirn;
|
||||
grub_disk_read (data->disk,
|
||||
zone << GRUB_MINIX_LOG2_ZONESZ,
|
||||
GRUB_MINIX_ZONE2SECT(zone),
|
||||
sizeof (grub_minix_uintn_t) * num,
|
||||
sizeof (grub_minix_uintn_t), (char *) &indirn);
|
||||
return grub_minix_le_to_cpu_n (indirn);
|
||||
}
|
||||
|
||||
/* Direct block. */
|
||||
if (blk < 7)
|
||||
if (blk < GRUB_MINIX_INODE_DIR_BLOCKS)
|
||||
return GRUB_MINIX_INODE_DIR_ZONES (data, blk);
|
||||
|
||||
/* Indirect block. */
|
||||
blk -= 7;
|
||||
if (blk < GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data))
|
||||
blk -= GRUB_MINIX_INODE_DIR_BLOCKS;
|
||||
if (blk < block_per_zone)
|
||||
{
|
||||
indir = grub_get_indir (GRUB_MINIX_INODE_INDIR_ZONE (data), blk);
|
||||
return indir;
|
||||
}
|
||||
|
||||
/* Double indirect block. */
|
||||
blk -= GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data);
|
||||
if (blk < (GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data))
|
||||
* (GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data)))
|
||||
blk -= block_per_zone;
|
||||
if (blk < block_per_zone * block_per_zone)
|
||||
{
|
||||
indir = grub_get_indir (GRUB_MINIX_INODE_DINDIR_ZONE (data),
|
||||
blk / GRUB_MINIX_ZONESZ);
|
||||
blk / block_per_zone);
|
||||
|
||||
indir = grub_get_indir (indir, blk % GRUB_MINIX_ZONESZ);
|
||||
indir = grub_get_indir (indir, blk % 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))
|
||||
{
|
||||
indir = grub_get_indir (grub_minix_le_to_cpu_n (data->inode.triple_indir_zone),
|
||||
(blk / block_per_zone) / block_per_zone);
|
||||
indir = grub_get_indir (indir, (blk / block_per_zone) % block_per_zone);
|
||||
indir = grub_get_indir (indir, blk % block_per_zone);
|
||||
|
||||
return indir;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This should never happen. */
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "file bigger than maximum size");
|
||||
|
||||
|
@ -185,25 +240,26 @@ static grub_ssize_t
|
|||
grub_minix_read_file (struct grub_minix_data *data,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_disk_addr_t len, char *buf)
|
||||
grub_off_t pos, grub_disk_addr_t len, char *buf)
|
||||
{
|
||||
struct grub_minix_sblock *sblock = &data->sblock;
|
||||
int i;
|
||||
int blockcnt;
|
||||
grub_disk_addr_t i;
|
||||
grub_disk_addr_t blockcnt;
|
||||
grub_uint64_t posblock;
|
||||
grub_uint64_t blockoff;
|
||||
|
||||
/* 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;
|
||||
|
||||
blockcnt = (len + pos + GRUB_MINIX_BSIZE - 1) / GRUB_MINIX_BSIZE;
|
||||
blockcnt = grub_divmod64 ((len + pos + data->block_size - 1),
|
||||
data->block_size, 0);
|
||||
posblock = grub_divmod64 (pos, data->block_size, &blockoff);
|
||||
|
||||
for (i = pos / GRUB_MINIX_BSIZE; i < blockcnt; i++)
|
||||
for (i = posblock; i < blockcnt; i++)
|
||||
{
|
||||
int blknr;
|
||||
int blockoff = pos % GRUB_MINIX_BSIZE;
|
||||
int blockend = GRUB_MINIX_BSIZE;
|
||||
|
||||
int skipfirst = 0;
|
||||
grub_disk_addr_t blknr;
|
||||
grub_uint64_t blockend = data->block_size;
|
||||
grub_off_t skipfirst = 0;
|
||||
|
||||
blknr = grub_minix_get_file_block (data, i);
|
||||
if (grub_errno)
|
||||
|
@ -212,28 +268,28 @@ grub_minix_read_file (struct grub_minix_data *data,
|
|||
/* Last block. */
|
||||
if (i == blockcnt - 1)
|
||||
{
|
||||
blockend = (len + pos) % GRUB_MINIX_BSIZE;
|
||||
grub_divmod64 (len + pos, data->block_size, &blockend);
|
||||
|
||||
if (!blockend)
|
||||
blockend = GRUB_MINIX_BSIZE;
|
||||
blockend = data->block_size;
|
||||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == (pos / (int) GRUB_MINIX_BSIZE))
|
||||
if (i == posblock)
|
||||
{
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
}
|
||||
|
||||
data->disk->read_hook = read_hook;
|
||||
grub_disk_read (data->disk, blknr << GRUB_MINIX_LOG2_ZONESZ,
|
||||
grub_disk_read (data->disk,
|
||||
GRUB_MINIX_ZONE2SECT(blknr),
|
||||
skipfirst, blockend, buf);
|
||||
|
||||
data->disk->read_hook = 0;
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
||||
buf += GRUB_MINIX_BSIZE - skipfirst;
|
||||
buf += data->block_size - skipfirst;
|
||||
}
|
||||
|
||||
return len;
|
||||
|
@ -248,16 +304,13 @@ grub_minix_read_inode (struct grub_minix_data *data, int ino)
|
|||
struct grub_minix_sblock *sblock = &data->sblock;
|
||||
|
||||
/* Block in which the inode is stored. */
|
||||
int block;
|
||||
grub_disk_addr_t block;
|
||||
data->ino = ino;
|
||||
|
||||
/* The first inode in minix is inode 1. */
|
||||
ino--;
|
||||
|
||||
block = ((2 + grub_le_to_cpu16 (sblock->inode_bmap_size)
|
||||
+ grub_le_to_cpu16 (sblock->zone_bmap_size))
|
||||
<< GRUB_MINIX_LOG2_BSIZE);
|
||||
|
||||
block = GRUB_MINIX_ZONE2SECT (2 + grub_le_to_cpu16 (sblock->inode_bmap_size)
|
||||
+ grub_le_to_cpu16 (sblock->zone_bmap_size));
|
||||
block += ino / (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode));
|
||||
int offs = (ino % (GRUB_DISK_SECTOR_SIZE
|
||||
/ sizeof (struct grub_minix_inode))
|
||||
|
@ -333,7 +386,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path)
|
|||
|
||||
do
|
||||
{
|
||||
grub_uint16_t ino;
|
||||
grub_minix_ino_t ino;
|
||||
char filename[data->filename_size + 1];
|
||||
|
||||
if (grub_strlen (name) == 0)
|
||||
|
@ -353,7 +406,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path)
|
|||
if (!grub_strcmp (name, filename))
|
||||
{
|
||||
dirino = data->ino;
|
||||
grub_minix_read_inode (data, grub_le_to_cpu16 (ino));
|
||||
grub_minix_read_inode (data, grub_minix_le_to_cpu_ino (ino));
|
||||
|
||||
/* Follow the symlink. */
|
||||
if ((GRUB_MINIX_INODE_MODE (data)
|
||||
|
@ -387,7 +440,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path)
|
|||
pos += sizeof (ino) + data->filename_size;
|
||||
} while (pos < GRUB_MINIX_INODE_SIZE (data));
|
||||
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
@ -409,20 +462,35 @@ grub_minix_mount (grub_disk_t disk)
|
|||
goto fail;
|
||||
|
||||
if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC)
|
||||
{
|
||||
#if !defined(MODE_MINIX3)
|
||||
data->filename_size = 14;
|
||||
#else
|
||||
data->filename_size = 60;
|
||||
#endif
|
||||
}
|
||||
#if !defined(MODE_MINIX3)
|
||||
else if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC_30)
|
||||
data->filename_size = 30;
|
||||
#endif
|
||||
else
|
||||
goto fail;
|
||||
|
||||
data->disk = disk;
|
||||
data->linknest = 0;
|
||||
#ifdef MODE_MINIX3
|
||||
data->block_size = grub_le_to_cpu16 (data->sblock.block_size);
|
||||
#else
|
||||
data->block_size = 1024U;
|
||||
#endif
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
grub_free (data);
|
||||
#ifdef MODE_MINIX2
|
||||
#if defined(MODE_MINIX3)
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a minix3 filesystem");
|
||||
#elif defined(MODE_MINIX2)
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a minix2 filesystem");
|
||||
#else
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a minix filesystem");
|
||||
|
@ -458,7 +526,7 @@ grub_minix_dir (grub_device_t device, const char *path,
|
|||
|
||||
while (pos < GRUB_MINIX_INODE_SIZE (data))
|
||||
{
|
||||
grub_uint16_t ino;
|
||||
grub_minix_ino_t ino;
|
||||
char filename[data->filename_size + 1];
|
||||
int dirino = data->ino;
|
||||
struct grub_dirhook_info info;
|
||||
|
@ -474,12 +542,18 @@ grub_minix_dir (grub_device_t device, const char *path,
|
|||
(char *) filename) < 0)
|
||||
return grub_errno;
|
||||
filename[data->filename_size] = '\0';
|
||||
if (!ino)
|
||||
{
|
||||
pos += sizeof (ino) + data->filename_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The filetype is not stored in the dirent. Read the inode to
|
||||
find out the filetype. This *REALLY* sucks. */
|
||||
grub_minix_read_inode (data, grub_le_to_cpu16 (ino));
|
||||
grub_minix_read_inode (data, grub_minix_le_to_cpu_ino (ino));
|
||||
info.dir = ((GRUB_MINIX_INODE_MODE (data)
|
||||
& GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_le_to_cpu32 (data->inode.mtime);
|
||||
|
||||
if (hook (filename, &info) ? 1 : 0)
|
||||
break;
|
||||
|
||||
|
@ -556,7 +630,9 @@ grub_minix_close (grub_file_t file)
|
|||
|
||||
static struct grub_fs grub_minix_fs =
|
||||
{
|
||||
#ifdef MODE_MINIX2
|
||||
#if defined(MODE_MINIX3)
|
||||
.name = "minix3",
|
||||
#elif defined(MODE_MINIX2)
|
||||
.name = "minix2",
|
||||
#else
|
||||
.name = "minix",
|
||||
|
@ -568,7 +644,9 @@ static struct grub_fs grub_minix_fs =
|
|||
.next = 0
|
||||
};
|
||||
|
||||
#ifdef MODE_MINIX2
|
||||
#if defined(MODE_MINIX3)
|
||||
GRUB_MOD_INIT(minix3)
|
||||
#elif defined(MODE_MINIX2)
|
||||
GRUB_MOD_INIT(minix2)
|
||||
#else
|
||||
GRUB_MOD_INIT(minix)
|
||||
|
@ -578,7 +656,9 @@ GRUB_MOD_INIT(minix)
|
|||
my_mod = mod;
|
||||
}
|
||||
|
||||
#ifdef MODE_MINIX2
|
||||
#if defined(MODE_MINIX3)
|
||||
GRUB_MOD_FINI(minix3)
|
||||
#elif defined(MODE_MINIX2)
|
||||
GRUB_MOD_FINI(minix2)
|
||||
#else
|
||||
GRUB_MOD_FINI(minix)
|
||||
|
|
2
grub-core/fs/minix3.c
Normal file
2
grub-core/fs/minix3.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define MODE_MINIX3 1
|
||||
#include "minix.c"
|
|
@ -35,6 +35,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define NILFS_INODE_BMAP_SIZE 7
|
||||
|
||||
#define NILFS_SUPORT_REV 2
|
||||
|
@ -301,7 +303,7 @@ grub_nilfs2_palloc_entries_per_group (struct grub_nilfs2_data *data)
|
|||
|
||||
static inline grub_uint64_t
|
||||
grub_nilfs2_palloc_group (struct grub_nilfs2_data *data,
|
||||
grub_uint64_t nr, grub_uint32_t * offset)
|
||||
grub_uint64_t nr, grub_uint64_t * offset)
|
||||
{
|
||||
return grub_divmod64 (nr, grub_nilfs2_palloc_entries_per_group (data),
|
||||
offset);
|
||||
|
@ -366,13 +368,15 @@ grub_nilfs2_palloc_entry_offset (struct grub_nilfs2_data *data,
|
|||
grub_uint64_t nr, unsigned long entry_size)
|
||||
{
|
||||
unsigned long group;
|
||||
grub_uint32_t group_offset;
|
||||
grub_uint64_t group_offset;
|
||||
|
||||
group = grub_nilfs2_palloc_group (data, nr, &group_offset);
|
||||
|
||||
return grub_nilfs2_palloc_bitmap_block_offset (data, group,
|
||||
entry_size) + 1 +
|
||||
group_offset / grub_nilfs2_entries_per_block (data, entry_size);
|
||||
grub_divmod64 (group_offset, grub_nilfs2_entries_per_block (data,
|
||||
entry_size),
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
|
@ -575,7 +579,7 @@ grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key)
|
|||
struct grub_nilfs2_dat_entry entry;
|
||||
grub_disk_t disk = data->disk;
|
||||
grub_uint64_t pptr;
|
||||
grub_uint32_t blockno, offset;
|
||||
grub_uint64_t blockno, offset;
|
||||
unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
|
||||
|
||||
blockno = grub_nilfs2_palloc_entry_offset (data, key,
|
||||
|
@ -624,7 +628,7 @@ grub_nilfs2_read_file (grub_fshelp_node_t node,
|
|||
sector,
|
||||
unsigned offset,
|
||||
unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_nilfs2_read_block,
|
||||
|
@ -639,7 +643,7 @@ grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data,
|
|||
struct grub_nilfs2_checkpoint *cpp)
|
||||
{
|
||||
grub_uint64_t blockno;
|
||||
grub_uint32_t offset;
|
||||
grub_uint64_t offset;
|
||||
grub_uint64_t pptr;
|
||||
grub_disk_t disk = data->disk;
|
||||
unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
|
||||
|
@ -677,7 +681,7 @@ grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
|
|||
grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
|
||||
{
|
||||
grub_uint64_t blockno;
|
||||
unsigned int offset;
|
||||
grub_uint64_t offset;
|
||||
grub_uint64_t pptr;
|
||||
grub_disk_t disk = data->disk;
|
||||
unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
|
||||
|
@ -862,7 +866,7 @@ grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
|
|||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
{
|
||||
unsigned int fpos = 0;
|
||||
grub_off_t fpos = 0;
|
||||
struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
|
||||
|
||||
if (!diro->inode_read)
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <grub/ntfs.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
ntfscomp_func_t grub_ntfscomp_func;
|
||||
|
@ -429,7 +431,7 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest,
|
|||
if (at->flags & AF_GPOS)
|
||||
{
|
||||
grub_disk_addr_t st0, st1;
|
||||
grub_uint32_t m;
|
||||
grub_uint64_t m;
|
||||
|
||||
grub_divmod64 (ofs >> BLK_SHR, ctx->comp.spc, &m);
|
||||
|
||||
|
@ -610,6 +612,10 @@ list_file (struct grub_ntfs_file *diro, char *pos,
|
|||
|
||||
fdiro->data = diro->data;
|
||||
fdiro->ino = u32at (pos, 0);
|
||||
if (u64at (pos, 0x20) > u64at (pos, 0x28))
|
||||
fdiro->mtime = u64at (pos, 0x20);
|
||||
else
|
||||
fdiro->mtime = u64at (pos, 0x28);
|
||||
|
||||
ustr = grub_malloc (ns * 4 + 1);
|
||||
if (ustr == NULL)
|
||||
|
@ -880,6 +886,10 @@ grub_ntfs_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_divmod64 (node->mtime, 10000000, 0)
|
||||
- 86400ULL * 365 * (1970 - 1601)
|
||||
- 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100);
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
@ -1077,14 +1087,15 @@ grub_ntfs_uuid (grub_device_t device, char **uuid)
|
|||
if (*uuid)
|
||||
for (ptr = *uuid; *ptr; ptr++)
|
||||
*ptr = grub_toupper (*ptr);
|
||||
free_file (&data->mmft);
|
||||
free_file (&data->cmft);
|
||||
grub_free (data);
|
||||
}
|
||||
else
|
||||
*uuid = NULL;
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
grub_free (data);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <grub/fshelp.h>
|
||||
#include <grub/ntfs.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_err_t
|
||||
decomp_nextvcn (struct grub_ntfs_comp *cc)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define MIN(a, b) \
|
||||
({ typeof (a) _a = (a); \
|
||||
typeof (b) _b = (b); \
|
||||
|
@ -222,6 +224,7 @@ struct grub_fshelp_node
|
|||
grub_uint32_t block_number; /* 0 if node is not found. */
|
||||
grub_uint16_t block_position;
|
||||
grub_uint64_t next_offset;
|
||||
grub_int32_t mtime;
|
||||
enum grub_reiserfs_item_type type; /* To know how to read the header. */
|
||||
struct grub_reiserfs_item_header header;
|
||||
};
|
||||
|
@ -868,6 +871,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
|
|||
entry_v1_stat.rdev,
|
||||
entry_v1_stat.first_direct_byte);
|
||||
#endif
|
||||
entry_item->mtime = grub_le_to_cpu32 (entry_v1_stat.mtime);
|
||||
if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IFLNK)
|
||||
== S_IFLNK)
|
||||
entry_type = GRUB_FSHELP_SYMLINK;
|
||||
|
@ -914,6 +918,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
|
|||
entry_v2_stat.blocks,
|
||||
entry_v2_stat.first_direct_byte);
|
||||
#endif
|
||||
entry_item->mtime = grub_le_to_cpu32 (entry_v2_stat.mtime);
|
||||
if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK)
|
||||
== S_IFLNK)
|
||||
entry_type = GRUB_FSHELP_SYMLINK;
|
||||
|
@ -1276,6 +1281,8 @@ grub_reiserfs_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = 1;
|
||||
info.mtime = node->mtime;
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
|
461
grub-core/fs/romfs.c
Normal file
461
grub-core/fs/romfs.c
Normal file
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/file.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
struct grub_romfs_superblock
|
||||
{
|
||||
char magic[8];
|
||||
#define GRUB_ROMFS_MAGIC "-rom1fs-"
|
||||
grub_uint32_t total_size;
|
||||
grub_uint32_t chksum;
|
||||
char label[0];
|
||||
};
|
||||
|
||||
struct grub_romfs_file_header
|
||||
{
|
||||
grub_uint32_t next_file;
|
||||
grub_uint32_t spec;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t chksum;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct grub_romfs_data
|
||||
{
|
||||
grub_disk_addr_t first_file;
|
||||
grub_disk_t disk;
|
||||
};
|
||||
|
||||
struct grub_fshelp_node
|
||||
{
|
||||
grub_disk_addr_t addr;
|
||||
struct grub_romfs_data *data;
|
||||
grub_disk_addr_t data_addr;
|
||||
/* Not filled for root. */
|
||||
struct grub_romfs_file_header file;
|
||||
};
|
||||
|
||||
#define GRUB_ROMFS_ALIGN 16
|
||||
#define GRUB_ROMFS_TYPE_MASK 7
|
||||
#define GRUB_ROMFS_TYPE_HARDLINK 0
|
||||
#define GRUB_ROMFS_TYPE_DIRECTORY 1
|
||||
#define GRUB_ROMFS_TYPE_REGULAR 2
|
||||
#define GRUB_ROMFS_TYPE_SYMLINK 3
|
||||
|
||||
static grub_err_t
|
||||
do_checksum (void *in, grub_size_t insize)
|
||||
{
|
||||
grub_uint32_t *a = in;
|
||||
grub_size_t sz = insize / 4;
|
||||
grub_uint32_t *b = a + sz;
|
||||
grub_uint32_t csum = 0;
|
||||
|
||||
while (a < b)
|
||||
csum += grub_be_to_cpu32 (*a++);
|
||||
if (csum)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid checksum");
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_romfs_data *
|
||||
grub_romfs_mount (grub_device_t dev)
|
||||
{
|
||||
union {
|
||||
struct grub_romfs_superblock sb;
|
||||
char d[512];
|
||||
} sb;
|
||||
grub_err_t err;
|
||||
char *ptr;
|
||||
grub_disk_addr_t sec = 0;
|
||||
struct grub_romfs_data *data;
|
||||
if (!dev->disk)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a disk");
|
||||
return NULL;
|
||||
}
|
||||
err = grub_disk_read (dev->disk, 0, 0, sizeof (sb), &sb);
|
||||
if (err == GRUB_ERR_OUT_OF_RANGE)
|
||||
err = grub_errno = GRUB_ERR_BAD_FS;
|
||||
if (err)
|
||||
return NULL;
|
||||
if (grub_be_to_cpu32 (sb.sb.total_size) < sizeof (sb))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "too short filesystem");
|
||||
return NULL;
|
||||
}
|
||||
err = do_checksum (&sb, sizeof (sb) < grub_be_to_cpu32 (sb.sb.total_size) ?
|
||||
sizeof (sb) : grub_be_to_cpu32 (sb.sb.total_size));
|
||||
if (err)
|
||||
return NULL;
|
||||
for (ptr = sb.sb.label; (void *) ptr < (void *) (&sb + 1)
|
||||
&& ptr < sb.d + grub_be_to_cpu32 (sb.sb.total_size); ptr++)
|
||||
if (!*ptr)
|
||||
break;
|
||||
if ((void *) ptr == &sb + 1)
|
||||
for (sec++; ; sec++)
|
||||
{
|
||||
err = grub_disk_read (dev->disk, sec, 0, sizeof (sb), &sb);
|
||||
if (err == GRUB_ERR_OUT_OF_RANGE)
|
||||
err = grub_errno = GRUB_ERR_BAD_FS;
|
||||
if (err)
|
||||
return NULL;
|
||||
for (ptr = sb.d; (void *) ptr < (void *) (&sb + 1)
|
||||
&& ptr < sb.d + grub_be_to_cpu32 (sb.sb.total_size); ptr++)
|
||||
if (!*ptr)
|
||||
break;
|
||||
}
|
||||
data = grub_malloc (sizeof (*data));
|
||||
if (!data)
|
||||
return NULL;
|
||||
data->first_file = ALIGN_UP (ptr - sb.d, GRUB_ROMFS_ALIGN) + sec * 512;
|
||||
data->disk = dev->disk;
|
||||
return data;
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_romfs_read_symlink (grub_fshelp_node_t node)
|
||||
{
|
||||
char *ret;
|
||||
grub_err_t err;
|
||||
ret = grub_malloc (grub_be_to_cpu32 (node->file.size) + 1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
err = grub_disk_read (node->data->disk,
|
||||
(node->data_addr) >> GRUB_DISK_SECTOR_BITS,
|
||||
(node->data_addr) & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
grub_be_to_cpu32 (node->file.size), ret);
|
||||
if (err)
|
||||
{
|
||||
grub_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
ret[grub_be_to_cpu32 (node->file.size)] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_romfs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
{
|
||||
grub_disk_addr_t caddr;
|
||||
struct grub_romfs_file_header hdr;
|
||||
grub_size_t a = 0;
|
||||
char *name = NULL;
|
||||
unsigned nptr;
|
||||
unsigned i, j;
|
||||
for (caddr = dir->data_addr; caddr;
|
||||
caddr = grub_be_to_cpu32 (hdr.next_file) & ~(GRUB_ROMFS_ALIGN - 1))
|
||||
{
|
||||
grub_disk_addr_t naddr = caddr + sizeof (hdr);
|
||||
grub_uint32_t csum = 0;
|
||||
enum grub_fshelp_filetype filetype = GRUB_FSHELP_UNKNOWN;
|
||||
struct grub_fshelp_node *node;
|
||||
grub_err_t err;
|
||||
|
||||
err = grub_disk_read (dir->data->disk, caddr >> GRUB_DISK_SECTOR_BITS,
|
||||
caddr & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
sizeof (hdr), &hdr);
|
||||
if (err)
|
||||
{
|
||||
grub_free (name);
|
||||
return 1;
|
||||
}
|
||||
for (nptr = 0; ; nptr++, naddr += 16)
|
||||
{
|
||||
if (a >= nptr)
|
||||
{
|
||||
char *on;
|
||||
a = 2 * (nptr + 1);
|
||||
on = name;
|
||||
name = grub_realloc (name, a * 16);
|
||||
if (!name)
|
||||
{
|
||||
grub_free (on);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
err = grub_disk_read (dir->data->disk, naddr >> GRUB_DISK_SECTOR_BITS,
|
||||
naddr & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
16, name + 16 * nptr);
|
||||
if (err)
|
||||
return 1;
|
||||
for (j = 0; j < 16; j++)
|
||||
if (!name[16 * nptr + j])
|
||||
break;
|
||||
if (j != 16)
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < sizeof (hdr) / sizeof (grub_uint32_t); i++)
|
||||
csum += grub_be_to_cpu32 (((grub_uint32_t *) &hdr)[i]);
|
||||
for (i = 0; i < (nptr + 1) * 4; i++)
|
||||
csum += grub_be_to_cpu32 (((grub_uint32_t *) name)[i]);
|
||||
if (csum != 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "invalid checksum");
|
||||
grub_free (name);
|
||||
return 1;
|
||||
}
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (!node)
|
||||
return 1;
|
||||
node->addr = caddr;
|
||||
node->data_addr = caddr + (nptr + 1) * 16 + sizeof (hdr);
|
||||
node->data = dir->data;
|
||||
node->file = hdr;
|
||||
switch (grub_be_to_cpu32 (hdr.next_file) & GRUB_ROMFS_TYPE_MASK)
|
||||
{
|
||||
case GRUB_ROMFS_TYPE_REGULAR:
|
||||
filetype = GRUB_FSHELP_REG;
|
||||
break;
|
||||
case GRUB_ROMFS_TYPE_SYMLINK:
|
||||
filetype = GRUB_FSHELP_SYMLINK;
|
||||
break;
|
||||
case GRUB_ROMFS_TYPE_DIRECTORY:
|
||||
node->data_addr = grub_be_to_cpu32 (hdr.spec);
|
||||
filetype = GRUB_FSHELP_DIR;
|
||||
break;
|
||||
case GRUB_ROMFS_TYPE_HARDLINK:
|
||||
{
|
||||
grub_disk_addr_t laddr;
|
||||
node->addr = laddr = grub_be_to_cpu32 (hdr.spec);
|
||||
err = grub_disk_read (dir->data->disk,
|
||||
laddr >> GRUB_DISK_SECTOR_BITS,
|
||||
laddr & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
sizeof (node->file), &node->file);
|
||||
if (err)
|
||||
return 1;
|
||||
if ((grub_be_to_cpu32 (node->file.next_file) & GRUB_ROMFS_TYPE_MASK)
|
||||
== GRUB_ROMFS_TYPE_REGULAR
|
||||
|| (grub_be_to_cpu32 (node->file.next_file)
|
||||
& GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_SYMLINK)
|
||||
{
|
||||
laddr += sizeof (hdr);
|
||||
while (1)
|
||||
{
|
||||
char buf[16];
|
||||
err = grub_disk_read (dir->data->disk,
|
||||
laddr >> GRUB_DISK_SECTOR_BITS,
|
||||
laddr & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
16, buf);
|
||||
if (err)
|
||||
return 1;
|
||||
for (i = 0; i < 16; i++)
|
||||
if (!buf[i])
|
||||
break;
|
||||
if (i != 16)
|
||||
break;
|
||||
laddr += 16;
|
||||
}
|
||||
node->data_addr = laddr + 16;
|
||||
}
|
||||
if ((grub_be_to_cpu32 (node->file.next_file)
|
||||
& GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_REGULAR)
|
||||
filetype = GRUB_FSHELP_REG;
|
||||
if ((grub_be_to_cpu32 (node->file.next_file)
|
||||
& GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_SYMLINK)
|
||||
filetype = GRUB_FSHELP_SYMLINK;
|
||||
if ((grub_be_to_cpu32 (node->file.next_file) & GRUB_ROMFS_TYPE_MASK)
|
||||
== GRUB_ROMFS_TYPE_DIRECTORY)
|
||||
{
|
||||
node->data_addr = grub_be_to_cpu32 (node->file.spec);
|
||||
filetype = GRUB_FSHELP_DIR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hook (name, filetype, node))
|
||||
{
|
||||
grub_free (name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
grub_free (name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_romfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
struct grub_romfs_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0, start;
|
||||
|
||||
auto int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node);
|
||||
|
||||
int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
||||
data = grub_romfs_mount (device);
|
||||
if (! data)
|
||||
goto fail;
|
||||
|
||||
start.addr = data->first_file;
|
||||
start.data_addr = data->first_file;
|
||||
start.data = data;
|
||||
grub_fshelp_find_file (path, &start, &fdiro, grub_romfs_iterate_dir,
|
||||
grub_romfs_read_symlink, GRUB_FSHELP_DIR);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_romfs_iterate_dir (fdiro, iterate);
|
||||
|
||||
fail:
|
||||
grub_free (data);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_romfs_open (struct grub_file *file, const char *name)
|
||||
{
|
||||
struct grub_romfs_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0, start;
|
||||
|
||||
data = grub_romfs_mount (file->device);
|
||||
if (! data)
|
||||
goto fail;
|
||||
|
||||
start.addr = data->first_file;
|
||||
start.data_addr = data->first_file;
|
||||
start.data = data;
|
||||
|
||||
grub_fshelp_find_file (name, &start, &fdiro, grub_romfs_iterate_dir,
|
||||
grub_romfs_read_symlink, GRUB_FSHELP_REG);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
file->size = grub_be_to_cpu32 (fdiro->file.size);
|
||||
file->data = fdiro;
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
fail:
|
||||
grub_free (data);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_romfs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_fshelp_node *data = file->data;
|
||||
|
||||
/* XXX: The file is stored in as a single extent. */
|
||||
data->data->disk->read_hook = file->read_hook;
|
||||
grub_disk_read (data->data->disk,
|
||||
(data->data_addr + file->offset) >> GRUB_DISK_SECTOR_BITS,
|
||||
(data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
len, buf);
|
||||
data->data->disk->read_hook = NULL;
|
||||
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_romfs_close (grub_file_t file)
|
||||
{
|
||||
grub_free (file->data);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_romfs_label (grub_device_t device, char **label)
|
||||
{
|
||||
struct grub_romfs_data *data;
|
||||
grub_err_t err;
|
||||
|
||||
*label = NULL;
|
||||
|
||||
data = grub_romfs_mount (device);
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
*label = grub_malloc (data->first_file + 1
|
||||
- sizeof (struct grub_romfs_superblock));
|
||||
if (!*label)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
err = grub_disk_read (device->disk, 0, sizeof (struct grub_romfs_superblock),
|
||||
data->first_file
|
||||
- sizeof (struct grub_romfs_superblock),
|
||||
*label);
|
||||
if (err)
|
||||
{
|
||||
grub_free (data);
|
||||
grub_free (*label);
|
||||
*label = NULL;
|
||||
return err;
|
||||
}
|
||||
(*label)[data->first_file - sizeof (struct grub_romfs_superblock)] = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
static struct grub_fs grub_romfs_fs =
|
||||
{
|
||||
.name = "romfs",
|
||||
.dir = grub_romfs_dir,
|
||||
.open = grub_romfs_open,
|
||||
.read = grub_romfs_read,
|
||||
.close = grub_romfs_close,
|
||||
.label = grub_romfs_label,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 0,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(romfs)
|
||||
{
|
||||
grub_fs_register (&grub_romfs_fs);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(romfs)
|
||||
{
|
||||
grub_fs_unregister (&grub_romfs_fs);
|
||||
}
|
|
@ -26,6 +26,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* The common header for a block. */
|
||||
struct grub_sfs_bheader
|
||||
{
|
||||
|
@ -66,7 +68,7 @@ struct grub_sfs_obj
|
|||
grub_uint32_t dir_objc;
|
||||
} dir __attribute__ ((packed));
|
||||
} file_dir;
|
||||
grub_uint8_t unused3[4];
|
||||
grub_uint32_t mtime;
|
||||
grub_uint8_t type;
|
||||
grub_uint8_t filename[1];
|
||||
grub_uint8_t comment[1];
|
||||
|
@ -119,6 +121,7 @@ struct grub_fshelp_node
|
|||
struct grub_sfs_data *data;
|
||||
int block;
|
||||
int size;
|
||||
grub_uint32_t mtime;
|
||||
};
|
||||
|
||||
/* Information about a "mounted" sfs filesystem. */
|
||||
|
@ -247,7 +250,7 @@ static grub_ssize_t
|
|||
grub_sfs_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_sfs_read_block,
|
||||
|
@ -355,10 +358,12 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
int pos;
|
||||
|
||||
auto int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name, int block,
|
||||
int size, int type);
|
||||
int size, int type,
|
||||
grub_uint32_t mtime);
|
||||
|
||||
int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name, int block,
|
||||
int size, int type)
|
||||
int size, int type,
|
||||
grub_uint32_t mtime)
|
||||
{
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (!node)
|
||||
|
@ -367,6 +372,7 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
node->data = data;
|
||||
node->size = size;
|
||||
node->block = block;
|
||||
node->mtime = mtime;
|
||||
|
||||
return hook (name, type, node);
|
||||
}
|
||||
|
@ -426,7 +432,7 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
|
||||
if (grub_sfs_create_node (filename, block,
|
||||
grub_be_to_cpu32 (obj->file_dir.file.size),
|
||||
type))
|
||||
type, grub_be_to_cpu32 (obj->mtime)))
|
||||
{
|
||||
grub_free (objc_data);
|
||||
return 1;
|
||||
|
@ -525,6 +531,8 @@ grub_sfs_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtime = node->mtime + 8 * 365 * 86400 + 86400 * 2;
|
||||
info.mtimeset = 1;
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
@ -579,6 +587,9 @@ static struct grub_fs grub_sfs_fs =
|
|||
.read = grub_sfs_read,
|
||||
.close = grub_sfs_close,
|
||||
.label = grub_sfs_label,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 0,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
|
700
grub-core/fs/squash4.c
Normal file
700
grub-core/fs/squash4.c
Normal file
|
@ -0,0 +1,700 @@
|
|||
/* squash4.c - SquashFS */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/err.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
#include <grub/deflate.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/*
|
||||
object format Pointed by
|
||||
superblock RAW Fixed offset (0)
|
||||
data RAW ? Fixed offset (60)
|
||||
inode table Chunk superblock
|
||||
dir table Chunk superblock
|
||||
fragment table Chunk unk1
|
||||
unk1 RAW, Chunk superblock
|
||||
unk2 RAW superblock
|
||||
UID/GID Chunk exttblptr
|
||||
exttblptr RAW superblock
|
||||
|
||||
UID/GID table is the array ot uint32_t
|
||||
unk1 contains pointer to fragment table followed by some chunk.
|
||||
unk2 containts one uint64_t
|
||||
*/
|
||||
|
||||
struct grub_squash_super
|
||||
{
|
||||
grub_uint32_t magic;
|
||||
#define SQUASH_MAGIC 0x73717368
|
||||
grub_uint32_t dummy1;
|
||||
grub_uint32_t creation_time;
|
||||
grub_uint32_t block_size;
|
||||
grub_uint64_t dummy3;
|
||||
grub_uint64_t dummy4;
|
||||
grub_uint16_t root_ino_offset;
|
||||
grub_uint32_t root_ino_chunk;
|
||||
grub_uint16_t dummy5;
|
||||
grub_uint64_t total_size;
|
||||
grub_uint64_t exttbloffset;
|
||||
grub_uint64_t dummy6;
|
||||
grub_uint64_t inodeoffset;
|
||||
grub_uint64_t diroffset;
|
||||
grub_uint64_t unk1offset;
|
||||
grub_uint64_t unk2offset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Chunk-based */
|
||||
struct grub_squash_inode
|
||||
{
|
||||
/* Same values as direlem types. */
|
||||
grub_uint16_t type;
|
||||
grub_uint16_t dummy[3];
|
||||
grub_uint32_t mtime;
|
||||
union
|
||||
{
|
||||
struct {
|
||||
grub_uint32_t dummy;
|
||||
grub_uint32_t chunk;
|
||||
grub_uint32_t fragment;
|
||||
grub_uint32_t offset;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t block_size[0];
|
||||
} __attribute__ ((packed)) file;
|
||||
struct {
|
||||
grub_uint32_t dummy;
|
||||
grub_uint64_t chunk;
|
||||
grub_uint64_t size;
|
||||
grub_uint32_t dummy2[3];
|
||||
grub_uint32_t fragment;
|
||||
grub_uint32_t offset;
|
||||
grub_uint32_t dummy3;
|
||||
grub_uint32_t block_size[0];
|
||||
} __attribute__ ((packed)) long_file;
|
||||
struct {
|
||||
grub_uint32_t dummy1;
|
||||
grub_uint32_t chunk;
|
||||
grub_uint32_t dummy2;
|
||||
grub_uint16_t size;
|
||||
grub_uint32_t offset;
|
||||
grub_uint16_t dummy3;
|
||||
} __attribute__ ((packed)) dir;
|
||||
struct {
|
||||
grub_uint64_t dummy;
|
||||
grub_uint32_t namelen;
|
||||
char name[0];
|
||||
} __attribute__ ((packed)) symlink;
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_squash_cache_inode
|
||||
{
|
||||
struct grub_squash_inode ino;
|
||||
grub_disk_addr_t ino_chunk;
|
||||
grub_uint16_t ino_offset;
|
||||
grub_uint32_t *block_sizes;
|
||||
grub_disk_addr_t *cumulated_block_sizes;
|
||||
};
|
||||
|
||||
/* Chunk-based. */
|
||||
struct grub_squash_dirent_header
|
||||
{
|
||||
/* Actually the value is the number of elements - 1. */
|
||||
grub_uint32_t nelems;
|
||||
grub_uint64_t ino_chunk;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_squash_dirent
|
||||
{
|
||||
grub_uint16_t ino_offset;
|
||||
grub_uint16_t dummy;
|
||||
grub_uint16_t type;
|
||||
/* Actually the value is the length of name - 1. */
|
||||
grub_uint16_t namelen;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
SQUASH_TYPE_DIR = 1,
|
||||
SQUASH_TYPE_REGULAR = 2,
|
||||
SQUASH_TYPE_SYMLINK = 3,
|
||||
SQUASH_TYPE_LONG_REGULAR = 9,
|
||||
};
|
||||
|
||||
|
||||
struct grub_squash_frag_desc
|
||||
{
|
||||
grub_uint64_t offset;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t dummy;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
SQUASH_CHUNK_FLAGS = 0x8000,
|
||||
SQUASH_CHUNK_UNCOMPRESSED = 0x8000
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SQUASH_BLOCK_FLAGS = 0x1000000,
|
||||
SQUASH_BLOCK_UNCOMPRESSED = 0x1000000
|
||||
};
|
||||
|
||||
#define SQUASH_CHUNK_SIZE 0x2000
|
||||
|
||||
struct grub_squash_data
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_squash_super sb;
|
||||
struct grub_squash_cache_inode ino;
|
||||
grub_uint64_t fragments;
|
||||
};
|
||||
|
||||
struct grub_fshelp_node
|
||||
{
|
||||
struct grub_squash_data *data;
|
||||
struct grub_squash_inode ino;
|
||||
grub_disk_addr_t ino_chunk;
|
||||
grub_uint16_t ino_offset;
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len,
|
||||
grub_uint64_t chunk, grub_off_t offset)
|
||||
{
|
||||
grub_uint64_t chunk_start;
|
||||
chunk_start = grub_le_to_cpu64 (chunk);
|
||||
while (len > 0)
|
||||
{
|
||||
grub_uint64_t csize;
|
||||
grub_uint16_t d;
|
||||
grub_err_t err;
|
||||
while (1)
|
||||
{
|
||||
err = grub_disk_read (data->disk,
|
||||
chunk_start >> GRUB_DISK_SECTOR_BITS,
|
||||
chunk_start & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
sizeof (d), &d);
|
||||
if (err)
|
||||
return err;
|
||||
if (offset < SQUASH_CHUNK_SIZE)
|
||||
break;
|
||||
offset -= SQUASH_CHUNK_SIZE;
|
||||
chunk_start += 2 + (grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS);
|
||||
}
|
||||
|
||||
csize = SQUASH_CHUNK_SIZE - offset;
|
||||
if (csize > len)
|
||||
csize = len;
|
||||
|
||||
if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED)
|
||||
{
|
||||
grub_disk_addr_t a = chunk_start + 2 + offset;
|
||||
err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS),
|
||||
a & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
csize, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *tmp;
|
||||
grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS;
|
||||
grub_disk_addr_t a = chunk_start + 2;
|
||||
tmp = grub_malloc (bsize);
|
||||
if (!tmp)
|
||||
return grub_errno;
|
||||
/* FIXME: buffer uncompressed data. */
|
||||
err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS),
|
||||
a & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
bsize, tmp);
|
||||
if (err)
|
||||
{
|
||||
grub_free (tmp);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (grub_zlib_decompress (tmp, bsize, offset,
|
||||
buf, csize) < 0)
|
||||
{
|
||||
grub_free (tmp);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_free (tmp);
|
||||
}
|
||||
len -= csize;
|
||||
offset += csize;
|
||||
buf = (char *) buf + csize;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_squash_data *
|
||||
squash_mount (grub_disk_t disk)
|
||||
{
|
||||
struct grub_squash_super sb;
|
||||
grub_err_t err;
|
||||
struct grub_squash_data *data;
|
||||
grub_uint64_t frag;
|
||||
|
||||
err = grub_disk_read (disk, 0, 0, sizeof (sb), &sb);
|
||||
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a squash4");
|
||||
if (err)
|
||||
return NULL;
|
||||
if (grub_le_to_cpu32 (sb.magic) != SQUASH_MAGIC)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "not squash4");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = grub_disk_read (disk,
|
||||
grub_le_to_cpu64 (sb.unk1offset)
|
||||
>> GRUB_DISK_SECTOR_BITS,
|
||||
grub_le_to_cpu64 (sb.unk1offset)
|
||||
& (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag);
|
||||
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a squash4");
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
data = grub_malloc (sizeof (*data));
|
||||
if (!data)
|
||||
return NULL;
|
||||
data->sb = sb;
|
||||
data->disk = disk;
|
||||
data->fragments = grub_le_to_cpu64 (frag);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_squash_read_symlink (grub_fshelp_node_t node)
|
||||
{
|
||||
char *ret;
|
||||
grub_err_t err;
|
||||
ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1);
|
||||
|
||||
err = read_chunk (node->data, ret,
|
||||
grub_le_to_cpu32 (node->ino.symlink.namelen),
|
||||
grub_le_to_cpu64 (node->data->sb.inodeoffset)
|
||||
+ node->ino_chunk,
|
||||
node->ino_offset + (node->ino.symlink.name
|
||||
- (char *) &node->ino));
|
||||
if (err)
|
||||
{
|
||||
grub_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
ret[grub_le_to_cpu32 (node->ino.symlink.namelen)] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
{
|
||||
grub_uint32_t off = grub_le_to_cpu16 (dir->ino.dir.offset);
|
||||
grub_uint32_t endoff;
|
||||
unsigned i;
|
||||
|
||||
/* FIXME: why - 3 ? */
|
||||
endoff = grub_le_to_cpu32 (dir->ino.dir.size) + off - 3;
|
||||
|
||||
while (off < endoff)
|
||||
{
|
||||
struct grub_squash_dirent_header dh;
|
||||
grub_err_t err;
|
||||
|
||||
err = read_chunk (dir->data, &dh, sizeof (dh),
|
||||
grub_le_to_cpu64 (dir->data->sb.diroffset)
|
||||
+ grub_le_to_cpu32 (dir->ino.dir.chunk), off);
|
||||
if (err)
|
||||
return 0;
|
||||
off += sizeof (dh);
|
||||
for (i = 0; i < (unsigned) grub_le_to_cpu16 (dh.nelems) + 1; i++)
|
||||
{
|
||||
char *buf;
|
||||
int r;
|
||||
struct grub_fshelp_node *node;
|
||||
enum grub_fshelp_filetype filetype = GRUB_FSHELP_REG;
|
||||
struct grub_squash_dirent di;
|
||||
struct grub_squash_inode ino;
|
||||
|
||||
err = read_chunk (dir->data, &di, sizeof (di),
|
||||
grub_le_to_cpu64 (dir->data->sb.diroffset)
|
||||
+ grub_le_to_cpu32 (dir->ino.dir.chunk), off);
|
||||
if (err)
|
||||
return 0;
|
||||
off += sizeof (di);
|
||||
|
||||
err = read_chunk (dir->data, &ino, sizeof (ino),
|
||||
grub_le_to_cpu64 (dir->data->sb.inodeoffset)
|
||||
+ grub_le_to_cpu32 (dh.ino_chunk),
|
||||
grub_cpu_to_le16 (di.ino_offset));
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2);
|
||||
if (!buf)
|
||||
return 0;
|
||||
err = read_chunk (dir->data, buf,
|
||||
grub_le_to_cpu16 (di.namelen) + 1,
|
||||
grub_le_to_cpu64 (dir->data->sb.diroffset)
|
||||
+ grub_le_to_cpu32 (dir->ino.dir.chunk), off);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
off += grub_le_to_cpu16 (di.namelen) + 1;
|
||||
buf[grub_le_to_cpu16 (di.namelen) + 1] = 0;
|
||||
if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_DIR)
|
||||
filetype = GRUB_FSHELP_DIR;
|
||||
if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_SYMLINK)
|
||||
filetype = GRUB_FSHELP_SYMLINK;
|
||||
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (! node)
|
||||
return 0;
|
||||
*node = *dir;
|
||||
node->ino = ino;
|
||||
node->ino_chunk = grub_le_to_cpu32 (dh.ino_chunk);
|
||||
node->ino_offset = grub_le_to_cpu16 (di.ino_offset);
|
||||
|
||||
r = hook (buf, filetype, node);
|
||||
|
||||
grub_free (buf);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root)
|
||||
{
|
||||
grub_memset (root, 0, sizeof (*root));
|
||||
root->data = data;
|
||||
|
||||
return read_chunk (data, &root->ino, sizeof (root->ino),
|
||||
grub_le_to_cpu64 (data->sb.inodeoffset)
|
||||
+ grub_le_to_cpu16 (data->sb.root_ino_chunk),
|
||||
grub_cpu_to_le16 (data->sb.root_ino_offset));
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_squash_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
auto int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node);
|
||||
|
||||
int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_le_to_cpu32 (node->ino.mtime);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
||||
struct grub_squash_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0;
|
||||
struct grub_fshelp_node root;
|
||||
grub_err_t err;
|
||||
|
||||
data = squash_mount (device->disk);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
err = make_root_node (data, &root);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir,
|
||||
grub_squash_read_symlink, GRUB_FSHELP_DIR);
|
||||
if (!grub_errno)
|
||||
grub_squash_iterate_dir (fdiro, iterate);
|
||||
|
||||
grub_free (data);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_squash_open (struct grub_file *file, const char *name)
|
||||
{
|
||||
struct grub_squash_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0;
|
||||
struct grub_fshelp_node root;
|
||||
grub_err_t err;
|
||||
|
||||
data = squash_mount (file->device->disk);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
err = make_root_node (data, &root);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
grub_fshelp_find_file (name, &root, &fdiro, grub_squash_iterate_dir,
|
||||
grub_squash_read_symlink, GRUB_FSHELP_REG);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
file->data = data;
|
||||
data->ino.ino = fdiro->ino;
|
||||
data->ino.block_sizes = NULL;
|
||||
data->ino.cumulated_block_sizes = NULL;
|
||||
data->ino.ino_chunk = fdiro->ino_chunk;
|
||||
data->ino.ino_offset = fdiro->ino_offset;
|
||||
|
||||
if (fdiro->ino.type
|
||||
== grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
file->size = grub_le_to_cpu64 (fdiro->ino.long_file.size);
|
||||
else
|
||||
file->size = grub_le_to_cpu32 (fdiro->ino.file.size);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
direct_read (struct grub_squash_data *data,
|
||||
struct grub_squash_cache_inode *ino,
|
||||
grub_off_t off, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_off_t cumulated_uncompressed_size = 0;
|
||||
grub_uint64_t a;
|
||||
grub_size_t i;
|
||||
grub_size_t origlen = len;
|
||||
|
||||
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
a = grub_le_to_cpu64 (ino->ino.long_file.chunk);
|
||||
else
|
||||
a = grub_le_to_cpu32 (ino->ino.file.chunk);
|
||||
|
||||
if (!ino->block_sizes)
|
||||
{
|
||||
grub_off_t total_size;
|
||||
grub_size_t total_blocks;
|
||||
grub_size_t block_offset;
|
||||
if (ino->ino.type
|
||||
== grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
{
|
||||
total_size = grub_le_to_cpu64 (ino->ino.long_file.size);
|
||||
block_offset = ((char *) &ino->ino.long_file.block_size
|
||||
- (char *) &ino->ino);
|
||||
}
|
||||
else
|
||||
{
|
||||
total_size = grub_le_to_cpu32 (ino->ino.file.size);
|
||||
block_offset = ((char *) &ino->ino.file.block_size
|
||||
- (char *) &ino->ino);
|
||||
}
|
||||
total_blocks = grub_divmod64 (total_size
|
||||
+ grub_le_to_cpu32 (data->sb.block_size) - 1,
|
||||
grub_le_to_cpu32 (data->sb.block_size),
|
||||
0);
|
||||
ino->block_sizes = grub_malloc (total_blocks
|
||||
* sizeof (ino->block_sizes[0]));
|
||||
ino->cumulated_block_sizes = grub_malloc (total_blocks
|
||||
* sizeof (ino->cumulated_block_sizes[0]));
|
||||
if (!ino->block_sizes || !ino->cumulated_block_sizes)
|
||||
{
|
||||
grub_free (ino->block_sizes);
|
||||
grub_free (ino->cumulated_block_sizes);
|
||||
ino->block_sizes = 0;
|
||||
ino->cumulated_block_sizes = 0;
|
||||
return -1;
|
||||
}
|
||||
err = read_chunk (data, ino->block_sizes,
|
||||
total_blocks * sizeof (ino->block_sizes[0]),
|
||||
grub_le_to_cpu64 (data->sb.inodeoffset)
|
||||
+ ino->ino_chunk,
|
||||
ino->ino_offset + block_offset);
|
||||
if (err)
|
||||
{
|
||||
grub_free (ino->block_sizes);
|
||||
grub_free (ino->cumulated_block_sizes);
|
||||
ino->block_sizes = 0;
|
||||
ino->cumulated_block_sizes = 0;
|
||||
return -1;
|
||||
}
|
||||
ino->cumulated_block_sizes[0] = 0;
|
||||
for (i = 1; i < total_blocks; i++)
|
||||
ino->cumulated_block_sizes[i] = ino->cumulated_block_sizes[i - 1]
|
||||
+ (grub_le_to_cpu32 (ino->block_sizes[i - 1]) & ~SQUASH_BLOCK_FLAGS);
|
||||
}
|
||||
|
||||
if (a == 0)
|
||||
a = sizeof (struct grub_squash_super);
|
||||
i = grub_divmod64 (off, grub_le_to_cpu32 (data->sb.block_size), 0);
|
||||
cumulated_uncompressed_size = grub_le_to_cpu32 (data->sb.block_size)
|
||||
* (grub_disk_addr_t) i;
|
||||
while (cumulated_uncompressed_size < off + len)
|
||||
{
|
||||
grub_size_t boff, read;
|
||||
boff = off - cumulated_uncompressed_size;
|
||||
read = grub_le_to_cpu32 (data->sb.block_size) - boff;
|
||||
if (read > len)
|
||||
read = len;
|
||||
if (!(ino->block_sizes[i] & SQUASH_BLOCK_UNCOMPRESSED))
|
||||
err = grub_zlib_disk_read (data->disk,
|
||||
ino->cumulated_block_sizes[i] + a,
|
||||
boff, buf, read);
|
||||
else
|
||||
err = grub_disk_read (data->disk,
|
||||
(ino->cumulated_block_sizes[i] + a + boff)
|
||||
>> GRUB_DISK_SECTOR_BITS,
|
||||
(ino->cumulated_block_sizes[i] + a + boff)
|
||||
& (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
read, buf);
|
||||
if (err)
|
||||
return -1;
|
||||
off += read;
|
||||
len -= read;
|
||||
buf += read;
|
||||
cumulated_uncompressed_size += grub_le_to_cpu32 (data->sb.block_size);
|
||||
i++;
|
||||
}
|
||||
return origlen;
|
||||
}
|
||||
|
||||
|
||||
static grub_ssize_t
|
||||
grub_squash_read_data (struct grub_squash_data *data,
|
||||
struct grub_squash_cache_inode *ino,
|
||||
grub_off_t off, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_uint64_t a, b;
|
||||
grub_uint32_t fragment;
|
||||
int compressed = 0;
|
||||
struct grub_squash_frag_desc frag;
|
||||
|
||||
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
{
|
||||
a = grub_le_to_cpu64 (ino->ino.long_file.chunk);
|
||||
fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = grub_le_to_cpu32 (ino->ino.file.chunk);
|
||||
fragment = grub_le_to_cpu32 (ino->ino.file.fragment);
|
||||
}
|
||||
|
||||
if (fragment == 0xffffffff)
|
||||
return direct_read (data, ino, off, buf, len);
|
||||
|
||||
err = read_chunk (data, &frag, sizeof (frag),
|
||||
data->fragments, sizeof (frag) * fragment);
|
||||
if (err)
|
||||
return -1;
|
||||
a += grub_le_to_cpu64 (frag.offset);
|
||||
compressed = !(frag.size & SQUASH_BLOCK_UNCOMPRESSED);
|
||||
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
b = grub_le_to_cpu64 (ino->ino.long_file.offset) + off;
|
||||
else
|
||||
b = grub_le_to_cpu32 (ino->ino.file.offset) + off;
|
||||
|
||||
/* FIXME: cache uncompressed chunks. */
|
||||
if (compressed)
|
||||
err = grub_zlib_disk_read (data->disk, a, b, buf, len);
|
||||
else
|
||||
err = grub_disk_read (data->disk, (a + b) >> GRUB_DISK_SECTOR_BITS,
|
||||
(a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
|
||||
if (err)
|
||||
return -1;
|
||||
return len;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_squash_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_squash_data *data = file->data;
|
||||
|
||||
return grub_squash_read_data (data, &data->ino,
|
||||
file->offset, buf, len);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_squash_close (grub_file_t file)
|
||||
{
|
||||
grub_free (file->data);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_squash_mtime (grub_device_t dev, grub_int32_t *tm)
|
||||
{
|
||||
struct grub_squash_data *data = 0;
|
||||
|
||||
data = squash_mount (dev->disk);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
*tm = grub_le_to_cpu32 (data->sb.creation_time);
|
||||
grub_free (data);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_fs grub_squash_fs =
|
||||
{
|
||||
.name = "squash4",
|
||||
.dir = grub_squash_dir,
|
||||
.open = grub_squash_open,
|
||||
.read = grub_squash_read,
|
||||
.close = grub_squash_close,
|
||||
.mtime = grub_squash_mtime,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 0,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(squash4)
|
||||
{
|
||||
grub_fs_register (&grub_squash_fs);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(squash4)
|
||||
{
|
||||
grub_fs_unregister (&grub_squash_fs);
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
#include <grub/charset.h>
|
||||
#include <grub/datetime.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_UDF_MAX_PDS 2
|
||||
#define GRUB_UDF_MAX_PMS 6
|
||||
|
@ -543,8 +546,7 @@ grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
}
|
||||
|
||||
fail:
|
||||
if (buf)
|
||||
grub_free (buf);
|
||||
grub_free (buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -788,6 +790,43 @@ fail:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
read_string (grub_uint8_t *raw, grub_size_t sz)
|
||||
{
|
||||
grub_uint16_t *utf16 = NULL;
|
||||
char *ret;
|
||||
grub_size_t utf16len = 0;
|
||||
|
||||
if (raw[0] != 8 && raw[0] != 16)
|
||||
return NULL;
|
||||
|
||||
if (raw[0] == 8)
|
||||
{
|
||||
unsigned i;
|
||||
utf16len = sz - 1;
|
||||
utf16 = grub_malloc (utf16len * sizeof (utf16[0]));
|
||||
if (!utf16)
|
||||
return NULL;
|
||||
for (i = 0; i < utf16len; i++)
|
||||
utf16[i] = raw[i + 1];
|
||||
}
|
||||
if (raw[0] == 16)
|
||||
{
|
||||
unsigned i;
|
||||
utf16len = (sz - 1) / 2;
|
||||
utf16 = grub_malloc (utf16len * sizeof (utf16[0]));
|
||||
if (!utf16)
|
||||
return NULL;
|
||||
for (i = 0; i < utf16len; i++)
|
||||
utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2];
|
||||
}
|
||||
ret = grub_malloc (utf16len * 3 + 1);
|
||||
if (ret)
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) ret, utf16, utf16len) = '\0';
|
||||
grub_free (utf16);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_udf_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
|
@ -841,13 +880,13 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
|
|||
else
|
||||
{
|
||||
enum grub_fshelp_filetype type;
|
||||
char *filename;
|
||||
grub_uint8_t raw[dirent.file_ident_length];
|
||||
grub_uint16_t utf16[dirent.file_ident_length - 1];
|
||||
grub_uint8_t filename[dirent.file_ident_length * 2];
|
||||
grub_size_t utf16len = 0;
|
||||
|
||||
type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ?
|
||||
(GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG));
|
||||
if (child->fe.icbtag.file_type == GRUB_UDF_ICBTAG_TYPE_SYMLINK)
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
|
||||
if ((grub_udf_read_file (dir, 0, offset,
|
||||
dirent.file_ident_length,
|
||||
|
@ -855,27 +894,16 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
|
|||
!= dirent.file_ident_length)
|
||||
return 0;
|
||||
|
||||
if (raw[0] == 8)
|
||||
{
|
||||
unsigned i;
|
||||
utf16len = dirent.file_ident_length - 1;
|
||||
for (i = 0; i < utf16len; i++)
|
||||
utf16[i] = raw[i + 1];
|
||||
}
|
||||
if (raw[0] == 16)
|
||||
{
|
||||
unsigned i;
|
||||
utf16len = (dirent.file_ident_length - 1) / 2;
|
||||
for (i = 0; i < utf16len; i++)
|
||||
utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2];
|
||||
}
|
||||
if (raw[0] == 8 || raw[0] == 16)
|
||||
{
|
||||
*grub_utf16_to_utf8 (filename, utf16, utf16len) = '\0';
|
||||
filename = read_string (raw, dirent.file_ident_length);
|
||||
if (!filename)
|
||||
grub_print_error ();
|
||||
|
||||
if (hook ((char *) filename, type, child))
|
||||
return 1;
|
||||
if (filename && hook (filename, type, child))
|
||||
{
|
||||
grub_free (filename);
|
||||
return 1;
|
||||
}
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -886,6 +914,25 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_ufs_read_symlink (grub_fshelp_node_t node)
|
||||
{
|
||||
grub_size_t sz = U64 (node->fe.file_size);
|
||||
grub_uint8_t *raw;
|
||||
char *ret;
|
||||
|
||||
if (sz < 4)
|
||||
return NULL;
|
||||
raw = grub_malloc (sz - 4);
|
||||
if (!raw)
|
||||
return NULL;
|
||||
if (grub_udf_read_file (node, NULL, 4, sz - 4, (char *) raw) < 0)
|
||||
return NULL;
|
||||
ret = read_string (raw, sz - 4);
|
||||
grub_free (raw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_udf_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
|
@ -904,8 +951,36 @@ grub_udf_dir (grub_device_t device, const char *path,
|
|||
grub_fshelp_node_t node)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
const struct grub_udf_timestamp *tstamp = NULL;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
if (U16 (node->fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE)
|
||||
tstamp = &node->fe.modification_time;
|
||||
else if (U16 (node->fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_EFE)
|
||||
tstamp = &node->efe.modification_time;
|
||||
|
||||
if (tstamp && (U16 (tstamp->type_and_timezone) & 0xf000) == 0x1000)
|
||||
{
|
||||
grub_int16_t tz;
|
||||
struct grub_datetime datetime;
|
||||
|
||||
datetime.year = U16 (tstamp->year);
|
||||
datetime.month = tstamp->month;
|
||||
datetime.day = tstamp->day;
|
||||
datetime.hour = tstamp->hour;
|
||||
datetime.minute = tstamp->minute;
|
||||
datetime.second = tstamp->second;
|
||||
|
||||
tz = U16 (tstamp->type_and_timezone) & 0xfff;
|
||||
if (tz & 0x800)
|
||||
tz |= 0xf000;
|
||||
if (tz == -2047)
|
||||
tz = 0;
|
||||
|
||||
info.mtimeset = !!grub_datetime2unixtime (&datetime, &info.mtime);
|
||||
|
||||
info.mtime -= 60 * tz;
|
||||
}
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
@ -921,7 +996,8 @@ grub_udf_dir (grub_device_t device, const char *path,
|
|||
|
||||
if (grub_fshelp_find_file (path, &rootnode,
|
||||
&foundnode,
|
||||
grub_udf_iterate_dir, 0, GRUB_FSHELP_DIR))
|
||||
grub_udf_iterate_dir, grub_ufs_read_symlink,
|
||||
GRUB_FSHELP_DIR))
|
||||
goto fail;
|
||||
|
||||
grub_udf_iterate_dir (foundnode, iterate);
|
||||
|
@ -955,7 +1031,8 @@ grub_udf_open (struct grub_file *file, const char *name)
|
|||
|
||||
if (grub_fshelp_find_file (name, &rootnode,
|
||||
&foundnode,
|
||||
grub_udf_iterate_dir, 0, GRUB_FSHELP_REG))
|
||||
grub_udf_iterate_dir, grub_ufs_read_symlink,
|
||||
GRUB_FSHELP_REG))
|
||||
goto fail;
|
||||
|
||||
file->data = foundnode;
|
||||
|
@ -1004,7 +1081,7 @@ grub_udf_label (grub_device_t device, char **label)
|
|||
|
||||
if (data)
|
||||
{
|
||||
*label = grub_strdup ((char *) &data->lvd.ident[1]);
|
||||
*label = read_string (data->lvd.ident, sizeof (data->lvd.ident));
|
||||
grub_free (data);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#ifdef MODE_UFS2
|
||||
#define GRUB_UFS_MAGIC 0x19540119
|
||||
#else
|
||||
|
@ -283,26 +285,29 @@ static grub_ssize_t
|
|||
grub_ufs_read_file (struct grub_ufs_data *data,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
struct grub_ufs_sblock *sblock = &data->sblock;
|
||||
int i;
|
||||
int blockcnt;
|
||||
grub_off_t i;
|
||||
grub_off_t blockcnt;
|
||||
|
||||
/* Adjust len so it we can't read past the end of the file. */
|
||||
if (len + pos > INODE_SIZE (data))
|
||||
len = INODE_SIZE (data) - pos;
|
||||
|
||||
blockcnt = (len + pos + UFS_BLKSZ (sblock) - 1) / UFS_BLKSZ (sblock);
|
||||
blockcnt = grub_divmod64 ((len + pos + UFS_BLKSZ (sblock) - 1),
|
||||
UFS_BLKSZ (sblock), 0);
|
||||
|
||||
for (i = pos / UFS_BLKSZ (sblock); i < blockcnt; i++)
|
||||
for (i = grub_divmod64 (pos, UFS_BLKSZ (sblock), 0); i < blockcnt; i++)
|
||||
{
|
||||
int blknr;
|
||||
int blockoff = pos % UFS_BLKSZ (sblock);
|
||||
int blockend = UFS_BLKSZ (sblock);
|
||||
grub_disk_addr_t blknr;
|
||||
grub_off_t blockoff;
|
||||
grub_off_t blockend = UFS_BLKSZ (sblock);
|
||||
|
||||
int skipfirst = 0;
|
||||
|
||||
grub_divmod64 (pos, UFS_BLKSZ (sblock), &blockoff);
|
||||
|
||||
blknr = grub_ufs_get_file_block (data, i);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
@ -310,14 +315,14 @@ grub_ufs_read_file (struct grub_ufs_data *data,
|
|||
/* Last block. */
|
||||
if (i == blockcnt - 1)
|
||||
{
|
||||
blockend = (len + pos) % UFS_BLKSZ (sblock);
|
||||
grub_divmod64 (len + pos, UFS_BLKSZ (sblock), &blockend);
|
||||
|
||||
if (!blockend)
|
||||
blockend = UFS_BLKSZ (sblock);
|
||||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == (pos / (int) UFS_BLKSZ (sblock)))
|
||||
if (i == grub_divmod64 (pos, UFS_BLKSZ (sblock), 0))
|
||||
{
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
|
@ -512,7 +517,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
|
|||
pos += grub_le_to_cpu16 (dirent.direntlen);
|
||||
} while (pos < INODE_SIZE (data));
|
||||
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define XFS_INODE_EXTENTS 9
|
||||
|
||||
#define XFS_INODE_FORMAT_INO 1
|
||||
|
@ -98,18 +100,29 @@ struct grub_xfs_btree_root
|
|||
grub_uint64_t keys[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_xfs_time
|
||||
{
|
||||
grub_uint32_t sec;
|
||||
grub_uint32_t nanosec;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_xfs_inode
|
||||
{
|
||||
grub_uint8_t magic[2];
|
||||
grub_uint16_t mode;
|
||||
grub_uint8_t version;
|
||||
grub_uint8_t format;
|
||||
grub_uint8_t unused2[50];
|
||||
grub_uint8_t unused2[26];
|
||||
struct grub_xfs_time atime;
|
||||
struct grub_xfs_time mtime;
|
||||
struct grub_xfs_time ctime;
|
||||
grub_uint64_t size;
|
||||
grub_uint64_t nblocks;
|
||||
grub_uint32_t extsize;
|
||||
grub_uint32_t nextents;
|
||||
grub_uint8_t unused3[20];
|
||||
grub_uint16_t unused3;
|
||||
grub_uint8_t fork_offset;
|
||||
grub_uint8_t unused4[17];
|
||||
union
|
||||
{
|
||||
char raw[156];
|
||||
|
@ -143,7 +156,7 @@ struct grub_xfs_data
|
|||
grub_disk_t disk;
|
||||
int pos;
|
||||
int bsize;
|
||||
int agsize;
|
||||
grub_uint32_t agsize;
|
||||
struct grub_fshelp_node diropen;
|
||||
};
|
||||
|
||||
|
@ -157,33 +170,67 @@ static grub_dl_t my_mod;
|
|||
#define FILETYPE_INO_DIRECTORY 0040000
|
||||
#define FILETYPE_INO_SYMLINK 0120000
|
||||
|
||||
#define GRUB_XFS_INO_AGBITS(data) \
|
||||
((data)->sblock.log2_agblk + (data)->sblock.log2_inop)
|
||||
#define GRUB_XFS_INO_INOINAG(data, ino) \
|
||||
(grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1))
|
||||
#define GRUB_XFS_INO_AG(data,ino) \
|
||||
(grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data))
|
||||
static inline int
|
||||
GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data)
|
||||
{
|
||||
return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop);
|
||||
}
|
||||
|
||||
#define GRUB_XFS_FSB_TO_BLOCK(data, fsb) \
|
||||
(((fsb) >> (data)->sblock.log2_agblk) * (data)->agsize \
|
||||
+ ((fsb) & ((1LL << (data)->sblock.log2_agblk) - 1)))
|
||||
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));
|
||||
}
|
||||
|
||||
#define GRUB_XFS_EXTENT_OFFSET(exts,ex) \
|
||||
((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 \
|
||||
| grub_be_to_cpu32 (exts[ex][1]) >> 9)
|
||||
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));
|
||||
}
|
||||
|
||||
#define GRUB_XFS_EXTENT_BLOCK(exts,ex) \
|
||||
((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) \
|
||||
& (0x1ff)) << 43 \
|
||||
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 \
|
||||
| grub_be_to_cpu32 (exts[ex][3]) >> 21)
|
||||
static inline grub_disk_addr_t
|
||||
GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb)
|
||||
{
|
||||
return ((fsb >> data->sblock.log2_agblk) * data->agsize
|
||||
+ (fsb & ((1LL << data->sblock.log2_agblk) - 1)));
|
||||
}
|
||||
|
||||
#define GRUB_XFS_EXTENT_SIZE(exts,ex) \
|
||||
(grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1))
|
||||
static inline grub_uint64_t
|
||||
GRUB_XFS_EXTENT_OFFSET (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);
|
||||
}
|
||||
|
||||
static inline grub_uint64_t
|
||||
GRUB_XFS_EXTENT_BLOCK (grub_xfs_extent *exts, int ex)
|
||||
{
|
||||
return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1])
|
||||
& (0x1ff)) << 43
|
||||
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11
|
||||
| grub_be_to_cpu32 (exts[ex][3]) >> 21);
|
||||
}
|
||||
|
||||
static inline grub_uint64_t
|
||||
GRUB_XFS_EXTENT_SIZE (grub_xfs_extent *exts, int ex)
|
||||
{
|
||||
return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 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);
|
||||
}
|
||||
|
||||
#define GRUB_XFS_ROUND_TO_DIRENT(pos) ((((pos) + 8 - 1) / 8) * 8)
|
||||
#define GRUB_XFS_NEXT_DIRENT(pos,len) \
|
||||
(pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2)
|
||||
|
||||
static inline grub_uint64_t
|
||||
grub_xfs_inode_block (struct grub_xfs_data *data,
|
||||
|
@ -239,13 +286,23 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
if (node->inode.format == XFS_INODE_FORMAT_BTREE)
|
||||
{
|
||||
grub_uint64_t *keys;
|
||||
int recoffset;
|
||||
|
||||
leaf = grub_malloc (node->data->sblock.bsize);
|
||||
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];
|
||||
if (node->inode.fork_offset)
|
||||
recoffset = (node->inode.fork_offset
|
||||
- ((char *) &node->inode.data.btree.keys - (char *) &node->inode))
|
||||
/ (2 * sizeof (grub_uint64_t));
|
||||
else
|
||||
recoffset = ((1 << node->data->sblock.log2_inode)
|
||||
- ((char *) &node->inode.data.btree.keys
|
||||
- (char *) &node->inode))
|
||||
/ (2 * sizeof (grub_uint64_t));
|
||||
do
|
||||
{
|
||||
int i;
|
||||
|
@ -262,12 +319,9 @@ 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_be_to_cpu64 (keys[i - 1 + nrec])
|
||||
<< (node->data->sblock.log2_bsize
|
||||
- GRUB_DISK_SECTOR_BITS),
|
||||
0, node->data->sblock.bsize, leaf))
|
||||
GRUB_XFS_FSB_TO_BLOCK (node->data, grub_be_to_cpu64 (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))
|
||||
|
@ -279,7 +333,11 @@ 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];
|
||||
} while (leaf->level);
|
||||
recoffset = ((node->data->bsize - ((char *) &leaf->keys
|
||||
- (char *) leaf))
|
||||
/ (2 * sizeof (grub_uint64_t)));
|
||||
}
|
||||
while (leaf->level);
|
||||
exts = (grub_xfs_extent *) keys;
|
||||
}
|
||||
else if (node->inode.format == XFS_INODE_FORMAT_EXT)
|
||||
|
@ -313,8 +371,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
}
|
||||
}
|
||||
|
||||
if (leaf)
|
||||
grub_free (leaf);
|
||||
grub_free (leaf);
|
||||
|
||||
return GRUB_XFS_FSB_TO_BLOCK(node->data, ret);
|
||||
}
|
||||
|
@ -326,7 +383,7 @@ static grub_ssize_t
|
|||
grub_xfs_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_xfs_read_block,
|
||||
|
@ -451,18 +508,27 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
|
|||
for (i = 0; i < diro->inode.data.dir.dirhead.count; i++)
|
||||
{
|
||||
grub_uint64_t ino;
|
||||
void *inopos = (((char *) de)
|
||||
grub_uint8_t *inopos = (((grub_uint8_t *) de)
|
||||
+ sizeof (struct grub_xfs_dir_entry)
|
||||
+ de->len - 1);
|
||||
char name[de->len + 1];
|
||||
|
||||
/* inopos might be unaligned. */
|
||||
if (smallino)
|
||||
{
|
||||
ino = grub_be_to_cpu32 (*(grub_uint32_t *) inopos);
|
||||
ino = grub_cpu_to_be64 (ino);
|
||||
}
|
||||
ino = (((grub_uint32_t) inopos[0]) << 24)
|
||||
| (((grub_uint32_t) inopos[1]) << 16)
|
||||
| (((grub_uint32_t) inopos[2]) << 8)
|
||||
| (((grub_uint32_t) inopos[3]) << 0);
|
||||
else
|
||||
ino = *(grub_uint64_t *) inopos;
|
||||
ino = (((grub_uint64_t) inopos[0]) << 56)
|
||||
| (((grub_uint64_t) inopos[1]) << 48)
|
||||
| (((grub_uint64_t) inopos[2]) << 40)
|
||||
| (((grub_uint64_t) inopos[3]) << 32)
|
||||
| (((grub_uint64_t) inopos[4]) << 24)
|
||||
| (((grub_uint64_t) inopos[5]) << 16)
|
||||
| (((grub_uint64_t) inopos[6]) << 8)
|
||||
| (((grub_uint64_t) inopos[7]) << 0);
|
||||
ino = grub_cpu_to_be64 (ino);
|
||||
|
||||
grub_memcpy (name, de->name, de->len);
|
||||
name[de->len] = '\0';
|
||||
|
@ -643,6 +709,11 @@ grub_xfs_dir (grub_device_t device, const char *path,
|
|||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
if (node->inode_read)
|
||||
{
|
||||
info.mtimeset = 1;
|
||||
info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec);
|
||||
}
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
|
@ -808,6 +879,9 @@ static struct grub_fs grub_xfs_fs =
|
|||
.close = grub_xfs_close,
|
||||
.label = grub_xfs_label,
|
||||
.uuid = grub_xfs_uuid,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 0,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#include <grub/zfs/dsl_dataset.h>
|
||||
#include <grub/deflate.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define ZPOOL_PROP_BOOTFS "bootfs"
|
||||
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
@ -196,7 +198,7 @@ zlib_decompress (void *s, void *d,
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
|
||||
static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
|
||||
{"inherit", NULL}, /* ZIO_COMPRESS_INHERIT */
|
||||
{"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */
|
||||
{"off", NULL}, /* ZIO_COMPRESS_OFF */
|
||||
|
@ -244,7 +246,7 @@ zio_checksum_off (const void *buf __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
/* Checksum Table and Values */
|
||||
zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
|
||||
static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
|
||||
{NULL, 0, 0, "inherit"},
|
||||
{NULL, 0, 0, "on"},
|
||||
{zio_checksum_off, 0, 0, "off"},
|
||||
|
@ -265,7 +267,7 @@ zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
|
|||
*/
|
||||
static grub_err_t
|
||||
zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
|
||||
grub_zfs_endian_t endian, char *buf, int size)
|
||||
grub_zfs_endian_t endian, char *buf, grub_size_t size)
|
||||
{
|
||||
zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
|
||||
zio_checksum_info_t *ci = &zio_checksum_table[checksum];
|
||||
|
@ -360,7 +362,7 @@ vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2)
|
|||
*
|
||||
*/
|
||||
static grub_err_t
|
||||
uberblock_verify (uberblock_phys_t * ub, int offset)
|
||||
uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset)
|
||||
{
|
||||
uberblock_t *uber = &ub->ubp_uberblock;
|
||||
grub_err_t err;
|
||||
|
@ -890,7 +892,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
|
|||
{
|
||||
grub_size_t csize;
|
||||
grub_uint64_t high;
|
||||
grub_uint32_t devn;
|
||||
grub_uint64_t devn;
|
||||
grub_err_t err;
|
||||
high = grub_divmod64 (sector + (asize > 2) + c, desc->n_children,
|
||||
&devn);
|
||||
|
@ -898,7 +900,8 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
|
|||
if (csize > len)
|
||||
csize = len;
|
||||
grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T
|
||||
"+%d+%u -> (0x%" PRIxGRUB_UINT64_T ", 0x%x)\n",
|
||||
"+%d+%u -> (0x%" PRIxGRUB_UINT64_T ", 0x%"
|
||||
PRIxGRUB_UINT64_T ")\n",
|
||||
sector,(asize > 2), c, high, devn);
|
||||
err = read_device (high << 9, &desc->children[devn],
|
||||
bsize, csize, buf);
|
||||
|
@ -1133,10 +1136,12 @@ static grub_err_t
|
|||
dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
|
||||
grub_zfs_endian_t *endian_out, struct grub_zfs_data *data)
|
||||
{
|
||||
int idx, level;
|
||||
int level;
|
||||
grub_off_t idx;
|
||||
blkptr_t *bp_array = dn->dn.dn_blkptr;
|
||||
int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT;
|
||||
blkptr_t *bp, *tmpbuf = 0;
|
||||
blkptr_t *bp;
|
||||
void *tmpbuf = 0;
|
||||
grub_zfs_endian_t endian;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
|
||||
|
@ -1179,7 +1184,7 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
|
|||
break;
|
||||
}
|
||||
grub_dprintf ("zfs", "endian = %d\n", endian);
|
||||
err = zio_read (bp, endian, (void **) &tmpbuf, 0, data);
|
||||
err = zio_read (bp, endian, &tmpbuf, 0, data);
|
||||
endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
|
||||
if (err)
|
||||
break;
|
||||
|
@ -1369,7 +1374,6 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
|
|||
name))
|
||||
{
|
||||
struct zap_leaf_array *la;
|
||||
grub_uint8_t *ip;
|
||||
|
||||
if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length,
|
||||
endian) != 1)
|
||||
|
@ -1377,7 +1381,6 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
|
|||
|
||||
/* get the uint64_t property value */
|
||||
la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk).l_array;
|
||||
ip = la->la_array;
|
||||
|
||||
*value = grub_be_to_cpu64 (la->la_array64);
|
||||
|
||||
|
@ -1414,7 +1417,7 @@ static grub_err_t
|
|||
fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
||||
char *name, grub_uint64_t * value, struct grub_zfs_data *data)
|
||||
{
|
||||
zap_leaf_phys_t *l;
|
||||
void *l;
|
||||
grub_uint64_t hash, idx, blkid;
|
||||
int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
|
||||
zap_dnode->endian) << DNODE_SHIFT);
|
||||
|
@ -1437,7 +1440,7 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
|||
/* Get the leaf block */
|
||||
if ((1U << blksft) < sizeof (zap_leaf_phys_t))
|
||||
return grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
|
||||
err = dmu_read (zap_dnode, blkid, (void **) &l, &leafendian, data);
|
||||
err = dmu_read (zap_dnode, blkid, &l, &leafendian, data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -1454,7 +1457,8 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
|||
struct grub_zfs_data *data)
|
||||
{
|
||||
zap_leaf_phys_t *l;
|
||||
grub_uint64_t idx, blkid;
|
||||
void *l_in;
|
||||
grub_uint64_t idx, idx2, blkid;
|
||||
grub_uint16_t chunk;
|
||||
int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
|
||||
zap_dnode->endian) << DNODE_SHIFT);
|
||||
|
@ -1477,13 +1481,19 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
|
|||
grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
|
||||
return 0;
|
||||
}
|
||||
for (idx = 0; idx < grub_zfs_to_cpu64 (zap->zap_num_leafs,
|
||||
zap_dnode->endian); idx++)
|
||||
for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++)
|
||||
{
|
||||
blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))],
|
||||
zap_dnode->endian);
|
||||
|
||||
err = dmu_read (zap_dnode, blkid, (void **) &l, &endian, data);
|
||||
for (idx2 = 0; idx2 < idx; idx2++)
|
||||
if (blkid == ((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))])
|
||||
break;
|
||||
if (idx2 != idx)
|
||||
continue;
|
||||
|
||||
err = dmu_read (zap_dnode, blkid, &l_in, &endian, data);
|
||||
l = l_in;
|
||||
if (err)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
@ -1612,7 +1622,7 @@ zap_iterate (dnode_end_t * zap_dnode,
|
|||
return 0;
|
||||
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
|
||||
|
||||
grub_dprintf ("zfs", "zap read\n");
|
||||
grub_dprintf ("zfs", "zap iterate\n");
|
||||
|
||||
if (block_type == ZBT_MICRO)
|
||||
{
|
||||
|
@ -1649,7 +1659,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
|||
grub_uint64_t blkid, blksz; /* the block id this object dnode is in */
|
||||
int epbs; /* shift of number of dnodes in a block */
|
||||
int idx; /* index within a block */
|
||||
dnode_phys_t *dnbuf;
|
||||
void *dnbuf;
|
||||
grub_err_t err;
|
||||
grub_zfs_endian_t endian;
|
||||
|
||||
|
@ -1672,7 +1682,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
|||
|
||||
grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian,
|
||||
(unsigned long long) blkid);
|
||||
err = dmu_read (mdn, blkid, (void **) &dnbuf, &endian, data);
|
||||
err = dmu_read (mdn, blkid, &dnbuf, &endian, data);
|
||||
if (err)
|
||||
return err;
|
||||
grub_dprintf ("zfs", "alive\n");
|
||||
|
@ -1694,7 +1704,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
|||
data->dnode_endian = endian;
|
||||
}
|
||||
|
||||
grub_memmove (&(buf->dn), &dnbuf[idx], DNODE_SIZE);
|
||||
grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE);
|
||||
buf->endian = endian;
|
||||
if (type && buf->dn.dn_type != type)
|
||||
return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
|
||||
|
@ -1831,52 +1841,53 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
|
|||
*path = ch;
|
||||
if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
|
||||
{
|
||||
char *sym_value;
|
||||
grub_size_t avail_in_dnode;
|
||||
grub_size_t sym_sz;
|
||||
int free_symval = 0;
|
||||
char *oldpath = path, *oldpathbuf = path_buf;
|
||||
grub_size_t bonuslen;
|
||||
bonuslen = (grub_uint8_t *) (&dnode_path->dn.dn + 1)
|
||||
- (grub_uint8_t *) DN_BONUS (&dnode_path->dn.dn);
|
||||
if (bonuslen <= sizeof (znode_phys_t))
|
||||
err = grub_error (GRUB_ERR_BAD_FS,
|
||||
"incorrect or unsupported symlink");
|
||||
if (dnode_path->dn.dn.dn_flags & 1)
|
||||
{
|
||||
void *sbuf;
|
||||
grub_size_t ssize;
|
||||
err = zio_read (dnode_path->dn.dn.dn_blkptr,
|
||||
dnode_path->dn.endian, &sbuf,
|
||||
&ssize, data);
|
||||
if (err)
|
||||
{
|
||||
grub_free (oldpathbuf);
|
||||
return err;
|
||||
}
|
||||
sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys));
|
||||
avail_in_dnode = (char *) (&dnode_path->dn + 1) - sym_value;
|
||||
|
||||
path = path_buf = grub_malloc (ssize+ grub_strlen (oldpath) + 1);
|
||||
if (!path_buf)
|
||||
{
|
||||
grub_free (oldpathbuf);
|
||||
grub_free (sbuf);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_memcpy (path, sbuf, ssize);
|
||||
path[ssize] = 0;
|
||||
grub_free (sbuf);
|
||||
}
|
||||
else
|
||||
sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian);
|
||||
|
||||
if (sym_sz > avail_in_dnode - 8)
|
||||
{
|
||||
path = path_buf
|
||||
= grub_malloc (bonuslen - sizeof (znode_phys_t)
|
||||
+ grub_strlen (oldpath) + 1);
|
||||
if (!path_buf)
|
||||
grub_size_t block;
|
||||
grub_size_t blksz;
|
||||
blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec,
|
||||
dnode_path->dn.endian)
|
||||
<< SPA_MINBLOCKSHIFT);
|
||||
|
||||
sym_value = grub_malloc (sym_sz);
|
||||
if (!sym_value)
|
||||
return grub_errno;
|
||||
for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
|
||||
{
|
||||
grub_free (oldpathbuf);
|
||||
return grub_errno;
|
||||
void *t;
|
||||
grub_size_t movesize;
|
||||
|
||||
err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
movesize = MIN (sym_sz - block * blksz, blksz);
|
||||
|
||||
grub_memcpy (sym_value + block * blksz, t, movesize);
|
||||
grub_free (t);
|
||||
}
|
||||
grub_memcpy (path, (char *) DN_BONUS(&dnode_path->dn.dn)
|
||||
+ sizeof (znode_phys_t),
|
||||
bonuslen - sizeof (znode_phys_t));
|
||||
path[bonuslen - sizeof (znode_phys_t)] = 0;
|
||||
free_symval = 1;
|
||||
}
|
||||
path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
|
||||
if (!path_buf)
|
||||
{
|
||||
grub_free (oldpathbuf);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_memcpy (path, sym_value, sym_sz);
|
||||
if (free_symval)
|
||||
grub_free (sym_value);
|
||||
path [sym_sz] = 0;
|
||||
grub_memcpy (path + grub_strlen (path), oldpath,
|
||||
grub_strlen (oldpath) + 1);
|
||||
|
||||
|
@ -2037,7 +2048,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
|
|||
static grub_err_t
|
||||
make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
|
||||
{
|
||||
objset_phys_t *osp;
|
||||
void *osp;
|
||||
blkptr_t *bp;
|
||||
grub_size_t ospsize;
|
||||
grub_err_t err;
|
||||
|
@ -2045,7 +2056,7 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
|
|||
grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
|
||||
|
||||
bp = &(((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_bp);
|
||||
err = zio_read (bp, mdn->endian, (void **) &osp, &ospsize, data);
|
||||
err = zio_read (bp, mdn->endian, &osp, &ospsize, data);
|
||||
if (err)
|
||||
return err;
|
||||
if (ospsize < OBJSET_PHYS_SIZE_V14)
|
||||
|
@ -2055,7 +2066,8 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
|
|||
}
|
||||
|
||||
mdn->endian = (grub_zfs_to_cpu64 (bp->blk_prop, mdn->endian)>>63) & 1;
|
||||
grub_memmove ((char *) &(mdn->dn), (char *) &osp->os_meta_dnode, DNODE_SIZE);
|
||||
grub_memmove ((char *) &(mdn->dn),
|
||||
(char *) &((objset_phys_t *) osp)->os_meta_dnode, DNODE_SIZE);
|
||||
grub_free (osp);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -2633,7 +2645,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
|
|||
*/
|
||||
if (data->dnode.dn.dn_bonustype == DMU_OT_SA)
|
||||
{
|
||||
sa_hdr_phys_t *sahdrp;
|
||||
void *sahdrp;
|
||||
int hdrsize;
|
||||
|
||||
if (data->dnode.dn.dn_bonuslen != 0)
|
||||
|
@ -2644,7 +2656,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
|
|||
{
|
||||
blkptr_t *bp = &data->dnode.dn.dn_spill;
|
||||
|
||||
err = zio_read (bp, data->dnode.endian, (void **) &sahdrp, NULL, data);
|
||||
err = zio_read (bp, data->dnode.endian, &sahdrp, NULL, data);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -2653,7 +2665,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
|
|||
return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
|
||||
}
|
||||
|
||||
hdrsize = SA_HDR_SIZE (sahdrp);
|
||||
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
|
||||
file->size = *(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET);
|
||||
}
|
||||
else
|
||||
|
@ -2675,7 +2687,7 @@ static grub_ssize_t
|
|||
grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_zfs_data *data = (struct grub_zfs_data *) file->data;
|
||||
int blksz, movesize;
|
||||
grub_size_t blksz, movesize;
|
||||
grub_size_t length;
|
||||
grub_size_t read;
|
||||
grub_err_t err;
|
||||
|
@ -2712,6 +2724,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
read = 0;
|
||||
while (length)
|
||||
{
|
||||
void *t;
|
||||
/*
|
||||
* Find requested blkid and the offset within that block.
|
||||
*/
|
||||
|
@ -2719,15 +2732,16 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
grub_free (data->file_buf);
|
||||
data->file_buf = 0;
|
||||
|
||||
err = dmu_read (&(data->dnode), blkid, (void **) &(data->file_buf),
|
||||
err = dmu_read (&(data->dnode), blkid, &t,
|
||||
0, data);
|
||||
data->file_buf = t;
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
data->file_start = blkid * blksz;
|
||||
data->file_end = data->file_start + blksz;
|
||||
|
||||
movesize = MIN (length, data->file_end - (int) file->offset - read);
|
||||
movesize = MIN (length, data->file_end - file->offset - read);
|
||||
|
||||
grub_memmove (buf, data->file_buf + file->offset + read
|
||||
- data->file_start, movesize);
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static inline void
|
||||
print_tabs (int n)
|
||||
{
|
||||
|
@ -364,21 +366,16 @@ grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc,
|
|||
grub_free (nv);
|
||||
grub_free (nvlist);
|
||||
|
||||
if (bootpath && devid)
|
||||
{
|
||||
bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu bootpath=%s diskdevid=%s",
|
||||
poolname, (unsigned long long) mdnobj,
|
||||
bootpath, devid);
|
||||
if (!bootfs)
|
||||
return grub_errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu",
|
||||
poolname, (unsigned long long) mdnobj);
|
||||
if (!bootfs)
|
||||
return grub_errno;
|
||||
}
|
||||
bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s",
|
||||
poolname, (unsigned long long) mdnobj,
|
||||
bootpath ? ",bootpath=\"" : "",
|
||||
bootpath ? : "",
|
||||
bootpath ? "\"" : "",
|
||||
devid ? ",diskdevid=\"" : "",
|
||||
devid ? : "",
|
||||
devid ? "\"" : "");
|
||||
if (!bootfs)
|
||||
return grub_errno;
|
||||
if (argc >= 2)
|
||||
grub_env_set (args[1], bootfs);
|
||||
else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue