Merge Mainline.

This commit is contained in:
Manoel R. Abranches 2011-05-27 00:23:33 -03:00
commit 85fd555441
191 changed files with 9311 additions and 1208 deletions

View file

@ -52,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];
@ -87,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. */
@ -117,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. */
@ -156,7 +164,7 @@ grub_affs_read_file (grub_fshelp_node_t node,
{
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);
}
@ -168,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));
@ -218,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;
@ -228,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;
@ -243,6 +248,8 @@ grub_affs_mount (grub_disk_t disk)
data->htsize = grub_be_to_cpu32 (rblock->htsize);
data->diropen.data = data;
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);
@ -293,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)
{
@ -306,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))
{
@ -319,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;
@ -328,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])
@ -358,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);
@ -403,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);
@ -467,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);
}

View file

@ -589,10 +589,14 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
struct grub_btrfs_key *key;
struct grub_btrfs_chunk_item *chunk;
grub_uint64_t csize;
grub_err_t err;
grub_err_t err = 0;
struct grub_btrfs_key key_out;
int challoc = 0;
grub_device_t dev;
struct grub_btrfs_key key_in;
grub_size_t chsize;
grub_disk_addr_t chaddr;
grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T "\n",
addr);
for (ptr = data->sblock.bootstrap_mapping;
@ -616,9 +620,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
+ sizeof (struct grub_btrfs_chunk_stripe)
* grub_le_to_cpu16 (chunk->nstripes);
}
struct grub_btrfs_key key_in;
grub_size_t chsize;
grub_disk_addr_t chaddr;
key_in.object_id = GRUB_BTRFS_OBJECT_ID_CHUNK;
key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK;
key_in.offset = addr;
@ -647,7 +649,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
chunk_found:
{
grub_uint32_t stripen;
grub_uint64_t stripen;
grub_uint64_t stripe_offset;
grub_uint64_t off = addr - grub_le_to_cpu64 (key->offset);
unsigned redundancy = 1;
@ -677,10 +679,10 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
{
grub_uint64_t stripe_length;
grub_dprintf ("btrfs", "single\n");
stripe_length = grub_divmod64_full (grub_le_to_cpu64 (chunk->size),
grub_le_to_cpu16 (chunk->nstripes),
NULL);
stripen = grub_divmod64_full (off, stripe_length, &stripe_offset);
stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size),
grub_le_to_cpu16 (chunk->nstripes),
NULL);
stripen = grub_divmod64 (off, stripe_length, &stripe_offset);
csize = (stripen + 1) * stripe_length - off;
break;
}
@ -697,7 +699,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
case GRUB_BTRFS_CHUNK_TYPE_RAID0:
{
grub_uint64_t middle, high;
grub_uint32_t low;
grub_uint64_t low;
grub_dprintf ("btrfs", "RAID0\n");
middle = grub_divmod64 (off,
grub_le_to_cpu64 (chunk->stripe_length),
@ -713,7 +715,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
case GRUB_BTRFS_CHUNK_TYPE_RAID10:
{
grub_uint64_t middle, high;
grub_uint32_t low;
grub_uint64_t low;
middle = grub_divmod64 (off,
grub_le_to_cpu64 (chunk->stripe_length),
&low);
@ -758,7 +760,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
"+0x%" PRIxGRUB_UINT64_T " (%d stripes (%d substripes) of %"
PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT32_T
PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT64_T
" maps to 0x%" PRIxGRUB_UINT64_T "\n",
grub_le_to_cpu64 (key->offset),
grub_le_to_cpu64 (chunk->size),

View file

@ -80,7 +80,7 @@ static grub_dl_t my_mod;
static grub_err_t
grub_cpio_find_file (struct grub_cpio_data *data, char **name,
grub_uint32_t * ofs)
grub_int32_t *mtime, grub_uint32_t * ofs)
{
#ifndef MODE_USTAR
struct head hd;
@ -93,6 +93,8 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
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++;
@ -141,6 +143,8 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
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);
#endif
return GRUB_ERR_NONE;
}
@ -206,7 +210,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)
@ -229,6 +235,8 @@ grub_cpio_dir (grub_device_t device, const char *path,
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)
@ -271,7 +279,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)

