Fix symlink handling on iso9660.

* grub-core/fs/iso9660.c (grub_fshelp_node): Remove dir_off. Add symlink
	All users updated.
	(grub_iso9660_susp_iterate): Accept zero-size iterate.
	(grub_iso9660_read_symlink): Moved most of code ...
	(grub_iso9660_iterate_dir): ... here. Fill node->symlink.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-10-25 21:52:48 +02:00
parent db82136381
commit 66b4085033
2 changed files with 90 additions and 102 deletions

View file

@ -1,3 +1,13 @@
2011-10-25 Vladimir Serbinenko <phcoder@gmail.com>
Fix symlink handling on iso9660.
* grub-core/fs/iso9660.c (grub_fshelp_node): Remove dir_off. Add symlink
All users updated.
(grub_iso9660_susp_iterate): Accept zero-size iterate.
(grub_iso9660_read_symlink): Moved most of code ...
(grub_iso9660_iterate_dir): ... here. Fill node->symlink.
2011-10-25 Vladimir Serbinenko <phcoder@gmail.com> 2011-10-25 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/loader/i386/bsd.c (grub_netbsd_add_boot_disk_and_wedge): * grub-core/loader/i386/bsd.c (grub_netbsd_add_boot_disk_and_wedge):

View file

@ -159,7 +159,7 @@ struct grub_fshelp_node
{ {
struct grub_iso9660_data *data; struct grub_iso9660_data *data;
grub_size_t have_dirents, alloc_dirents; grub_size_t have_dirents, alloc_dirents;
grub_off_t dir_off; char *symlink;
struct grub_iso9660_dir dirents[8]; struct grub_iso9660_dir dirents[8];
}; };
@ -257,7 +257,7 @@ read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf)
every entry. */ every entry. */
static grub_err_t static grub_err_t
grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off, grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
grub_size_t sua_size, grub_ssize_t sua_size,
grub_err_t (*hook) grub_err_t (*hook)
(struct grub_iso9660_susp_entry *entry)) (struct grub_iso9660_susp_entry *entry))
{ {
@ -288,6 +288,9 @@ grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
return 0; return 0;
} }
if (sua_size <= 0)
return GRUB_ERR_NONE;
if (load_sua ()) if (load_sua ())
return grub_errno; return grub_errno;
@ -454,7 +457,7 @@ grub_iso9660_mount (grub_disk_t disk)
rootnode.data = data; rootnode.data = data;
rootnode.alloc_dirents = 0; rootnode.alloc_dirents = 0;
rootnode.have_dirents = 1; rootnode.have_dirents = 1;
rootnode.dir_off = 0; rootnode.symlink = 0;
rootnode.dirents[0] = data->voldesc.rootdir; rootnode.dirents[0] = data->voldesc.rootdir;
/* The 2nd data byte stored how many bytes are skipped every time /* The 2nd data byte stored how many bytes are skipped every time
@ -480,102 +483,7 @@ grub_iso9660_mount (grub_disk_t disk)
static char * static char *
grub_iso9660_read_symlink (grub_fshelp_node_t node) grub_iso9660_read_symlink (grub_fshelp_node_t node)
{ {
int sua_off; return node->symlink ? grub_strdup (node->symlink) : grub_strdup ("");
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;
}
sua_off = (sizeof (node->dirents[0]) + node->dirents[0].namelen + 1
- (node->dirents[0].namelen % 2)
+ node->data->susp_skip);
sua_size = node->dirents[0].len - sua_off;
symlink = grub_malloc (1);
if (!symlink)
return 0;
*symlink = '\0';
if (grub_iso9660_susp_iterate (node, node->dir_off + sua_off,
sua_size, susp_iterate_sl))
{
grub_free (symlink);
return 0;
}
return symlink;
} }
static grub_off_t static grub_off_t
@ -602,6 +510,23 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
int filename_alloc = 0; int filename_alloc = 0;
enum grub_fshelp_filetype type; enum grub_fshelp_filetype type;
grub_off_t len; 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 *); auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *);
@ -659,6 +584,56 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
type = GRUB_FSHELP_UNKNOWN; 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; return 0;
} }
@ -667,6 +642,9 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
for (; offset < len; offset += dirent.len) for (; offset < len; offset += dirent.len)
{ {
symlink = 0;
addslash = 0;
if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
return 0; return 0;
@ -709,7 +687,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
/* Setup a new node. */ /* Setup a new node. */
node->data = dir->data; node->data = dir->data;
node->dir_off = offset; node->symlink = symlink;
/* If the filetype was not stored using rockridge, use /* If the filetype was not stored using rockridge, use
whatever is stored in the iso9660 filesystem. */ whatever is stored in the iso9660 filesystem. */
@ -838,7 +816,7 @@ grub_iso9660_dir (grub_device_t device, const char *path,
rootnode.data = data; rootnode.data = data;
rootnode.alloc_dirents = 0; rootnode.alloc_dirents = 0;
rootnode.have_dirents = 1; rootnode.have_dirents = 1;
rootnode.dir_off = 0; rootnode.symlink = 0;
rootnode.dirents[0] = data->voldesc.rootdir; rootnode.dirents[0] = data->voldesc.rootdir;
/* Use the fshelp function to traverse the path. */ /* Use the fshelp function to traverse the path. */
@ -881,7 +859,7 @@ grub_iso9660_open (struct grub_file *file, const char *name)
rootnode.data = data; rootnode.data = data;
rootnode.alloc_dirents = 0; rootnode.alloc_dirents = 0;
rootnode.have_dirents = 1; rootnode.have_dirents = 1;
rootnode.dir_off = 0; rootnode.symlink = 0;
rootnode.dirents[0] = data->voldesc.rootdir; rootnode.dirents[0] = data->voldesc.rootdir;
/* Use the fshelp function to traverse the path. */ /* Use the fshelp function to traverse the path. */