aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorThomas Schmitt <scdbackup@gmx.net>2013-03-31 14:56:51 -0700
committerH. Peter Anvin <hpa@zytor.com>2013-03-31 14:56:51 -0700
commit556ccf02efe3eae833bcc82c4764179580ba6361 (patch)
tree19b98a8284f78df4bfbcdb858888f9f5713f4e35 /core
parent66d551acdb0d516f43702983184483687c2128e4 (diff)
downloadsyslinux-556ccf02efe3eae833bcc82c4764179580ba6361.tar.gz
syslinux-556ccf02efe3eae833bcc82c4764179580ba6361.tar.xz
syslinux-556ccf02efe3eae833bcc82c4764179580ba6361.zip
iso9660: Add support for Rock Ridge filenames
Add support for parsing SUSP and RRIP records, and support for Rock Ridge filename extensions, thus avoiding the filename limitations (length and character set) of plain iso9660. This will be a part of using UTF-8 for filenames and console. [ hpa: manually rebased to the elflink branch ]
Diffstat (limited to 'core')
-rw-r--r--core/fs/iso9660/iso9660.c41
-rw-r--r--core/fs/iso9660/iso9660_fs.h5
-rw-r--r--core/fs/iso9660/susp_rr.c533
-rw-r--r--core/fs/iso9660/susp_rr.h84
4 files changed, 659 insertions, 4 deletions
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index fe58a5b3..0f7b3d2a 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -8,6 +8,7 @@
#include <fs.h>
#include <stdlib.h>
#include "iso9660_fs.h"
+#include "susp_rr.h"
/* Convert to lower case string */
static inline char iso_tolower(char c)
@@ -100,9 +101,10 @@ iso_find_entry(const char *dname, struct inode *inode)
block_t dir_block = PVT(inode)->lba;
int i = 0, offset = 0;
const char *de_name;
- int de_name_len, de_len;
+ int de_name_len, de_len, rr_name_len, ret;
const struct iso_dir_entry *de;
const char *data = NULL;
+ char *rr_name = NULL;
dprintf("iso_find_entry: \"%s\"\n", dname);
@@ -131,10 +133,24 @@ iso_find_entry(const char *dname, struct inode *inode)
continue;
}
+ /* Try to get Rock Ridge name */
+ ret = susp_rr_get_nm(fs, (char *) de, &rr_name, &rr_name_len);
+ if (ret > 0) {
+ if (strcmp(rr_name, dname) == 0) {
+ dprintf("Found (by RR name).\n");
+ free(rr_name);
+ return de;
+ }
+ free(rr_name);
+ rr_name = NULL;
+ continue; /* Rock Ridge was valid and did not match */
+ }
+
+ /* Fall back to ISO name */
de_name_len = de->name_len;
de_name = de->name;
if (iso_compare_name(de_name, de_name_len, dname)) {
- dprintf("Found.\n");
+ dprintf("Found (by ISO name).\n");
return de;
}
}
@@ -194,6 +210,8 @@ static int iso_readdir(struct file *file, struct dirent *dirent)
struct inode *inode = file->inode;
const struct iso_dir_entry *de;
const char *data = NULL;
+ char *rr_name = NULL;
+ int name_len, ret;
while (1) {
size_t offset = file->offset & (BLOCK_SIZE(fs) - 1);
@@ -218,8 +236,18 @@ static int iso_readdir(struct file *file, struct dirent *dirent)
dirent->d_ino = 0; /* Inode number is invalid to ISO fs */
dirent->d_off = file->offset;
dirent->d_type = get_inode_mode(de->flags);
- dirent->d_reclen = offsetof(struct dirent, d_name) + 1 +
- iso_convert_name(dirent->d_name, de->name, de->name_len);
+
+ /* Try to get Rock Ridge name */
+ ret = susp_rr_get_nm(fs, (char *) de, &rr_name, &name_len);
+ if (ret > 0) {
+ memcpy(dirent->d_name, rr_name, name_len);
+ free(rr_name);
+ rr_name = NULL;
+ } else {
+ name_len = iso_convert_name(dirent->d_name, de->name, de->name_len);
+ }
+
+ dirent->d_reclen = offsetof(struct dirent, d_name) + 1 + name_len;
file->offset += de->length; /* Update for next reading */
@@ -282,6 +310,11 @@ static int iso_fs_init(struct fs_info *fs)
/* Initialize the cache */
cache_init(fs->fs_dev, fs->block_shift);
+ /* Check for SP and ER in the first directory record of the root directory.
+ Set sbi->susp_skip and enable sbi->do_rr as appropriate.
+ */
+ susp_rr_check_signatures(fs, 1);
+
return fs->block_shift;
}
diff --git a/core/fs/iso9660/iso9660_fs.h b/core/fs/iso9660/iso9660_fs.h
index a365fa1a..40265642 100644
--- a/core/fs/iso9660/iso9660_fs.h
+++ b/core/fs/iso9660/iso9660_fs.h
@@ -37,6 +37,11 @@ struct iso_dir_entry {
struct iso_sb_info {
struct iso_dir_entry root;
+
+ int do_rr; /* 1 , 2 = try to process Rock Ridge info , 0 = do not.
+ 2 indicates that the id of RRIP 1.12 was found.
+ */
+ int susp_skip; /* Skip length from SUSP entry SP */
};
/*
diff --git a/core/fs/iso9660/susp_rr.c b/core/fs/iso9660/susp_rr.c
new file mode 100644
index 00000000..f609f7ff
--- /dev/null
+++ b/core/fs/iso9660/susp_rr.c
@@ -0,0 +1,533 @@
+/* Reader for SUSP and Rock Ridge information.
+
+ Copyright (c) 2013 Thomas Schmitt <scdbackup@gmx.net>
+ Provided under GNU General Public License version 2 or later.
+
+ Based on:
+ SUSP 1.12 (entries CE , PD , SP , ST , ER , ES)
+ ftp://ftp.ymi.com/pub/rockridge/susp112.ps
+ RRIP 1.12 (entries PX , PN , SL , NM , CL , PL , RE , TF , SF)
+ ftp://ftp.ymi.com/pub/rockridge/rrip112.ps
+ ECMA-119 aka ISO 9660
+ http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
+
+ Shortcommings / Future improvements:
+ (XXX): Avoid memcpy() with Continuation Areas wich span over more than one
+ block ? (Will then need memcpy() with entries which are hit by a
+ block boundary.) (Questionable whether the effort is worth it.)
+ (XXX): Take into respect ES entries ? (Hardly anybody does this.)
+
+*/
+
+#ifndef Isolinux_rockridge_in_libisofS
+
+/* Mindlessly copied from core/fs/iso9660/iso9660.c */
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <core.h>
+#include <cache.h>
+#include <disk.h>
+#include <fs.h>
+#include "iso9660_fs.h"
+
+#else /* ! Isolinux_rockridge_in_libisofS */
+
+/* ====== Test mock-up of definitions which should come from syslinux ====== */
+
+/* With defined Isolinux_rockridge_in_libisofS this source file can be included
+ into libisofs/fs_image.c and the outcome of its public functions can be
+ compared with the perception of libisofs when loading an ISO image.
+
+ Test results look ok with 50 ISO images when read by xorriso underneath
+ valgrind.
+*/
+
+typedef uint32_t block_t;
+
+#define dprintf printf
+
+struct device {
+ IsoDataSource *src;
+};
+
+
+struct susp_rr_dir_rec_wrap {
+ char data[256];
+};
+
+struct iso_sb_info {
+ struct susp_rr_dir_rec_wrap root;
+
+ int do_rr; /* 1 = try to process Rock Ridge info , 0 = do not */
+ int susp_skip; /* Skip length from SUSP enntry SP */
+};
+
+struct fs_info {
+ struct device *fs_dev;
+ struct iso_sb_info *fs_info;
+};
+
+#define get_cache dummy_get_cache
+
+static char *dummy_get_cache(struct device *fs_dev, block_t lba)
+{
+ static uint8_t buf[2048];
+ int ret;
+
+ ret = fs_dev->src->read_block(fs_dev->src, lba, buf);
+ if (ret < 0)
+ return NULL;
+ return (char *) buf;
+}
+
+/* =========================== End of test mock-up ========================= */
+
+#endif /* ! Isolinux_rockridge_for_reaL */
+
+
+static int susp_rr_is_out_of_mem(void *pt)
+{
+ if (pt != NULL)
+ return 0;
+ dprintf("susp_rr.c: Out of memory !\n");
+
+ /* XXX : Should one abort on global level ? */
+
+ return 1;
+}
+
+
+/* XXX: Is there already a reader for 32-bit MSB or LSB in the syslinux code ?
+ (iso9660.c seems to flatly assume that it runs on little-endian int.)
+*/
+static uint32_t susp_rr_read_msb(uint8_t *buf, int bytes)
+{
+ int i;
+ uint32_t ret = 0;
+
+ for (i = 0; i < bytes; i++) {
+ ret += ((uint32_t) buf[bytes - i - 1]) << (i * 8);
+ }
+ return ret;
+}
+
+
+/* State of iteration over SUSP entries.
+
+ This would be quite trivial if there was not the possibility of Continuation
+ Areas announced by the CE entry. In general they are quite rare, because
+ often all Rock Ridge entries fit into the ISO 9660 directory record.
+ So it seems unwise to invest much complexity into optimization of
+ Continuation Areas.
+ (I found 35 CE in a backup of mine which contains 63000 files, 2 CE in
+ a Debian netinst ISO, 2 CE in a Fedora live CD.)
+*/
+struct susp_rr_iter {
+ struct fs_info *fs; /* From where to read Continuation Area data */
+ char *dir_rec; /* ISO 9660 directory record */
+ int in_ce; /* 0= still reading dir_rec, 1= reading ce_data */
+ char *ce_data; /* Loaded Continuation Area data */
+ int ce_allocated; /* 0= do not free ce_data, 1= do free */
+ size_t read_pos; /* Current read offset in dir_rec or ce_data */
+ size_t read_end; /* Current first invalid read_pos */
+
+ block_t next_lba; /* Block number of start of next Continuation Area */
+ size_t next_offset; /* Byte offset within the next_lba block */
+ size_t next_length; /* Number of valid bytes in next Cont. Area */
+};
+
+
+static int susp_rr_iter_new(struct susp_rr_iter **iter,
+ struct fs_info *fs, char *dir_rec)
+{
+ struct iso_sb_info *sbi = fs->fs_info;
+ struct susp_rr_iter *o;
+ uint8_t len_fi;
+ int read_pos, read_end;
+
+ len_fi = ((uint8_t *) dir_rec)[32];
+ read_pos = 33 + len_fi + !(len_fi % 2) + sbi->susp_skip;
+ read_end = ((uint8_t *) dir_rec)[0];
+ if (read_pos + 4 > read_end)
+ return 0; /* Not enough System Use data present for SUSP */
+ if (dir_rec[read_pos + 3] != 1)
+ return 0; /* Not SUSP version 1 */
+
+ o= *iter= malloc(sizeof(struct susp_rr_iter));
+ if (susp_rr_is_out_of_mem(o))
+ return -1;
+ o->fs = fs;
+ o->dir_rec= dir_rec;
+ o->in_ce= 0;
+ o->read_pos = read_pos;
+ o->read_end = read_end;
+ o->next_lba = 0;
+ o->next_offset = o->next_length = 0;
+ o->ce_data = NULL;
+ o->ce_allocated = 0;
+ return 1;
+}
+
+
+static int susp_rr_iter_destroy(struct susp_rr_iter **iter)
+{
+ struct susp_rr_iter *o;
+
+ o = *iter;
+ if (o == NULL)
+ return 0;
+ if (o->ce_data != NULL && o->ce_allocated)
+ free(o->ce_data);
+ free(o);
+ *iter = NULL;
+ return 1;
+}
+
+
+/* Switch to next Continuation Area.
+*/
+static int susp_rr_switch_to_ca(struct susp_rr_iter *iter)
+{
+ block_t num_blocks, i;
+ const char *data = NULL;
+
+ num_blocks = (iter->next_offset + iter->next_length + 2047) / 2048;
+
+ if (iter->ce_data != NULL && iter->ce_allocated)
+ free(iter->ce_data);
+ iter->ce_data = NULL;
+ iter->ce_allocated = 0;
+ if (num_blocks > 1) {
+ /* The blocks are expected contiguously. Need to consolidate them. */
+ iter->ce_data = malloc(num_blocks * 2048);
+ if (susp_rr_is_out_of_mem(iter->ce_data))
+ return -1;
+ iter->ce_allocated = 1;
+ for (i = 0; i < num_blocks; i++) {
+ data = get_cache(iter->fs->fs_dev, iter->next_lba + i);
+ if (data == NULL) {
+ dprintf("susp_rr.c: Failure to read block %lu\n",
+ (unsigned long) iter->next_lba + i);
+ return -1;
+ }
+ memcpy(iter->ce_data + i * 2048, data, 2048);
+ }
+ } else {
+ /* Avoiding malloc() and memcpy() in the single block case */
+ data = get_cache(iter->fs->fs_dev, iter->next_lba);
+ if (data == NULL) {
+ dprintf("susp_rr.c: Failure to read block %lu\n",
+ (unsigned long) iter->next_lba);
+ return -1;
+ }
+ iter->ce_data = (char *) data;
+ }
+
+ iter->in_ce = 1;
+ iter->read_pos = iter->next_offset;
+ iter->read_end = iter->next_offset + iter->next_length;
+ iter->next_lba = 0;
+ iter->next_offset = iter->next_length = 0;
+ return 1;
+}
+
+
+/* Obtain the next SUSP entry.
+*/
+static int susp_rr_iterate(struct susp_rr_iter *iter, char **pos_pt)
+{
+ char *entries;
+ uint8_t susp_len, *u_entry;
+ int ret;
+
+ if (iter->in_ce) {
+ entries = iter->ce_data + iter->read_pos;
+ } else {
+ entries = iter->dir_rec + iter->read_pos;
+ }
+ if (iter->read_pos + 4 <= iter->read_end)
+ if (entries[3] != 1) {
+ /* Not SUSP version 1 */
+ dprintf("susp_rr.c: Chain of SUSP entries broken\n");
+ return -1;
+ }
+ if (iter->read_pos + 4 > iter->read_end ||
+ (entries[0] == 'S' && entries[1] == 'T')) {
+ /* This part of the SU area is done */
+ if (iter->next_length == 0) {
+ /* No further CE entry was encountered. Iteration ends now. */
+ return 0;
+ }
+ ret = susp_rr_switch_to_ca(iter);
+ if (ret <= 0)
+ return ret;
+ entries = iter->ce_data + iter->read_pos;
+ }
+
+ if (entries[0] == 'C' && entries[1] == 'E') {
+ if (iter->next_length > 0) {
+ dprintf("susp_rr.c: Surplus CE entry detected\n");
+ return -1;
+ }
+ /* Register address data of next Continuation Area */
+ u_entry = (uint8_t *) entries;
+ iter->next_lba = susp_rr_read_msb(u_entry + 8, 4);
+ iter->next_offset = susp_rr_read_msb(u_entry + 16, 4);
+ iter->next_length = susp_rr_read_msb(u_entry + 24, 4);
+ }
+
+ *pos_pt = entries;
+ susp_len = ((uint8_t *) entries)[2];
+ iter->read_pos += susp_len;
+ return 1;
+}
+
+
+/* Check for SP entry at position try_skip in the System Use area.
+*/
+static int susp_rr_check_sp(struct fs_info *fs, char *dir_rec, int try_skip)
+{
+ struct iso_sb_info *sbi = fs->fs_info;
+ int read_pos, read_end, len_fi;
+ uint8_t *sua;
+
+ len_fi = ((uint8_t *) dir_rec)[32];
+ read_pos = 33 + len_fi + !(len_fi % 2) + try_skip;
+ read_end = ((uint8_t *) dir_rec)[0];
+ if (read_end - read_pos < 7)
+ return 0;
+ sua = (uint8_t *) (dir_rec + read_pos);
+ if (sua[0] != 'S' || sua[1] != 'P' || sua[2] != 7 || sua[3] != 1 ||
+ sua[4] != 0xbe || sua[5] != 0xef)
+ return 0;
+ dprintf("susp_rr.c: SUSP signature detected\n");
+ sbi->susp_skip = ((uint8_t *) dir_rec)[6];
+ if (sbi->susp_skip > 0 && sbi->susp_skip != try_skip)
+ dprintf("susp_rr.c: Unusual: Non-zero skip length in SP entry\n");
+ return 1;
+}
+
+
+/* Public function. See susp_rr.h
+
+ Rock Ridge specific knowledge about NM and SL has been integrated here,
+ because this saves one malloc and memcpy for the file name.
+*/
+int susp_rr_get_entries(struct fs_info *fs, char *dir_rec, char *sig,
+ char **data, int *len_data, int flag)
+{
+ int count = 0, ret = 0, head_skip = 4, nmsp_flags = -1, is_done = 0;
+ char *pos_pt, *new_data;
+ uint8_t pay_len;
+ struct susp_rr_iter *iter = NULL;
+ struct iso_sb_info *sbi = fs->fs_info;
+
+ *data = NULL;
+ *len_data = 0;
+
+ if (!sbi->do_rr)
+ return 0; /* Rock Ridge is not enabled */
+
+ if (flag & 1)
+ head_skip = 5;
+
+ ret = susp_rr_iter_new(&iter, fs, dir_rec);
+ if (ret <= 0)
+ goto ex;
+ while (!is_done) {
+ ret = susp_rr_iterate(iter, &pos_pt);
+ if (ret < 0)
+ goto ex;
+ if (ret == 0)
+ break; /* End SUSP iteration */
+ if (sig[0] != pos_pt[0] || sig[1] != pos_pt[1])
+ continue; /* Next SUSP iteration */
+
+ pay_len = ((uint8_t *) pos_pt)[2];
+ if (pay_len < head_skip) {
+ dprintf("susp_rr.c: Short NM entry encountered.\n");
+ ret = -1;
+ goto ex;
+ }
+ pay_len -= head_skip;
+ if ((flag & 1)) {
+ if (nmsp_flags < 0)
+ nmsp_flags = ((uint8_t *) pos_pt)[4];
+ if (!(pos_pt[4] & 1)) /* No CONTINUE bit */
+ is_done = 1; /* This is the last iteration cycle */
+ }
+ count += pay_len;
+ if (count > 102400) {
+ dprintf("susp_rr.c: More than 100 KB in '%c%c' entries.\n",
+ sig[0], sig[1]);
+ ret = -1;
+ goto ex;
+ }
+ new_data = malloc(count + 1);
+ if (susp_rr_is_out_of_mem(new_data)) {
+ ret = -1;
+ goto ex;
+ }
+ if (*data != NULL) {
+ /* This case should be rare. An extra iteration pass to predict
+ the needed data size would hardly pay off.
+ */
+ memcpy(new_data, *data, *len_data);
+ free(*data);
+ }
+ new_data[count] = 0;
+ *data = new_data;
+ memcpy(*data + *len_data, pos_pt + head_skip, pay_len);
+ *len_data += pay_len;
+ }
+ if (*data == NULL) {
+ ret = 0;
+ } else if (flag & 1) {
+ ret = 0x100 | nmsp_flags;
+ } else {
+ ret = 1;
+ }
+ex:;
+ susp_rr_iter_destroy(&iter);
+ if (ret <= 0 && *data != NULL) {
+ free(*data);
+ *data = NULL;
+ }
+ return ret;
+}
+
+
+/* Public function. See susp_rr.h
+*/
+int susp_rr_get_nm(struct fs_info *fs, char *dir_rec,
+ char **name, int *len_name)
+{
+ int ret;
+
+ ret = susp_rr_get_entries(fs, dir_rec, "NM", name, len_name, 1);
+ if (ret <= 0)
+ return ret;
+
+ /* Interpret flags */
+ if (ret & 0x6) {
+ if (*name != NULL)
+ free(*name);
+ *len_name = 0;
+ *name = strdup(ret & 0x2 ? "." : "..");
+ if (susp_rr_is_out_of_mem(*name)) {
+ return -1;
+ }
+ *len_name = strlen(*name);
+ }
+ if (*len_name >= 256) {
+ dprintf("susp_rr.c: Rock Ridge name longer than 255 characters.\n");
+ free(*name);
+ *name = NULL;
+ *len_name = 0;
+ return -1;
+ }
+ return 1;
+}
+
+
+/* Public function. See susp_rr.h
+*/
+int susp_rr_check_signatures(struct fs_info *fs, int flag)
+{
+ struct iso_sb_info *sbi = fs->fs_info;
+ char *dir_rec;
+ char *data = NULL;
+ uint8_t *u_data;
+ block_t lba;
+ int len_data, i, len_er = 0, len_id, ret;
+ int rrip_112 = 0;
+
+ sbi->do_rr = 1; /* provisory for the time of examination */
+ sbi->susp_skip = 0;
+
+#ifndef Isolinux_rockridge_in_libisofS
+/* (There is a name collision with libisofs BLOCK_SIZE. On the other hand,
+ libisofs has hardcoded blocksize 2048.) */
+
+ /* For now this works only with 2 KB blocks */
+ if (BLOCK_SIZE(fs) != 2048) {
+ dprintf("susp_rr.c: Block size is not 2048. Rock Ridge disabled.\n");
+ goto no_susp;
+ }
+
+#endif /* Isolinux_rockridge_in_libisofS */
+
+ /* Obtain first dir_rec of root directory */
+ lba = susp_rr_read_msb(((uint8_t *) &(sbi->root)) + 6, 4);
+ dir_rec = (char *) get_cache(fs->fs_dev, lba);
+ if (dir_rec == NULL)
+ goto no_susp;
+
+ /* First System Use entry must be SP */
+ ret = susp_rr_check_sp(fs, dir_rec, 0);
+ if (ret == 0) {
+ /* SUSP 1.12 prescribes that on CD-ROM XA discs the SP entry is at
+ offset 14 of the System Use area.
+ How to detect a CD-ROM XA disc here ?
+ (libisofs ignores this prescription and lives well with that.
+ /usr/src/linux/fs/isofs/ makes a blind try with 14.)
+ */
+ ret = susp_rr_check_sp(fs, dir_rec, 14);
+ }
+ if (ret <= 0)
+ goto no_susp;
+
+ if (!(flag & 1)) {
+ ret = 1;
+ goto ex;
+ }
+
+ /* Look for ER entries */
+ ret = susp_rr_get_entries(fs, dir_rec, "ER", &data, &len_data, 0);
+ if (ret <= 0 || len_data < 8)
+ goto no_rr;
+ u_data = (uint8_t *) data;
+ for (i = 0; i < len_data; i += len_er) {
+ len_id = u_data[0];
+ len_er = 4 + len_id + u_data[1] + u_data[2];
+ if (i + len_er > len_data) {
+ dprintf("susp_rr.c: Error with field lengths in ER entry\n");
+ goto no_rr;
+ }
+ if (len_id == 10 && strncmp(data + 4, "RRIP_1991A", len_id) == 0) {
+ dprintf("susp_rr.c: Signature of Rock Ridge 1.10 detected\n");
+ break;
+ } else if ((len_id == 10 &&
+ strncmp(data + 4, "IEEE_P1282", len_id) == 0) ||
+ (len_id == 9 &&
+ strncmp(data + 4, "IEEE_1282", len_id) == 0)) {
+ dprintf("susp_rr.c: Signature of Rock Ridge 1.12 detected\n");
+ rrip_112 = 1;
+ break;
+ }
+ }
+ if (i >= len_data)
+ goto no_rr;
+
+ sbi->do_rr = 1 + rrip_112;
+ ret = 2 + rrip_112;
+ goto ex;
+
+no_susp:;
+ dprintf("susp_rr.c: No SUSP signature detected\n");
+ ret = 0;
+ goto ex;
+
+no_rr:;
+ dprintf("susp_rr.c: No Rock Ridge signature detected\n");
+ ret = 0;
+
+ex:;
+ if (ret <= 0)
+ sbi->do_rr = 0;
+ if (data != NULL)
+ free(data);
+ return ret;
+}
diff --git a/core/fs/iso9660/susp_rr.h b/core/fs/iso9660/susp_rr.h
new file mode 100644
index 00000000..16732df3
--- /dev/null
+++ b/core/fs/iso9660/susp_rr.h
@@ -0,0 +1,84 @@
+#ifndef ISO9660_SUSP_H
+#define ISO9660_SUSP_H 1
+
+/* Public functions of susp_rr.c, a reader for SUSP and Rock Ridge information.
+*/
+
+/* Inspect the ISO 9660 filesystem whether it bears the signatures of
+ SUSP and Rock Ridge.
+ Set the parameters fs->fs_info->do_rr and fs->fs_info->susp_skip.
+ To be called at the end of iso_fs_init().
+
+ SUSP demands an SP entry as first entry in the System Use area of
+ the first directory record in the root directory.
+ Rock Ridge prescribes at the same directory record an ER entry with
+ id field content "RRIP_1991A", or "IEEE_P1282", or "IEEE_1282".
+
+ @param fs The filesystem to inspect
+ @param flag Bitfield for control purposes:
+ bit0= Demand a Rock Ridge ER entry
+ @return 0 No valid SUSP signature found.
+ 1 Yes, signature of SUSP found. No ER was demanded.
+ 2 ER of RRIP 1.10 found.
+ 3 ER of RRIP 1.12 found.
+*/
+int susp_rr_check_signatures(struct fs_info *fs, int flag);
+
+
+/* Obtain the payload bytes of all SUSP entries with the given signature.
+
+ @param fs The filesystem from which to read CE blocks.
+ fs->fs_info->do_rr must be non-zero or else this function
+ will always return 0 (i.e. no payload found).
+ @param dir_rec Memory containing the whole ISO 9660 directory record.
+ @param sig Two characters of SUSP signature. E.g. "NM", "ER", ...
+ @param data Returns allocated memory with the payload.
+ A trailing 0-byte is added for convenience with strings.
+ If data is returned != NULL, then it has to be disposed
+ by free() when it is no longer needed.
+ @param len_data Returns the number of valid bytes in *data.
+ Not included in this count is the convenience 0-byte.
+ @param flag Bitfield for control purposes:
+ bit0= NM/SL mode:
+ Skip 5 header bytes rather than 4.
+ End after first matching entry without CONTINUE bit.
+ Return 0x100 | byte[4] (FLAGS) of first entry.
+ @return >0 Success.
+ *data and *len_data are valid.
+ Only in this case, *data is returned != NULL.
+ 0 Desired signature not found.
+ -1 Error.
+ Something is wrong with the ISO 9660 or SUSP data in
+ the image.
+*/
+int susp_rr_get_entries(struct fs_info *fs, char *dir_rec, char *sig,
+ char **data, int *len_data, int flag);
+
+
+/* Obtain the Rock Ridge name of a directory record.
+ If the found content of NM entries is longer than 255 characters,
+ then this function will not return it, but rather indicate an error.
+
+ @param fs The filesystem from which to read CE blocks.
+ fs->fs_info->do_rr must be non-zero or else this function
+ will always return 0 (i.e. no Rock Ridge name found).
+ @param dir_rec Memory containing the whole ISO 9660 directory record.
+ @param name Returns allocated memory with the name and a trailing
+ 0-byte. name might contain any byte values.
+ If name is returned != NULL, then it has to be disposed
+ by free() when it is no longer needed.
+ @param len_name Returns the number of valid bytes in *name.
+ Not included in this count is the 0-byte after the name.
+ @return >0 Success.
+ *name and *len_name are valid.
+ Only in this case, *data is returned != NULL.
+ 0 No NM entry found. No Rock Ridge name defined.
+ -1 Error.
+ Something is wrong with the ISO 9660 or SUSP data in
+ the image.
+*/
+int susp_rr_get_nm(struct fs_info *fs, char *dir_rec,
+ char **name, int *len_name);
+
+
+#endif /* ! ISO9660_SUSP_H */