[Libburn] libisofs patch
Todd Kulesza
todd@dropline.net
Mon, 16 Feb 2004 01:55:10 -0500
--=-0IyV+8Is2DXDPF66XPIu
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Ignore that last patch--this one goes a step further and includes the
ability to write out the Path Tables. It also fixes what I think was a
typo in iso_add_tree_dir() where the parent->children pointer is
decremented. I've fixed this to decrement parent->nchildren instead. I
also patched up the iso_add_tree_dir() function to update the parent
pointers for each grandchild node when the child node is reallocated,
otherwise the parent pointers get all fucked up every time
iso_add_tree_dir() is called.
Damn Ben, you weren't kidding when you said this lib is a beast to hack
on :)
Todd
On Sat, 2004-02-14 at 00:06, Todd Kulesza wrote:
> The attached patch fixes a small bug in the iso_lsb() function, fixes
> get_path_table_size() to calculate the length of the Path Tables
> correctly, and adds support for calculating the size of directory
> records. Still can't write ISOs, but getting ever-so-slightly closer...
>
> Todd
>
>
--=-0IyV+8Is2DXDPF66XPIu
Content-Disposition: attachment; filename=libisofs.diff
Content-Type: text/x-patch; name=libisofs.diff; charset=UTF-8
Content-Transfer-Encoding: 7bit
? libXmuu.so.1.0
? libburn/null.lo
Index: libisofs/tree.c
===================================================================
RCS file: /cvs/burn/burn/libisofs/tree.c,v
retrieving revision 1.6
diff -p -u -r1.6 tree.c
--- libisofs/tree.c 10 Dec 2003 05:45:26 -0000 1.6
+++ libisofs/tree.c 15 Feb 2004 19:42:27 -0000
@@ -76,7 +76,7 @@ iso_tree_add_dir (struct iso_tree_dir **
{
struct iso_tree_dir *parent;
struct iso_tree_dir *d;
- int i;
+ int i, j;
if (!(dparent && *dparent && name)) return NULL;
@@ -90,7 +90,7 @@ iso_tree_add_dir (struct iso_tree_dir **
if (!iso_tree_dir_set_name (&d, name)) {
/* we don't unalloc the end of the array but that's ok :> */
- parent->children--;
+ parent->nchildren--;
d = NULL;
} else {
d->volume = volume;
@@ -99,8 +99,14 @@ iso_tree_add_dir (struct iso_tree_dir **
d->volset = parent->volset;
}
- for (i = 0; i < parent->nchildren; ++i)
+ /* since 'parent->children' was set to a new memory location, fix the
+ * 'parent' references */
+ for (i = 0; i < parent->nchildren; ++i) {
*parent->children[i].me = &parent->children[i];
+ for (j = 0; j < parent->children[i].nchildren; ++j) {
+ parent->children[i].children[j].parent = &parent->children[i];
+ }
+ }
return d->me;
}
Index: libisofs/tree.h
===================================================================
RCS file: /cvs/burn/burn/libisofs/tree.h,v
retrieving revision 1.6
diff -p -u -r1.6 tree.h
--- libisofs/tree.h 10 Dec 2003 05:45:26 -0000 1.6
+++ libisofs/tree.h 15 Feb 2004 19:42:27 -0000
@@ -58,9 +58,12 @@ struct iso_tree_dir
/* the logical block at which the dir will be placed
in the volume */
int logical_block;
- /* XXX not really sure what this is the size of */
+ /* the number of bytes needed to hold the directory record
+ * for each file and subdirectory of this directory */
int size;
-
+ /* the position of the directory in the path table */
+ short position;
+
struct iso_tree_dir *parent;
struct iso_tree_dir *children;
Index: libisofs/util.c
===================================================================
RCS file: /cvs/burn/burn/libisofs/util.c,v
retrieving revision 1.3
diff -p -u -r1.3 util.c
--- libisofs/util.c 10 Feb 2004 12:45:20 -0000 1.3
+++ libisofs/util.c 15 Feb 2004 19:42:27 -0000
@@ -131,7 +131,7 @@ iso_lsb(unsigned char *buf, int num, int
assert (bytes <= sizeof (int));
for (i = 0; i < bytes; ++i)
- buf[i] = num << (sizeof (int)-1-i) >> (sizeof (int) - 1) << i;
+ buf[i] = (num >> (8 * i)) & 0xff;
}
void
Index: libisofs/writer.c
===================================================================
RCS file: /cvs/burn/burn/libisofs/writer.c,v
retrieving revision 1.15
diff -p -u -r1.15 writer.c
--- libisofs/writer.c 10 Feb 2004 12:45:20 -0000 1.15
+++ libisofs/writer.c 15 Feb 2004 19:42:28 -0000
@@ -43,8 +43,9 @@ get_path_table_size (struct iso_tree_dir
assert (dir);
+ /* a path table record is 8 bytes + the length of the directory identifier */
if (iso_tree_dir_get_name(ddir, ISO_FILE_NAME_ISO))
- size += strlen (dir->isoname1);
+ size += (8 + strlen (dir->isoname1));
else
{
/* if iso_tree_dir_get_name is NULL, this is the root dir
@@ -52,6 +53,10 @@ get_path_table_size (struct iso_tree_dir
size += 10;
}
+ /* pad the field if the directory identifier is an odd number of bytes */
+ if (size % 2)
+ size++;
+
for (i = 0; i < dir->nchildren; i++)
size += get_path_table_size (dir->children[i].me);
@@ -105,23 +110,46 @@ iso_source_free (struct burn_source *src
free (target);
}
+static int
+get_directory_record_length (const char *isoname)
+{
+ int size;
+
+ /* size = the length of the filename + 33 bytes (9.1) */
+ size = 33 + strlen (isoname);
+ /* if size is odd, pad it with a single byte (9.1.12) */
+ if (size % 2)
+ size++;
+
+ return size;
+}
+
void
iso_dir_layout (struct iso_write_target *target,
struct iso_tree_dir **ddir)
{
- int i;
+ int i, length;
struct iso_tree_dir *dir = *ddir;
dir->logical_block = target->logical_block++;
- dir->size = 0; /* XXX wtf goes here? */
+ length = 0;
for (i = 0; i < dir->nfiles; ++i) {
dir->files[i].logical_block = 0;
dir->files[i].size = 0;
+ length += get_directory_record_length (dir->files[i].isoname1);
}
- for (i = 0; i < dir->nchildren; ++i)
+ for (i = 0; i < dir->nchildren; ++i) {
iso_dir_layout (target, dir->children[i].me);
+ length += get_directory_record_length (dir->children[i].isoname1);
+ }
+
+ /* dir->size is the number of bytes needed to hold the directory record
+ * for each file and subdirectory of 'dir', padded to use up all of the
+ * bytes of a physical sector. */
+ dir->size = ((length / target->phys_sector_size) + 1)
+ * target->phys_sector_size;
}
void
@@ -420,21 +448,123 @@ iso_write_volume_terminator (struct iso_
return 1;
}
+/* write the path record for 'ddir' into 'buffer' */
+static int
+write_path_table_record (unsigned char *buffer,
+ struct iso_tree_dir **ddir,
+ int *position,
+ int lsb)
+{
+ int len, bytes_written;
+ short parent_position;
+ const char *name;
+ struct iso_tree_dir *dir = *ddir;
+
+ /* set the position in the path table of this directory */
+ dir->position = *position;
+ /* increment the position for the next path table record */
+ *position += 1;
+ if (dir->parent)
+ parent_position = dir->parent->position;
+ else
+ parent_position = 1;
+
+ name = dir->isoname1;
+ if (name)
+ len = strlen (name);
+ else
+ len = 1;
+
+ /* the directory identifier length (9.4.1) */
+ buffer[0] = len;
+ /* the extended attribute record length (9.4.2) */
+ buffer[1] = 0;
+ /* location of extent (9.4.3) */
+ if (lsb)
+ iso_lsb (&buffer[2], dir->logical_block, 4);
+ else
+ iso_msb (&buffer[2], dir->logical_block, 4);
+ /* parent directory record (9.4.4) */
+ if (lsb)
+ iso_lsb (&buffer[6], parent_position, 2);
+ else
+ iso_msb (&buffer[6], parent_position, 2);
+ /* the directory identifier (9.4.5) */
+ if (name)
+ memcpy (&buffer[8], name, len);
+ else
+ memset (&buffer[8], 0, len);
+ /* padding field (9.4.6) */
+ if (len % 2) {
+ bytes_written = 9 + len;
+ buffer[bytes_written] = 0;
+ }
+ else
+ bytes_written = 8 + len;
+
+ return bytes_written;
+}
+
+/* recursive function used to write the path records for each level
+ * of the file system sequentially, i.e. root, then all children of
+ * root, then all grandchildren of root, then all great-grandchildren
+ * of root, etc. */
+static int
+write_path_table_records (unsigned char *buffer,
+ struct iso_tree_dir **ddir,
+ int level,
+ int *position,
+ int lsb)
+{
+ int i, offset;
+ struct iso_tree_dir *dir = *ddir;
+
+ /* ISO9660 only allows directories to be nested 8-deep */
+ if (level >= 8)
+ return 0;
+
+ if (!level)
+ offset = write_path_table_record (buffer, ddir, position, lsb);
+ else {
+ offset = 0;
+ for (i = 0; i < dir->nchildren; ++i) {
+ offset += write_path_table_records (buffer + offset,
+ dir->children[i].me,
+ level - 1,
+ position,
+ lsb);
+ }
+ }
+
+ return offset;
+}
+
/* writes set of path table records */
-int iso_write_path_table (struct iso_write_target *t,
+int
+iso_write_path_table (struct iso_write_target *t,
unsigned char *buffer,
enum burn_source_status *err,
int lsb)
{
+ int i, offset, position;
struct iso_state_path_tables *state = &t->state_data.path_tables;
-
- /* XXX replace == 0 with < (size of path table) */
- if (state->sectors == 0) {
- /* XXX replace these 0xff's with actual path table data */
- memset (buffer, 0xff, t->phys_sector_size);
- } else {
+
+ if (state->sectors) {
+ offset = 0;
+ position = 1;
+
+ for (i = 0; i < 8; ++i) {
+ offset += write_path_table_records (buffer + offset,
+ t->volset->root,
+ i,
+ &position,
+ lsb);
+ }
+ }
+ else {
/* empty buffer sector */
memset (buffer, 0, t->phys_sector_size);
}
+
return (++state->sectors == 2);
}
--=-0IyV+8Is2DXDPF66XPIu--