[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--