View file

@ -26,6 +26,7 @@
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/charset.h>
#include <grub/fat.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -51,52 +52,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
| GRUB_FAT_ATTR_ARCHIVE \
| GRUB_FAT_ATTR_VOLUME_ID)
struct grub_fat_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 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;
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 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;
} __attribute__ ((packed));
struct grub_fat_dir_entry
{
grub_uint8_t name[11];

View file

@ -133,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. */
@ -144,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. */
@ -953,19 +957,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;
}
@ -1074,6 +1088,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)
{
@ -1109,6 +1139,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
};

View file

@ -27,6 +27,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/charset.h>
#include <grub/datetime.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -55,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
{
@ -64,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;
@ -146,6 +158,7 @@ struct grub_iso9660_data
struct grub_fshelp_node
{
struct grub_iso9660_data *data;
struct grub_iso9660_dir dirent;
unsigned int size;
unsigned int blk;
unsigned int dir_blk;
@ -155,6 +168,52 @@ struct grub_fshelp_node
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;
}
/* 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. */
@ -366,7 +425,6 @@ 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;
@ -444,13 +502,10 @@ grub_iso9660_read_symlink (grub_fshelp_node_t node)
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)
sua_off = (sizeof (node->dirent) + node->dirent.namelen + 1
- (node->dirent.namelen % 2)
+ node->data->susp_skip);
sua_size = dirent.len - sua_off;
sua_size = node->dirent.len - sua_off;
symlink = grub_malloc (1);
if (!symlink)
@ -647,6 +702,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
filename_alloc = 1;
}
node->dirent = dirent;
if (hook (filename, type, node))
{
if (filename_alloc)
@ -685,6 +741,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->dirent.mtime, &info.mtime);
grub_free (node);
return hook (filename, &info);
}
@ -882,6 +940,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 =
@ -893,6 +977,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
};

View file

@ -155,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;
@ -164,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
@ -760,6 +769,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;
}

View file

@ -27,14 +27,17 @@
GRUB_MOD_LICENSE ("GPLv3+");
#ifdef MODE_MINIX2
#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
@ -43,7 +46,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#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
@ -52,6 +55,13 @@ 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_MODE(data) (grub_le_to_cpu16 (data->inode.mode))
@ -62,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;
@ -78,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;
@ -111,6 +135,19 @@ struct grub_minix_inode
grub_uint32_t unused;
};
#else
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;
};
#endif
@ -123,6 +160,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;
@ -133,7 +171,6 @@ static grub_err_t grub_minix_find_file (struct grub_minix_data *data,
static int
grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
{
struct grub_minix_sblock *sblock = &data->sblock;
int indir;
auto int grub_get_indir (int, int);
@ -143,18 +180,18 @@ grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
{
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;
blk -= GRUB_MINIX_INODE_DIR_BLOCKS;
if (blk < GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data))
{
indir = grub_get_indir (GRUB_MINIX_INODE_INDIR_ZONE (data), blk);
@ -187,25 +224,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)
@ -214,28 +252,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;
@ -250,16 +288,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))
@ -335,7 +370,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)
@ -355,7 +390,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)
@ -411,20 +446,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");
@ -460,7 +510,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;
@ -476,12 +526,22 @@ 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;
#ifndef MODE_MINIX2
info.mtime = grub_le_to_cpu32 (data->inode.ctime);
#else
info.mtime = grub_le_to_cpu32 (data->inode.mtime);
#endif
if (hook (filename, &info) ? 1 : 0)
break;
@ -558,7 +618,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",
@ -570,7 +632,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)
@ -580,7 +644,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
View file

@ -0,0 +1,2 @@
#define MODE_MINIX3 1
#include "minix.c"

View file

@ -303,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);
@ -368,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);
}
@ -577,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,
@ -641,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));
@ -679,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));

