[syslinux:rockridge] iso9660: support for Rock Ridge filenames

syslinux-bot for Thomas Schmitt scdbackup at gmx.net
Sun Mar 31 14:48:05 PDT 2013


Commit-ID:  c2e07a22ea9749d4ac591b992f378e188b8afc40
Gitweb:     http://www.syslinux.org/commit/c2e07a22ea9749d4ac591b992f378e188b8afc40
Author:     Thomas Schmitt <scdbackup at gmx.net>
AuthorDate: Sun, 31 Mar 2013 14:37:20 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Sun, 31 Mar 2013 14:37:20 -0700

iso9660: support for Rock Ridge filenames

Add support for parsing SUSP and RRIP records and Rock Ridge long
filenames.  This also avoids the naming and character set limitations
of plain iso9660.

---
 core/fs/iso9660/iso9660.c    |  41 +++-
 core/fs/iso9660/iso9660_fs.h |   5 +
 core/fs/iso9660/susp_rr.c    | 533 +++++++++++++++++++++++++++++++++++++++++++
 core/fs/iso9660/susp_rr.h    |  84 +++++++
 4 files changed, 659 insertions(+), 4 deletions(-)

diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index 3cd3ac4..5d61d5f 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -7,6 +7,7 @@
 #include <disk.h>
 #include <fs.h>
 #include "iso9660_fs.h"
+#include "susp_rr.h"
 
 /* Convert to lower case string */
 static inline char iso_tolower(char c)
@@ -99,9 +100,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);
     
@@ -130,10 +132,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;
 	}
     }
@@ -193,6 +209,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);
@@ -217,8 +235,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 */
     
@@ -281,6 +309,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 a365fa1..4026564 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 0000000..f609f7f
--- /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 at 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 0000000..16732df
--- /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 */


More information about the Syslinux-commits mailing list