From 66b40850331be5979d85a3d0583c7bd74c704b08 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 25 Oct 2011 21:52:48 +0200 Subject: [PATCH] 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. --- ChangeLog | 10 +++ grub-core/fs/iso9660.c | 182 ++++++++++++++++++----------------------- 2 files changed, 90 insertions(+), 102 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c8af24e4..d40675db7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2011-10-25 Vladimir Serbinenko + + 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 * grub-core/loader/i386/bsd.c (grub_netbsd_add_boot_disk_and_wedge): diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c index f6cbbca95..f3e828b89 100644 --- a/grub-core/fs/iso9660.c +++ b/grub-core/fs/iso9660.c @@ -159,7 +159,7 @@ struct grub_fshelp_node { struct grub_iso9660_data *data; grub_size_t have_dirents, alloc_dirents; - grub_off_t dir_off; + char *symlink; 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. */ static grub_err_t 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) (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; } + if (sua_size <= 0) + return GRUB_ERR_NONE; + if (load_sua ()) return grub_errno; @@ -454,7 +457,7 @@ grub_iso9660_mount (grub_disk_t disk) rootnode.data = data; rootnode.alloc_dirents = 0; rootnode.have_dirents = 1; - rootnode.dir_off = 0; + rootnode.symlink = 0; rootnode.dirents[0] = data->voldesc.rootdir; /* 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 * grub_iso9660_read_symlink (grub_fshelp_node_t node) { - 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; - } - - 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; + return node->symlink ? grub_strdup (node->symlink) : grub_strdup (""); } static grub_off_t @@ -602,6 +510,23 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, 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 *); @@ -659,6 +584,56 @@ 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; } @@ -667,6 +642,9 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, for (; offset < len; offset += dirent.len) { + symlink = 0; + addslash = 0; + if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) return 0; @@ -709,7 +687,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, /* Setup a new node. */ node->data = dir->data; - node->dir_off = offset; + node->symlink = symlink; /* If the filetype was not stored using rockridge, use 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.alloc_dirents = 0; rootnode.have_dirents = 1; - rootnode.dir_off = 0; + rootnode.symlink = 0; rootnode.dirents[0] = data->voldesc.rootdir; /* 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.alloc_dirents = 0; rootnode.have_dirents = 1; - rootnode.dir_off = 0; + rootnode.symlink = 0; rootnode.dirents[0] = data->voldesc.rootdir; /* Use the fshelp function to traverse the path. */ -- 2.47.3