View file

@ -431,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);
@ -612,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)
@ -882,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);
}

View file

@ -224,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;
};
@ -870,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;
@ -916,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;
@ -1278,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);
}

458
grub-core/fs/romfs.c Normal file
View file

@ -0,0 +1,458 @@
/*
* 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>
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;
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);
}

View file

@ -68,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];
@ -121,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. */
@ -357,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)
@ -369,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);
}
@ -428,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;
@ -527,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);
}

548
grub-core/fs/squash4.c Normal file
View file

@ -0,0 +1,548 @@
/* 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 unk3 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 dummy2;
grub_uint64_t dummy3;
grub_uint8_t flags;
#define SQUASH_FLAG_UNCOMPRESSED_INODES 1
#define SQUASH_FLAG_UNCOMPRESSED_DATA 2
#define SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS 8
grub_uint8_t dummy4[7];
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;
} __attribute__ ((packed)) 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));
/* 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;
#define SQUASH_TYPE_DIR 1
#define SQUASH_TYPE_REGULAR 2
#define SQUASH_TYPE_SYMLINK 3
/* Actually the value is the length of name - 1. */
grub_uint16_t namelen;
char name[0];
} __attribute__ ((packed));
struct grub_squash_frag_desc
{
grub_uint64_t offset;
grub_uint64_t dummy;
} __attribute__ ((packed));
#define SQUASH_CHUNK_SIZE 0x2000
#define SQUASH_CHUNK_FLAGS 0x8000
#define SQUASH_CHUNK_UNCOMPRESSED 0x8000
struct grub_squash_data
{
grub_disk_t disk;
struct grub_squash_super sb;
struct grub_squash_inode ino;
grub_uint64_t fragments;
};
struct grub_fshelp_node
{
struct grub_squash_data *data;
struct grub_squash_inode ino;
grub_uint32_t ino_chunk;
grub_uint16_t ino_offset;
};
static grub_err_t
read_chunk (grub_disk_t disk, 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 (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 (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 (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_cpu32 (sb.unk1offset)
>> GRUB_DISK_SECTOR_BITS,
grub_le_to_cpu32 (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 = 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->disk, 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->disk, &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->disk, &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->disk, &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->disk, 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->disk, &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 = fdiro->ino;
file->size = grub_le_to_cpu32 (fdiro->ino.file.size);
return GRUB_ERR_NONE;
}
static grub_ssize_t
grub_squash_read_data (struct grub_squash_data *data,
grub_disk_t disk, const struct grub_squash_inode *ino,
grub_off_t off, char *buf, grub_size_t len)
{
grub_err_t err;
grub_uint64_t a, b;
int compressed = 0;
if (grub_le_to_cpu16 (ino->file.fragment) == 0xffff)
{
if (grub_le_to_cpu32 (ino->file.chunk))
a = grub_le_to_cpu32 (ino->file.chunk);
else
a = sizeof (struct grub_squash_super);
compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_DATA);
}
else
{
struct grub_squash_frag_desc frag;
err = read_chunk (disk, &frag, sizeof (frag),
data->fragments, sizeof (frag)
* grub_le_to_cpu16 (ino->file.fragment));
if (err)
return -1;
a = grub_le_to_cpu64 (frag.offset) + grub_le_to_cpu32 (ino->file.chunk);
compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS);
}
b = grub_le_to_cpu32 (data->ino.file.offset) + off;
/* FIXME: cache uncompressed chunks. */
if (compressed)
err = grub_zlib_disk_read (disk, a, b, buf, len);
else
err = grub_disk_read (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, file->device->disk, &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);
}

View file

@ -26,6 +26,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/charset.h>
#include <grub/datetime.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -885,6 +886,8 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
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,
@ -912,6 +915,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,
@ -930,8 +952,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);
}
@ -947,7 +997,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);
@ -981,7 +1032,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;

View file

@ -100,13 +100,22 @@ 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;
@ -654,6 +663,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);