[Libburn] libisofs cleanup & crash fix (now with file support!)

Todd Kulesza todd@dropline.net
Fri, 05 Mar 2004 00:35:37 -0500


--=-LUoi30Hkw15Qt146VP6t
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

And one more revision, this time adding support for unique ISO level-1
file names :)

Todd

On Thu, 2004-02-26 at 00:27, Todd Kulesza wrote:
> Here's a second pass at writing out files; it's much better than the
> last one because now it actually *works* ;)
> 
> I also addressed some issues with calculating directory record sizes and
> the size of the ISO as a whole.  It's going to need to be hammered on
> before release, but I think all of the important bits are in place :)
> 
> Todd
> 
> On Wed, 2004-02-25 at 18:05, Todd Kulesza wrote:
> > This patch cleans up the libisofs code a bit and fixes a nasty bug that
> > was causing random segfaults when writing ISOs.  It also includes my
> > first pass at writing the file area of an ISO (which really sucks and
> > needs lots of work), but I just wanted to get this patch in to fix the
> > segault.
> > 
> > Todd

--=-LUoi30Hkw15Qt146VP6t
Content-Disposition: attachment; filename=libisofs.diff
Content-Type: text/x-patch; name=libisofs.diff; charset=UTF-8
Content-Transfer-Encoding: 7bit

Index: libisofs/libisofs.h
===================================================================
RCS file: /cvs/burn/burn/libisofs/libisofs.h,v
retrieving revision 1.14
diff -p -u -r1.14 libisofs.h
--- libisofs/libisofs.h	10 Feb 2004 12:45:20 -0000	1.14
+++ libisofs/libisofs.h	5 Mar 2004 05:32:56 -0000
@@ -71,6 +71,7 @@ const char* iso_tree_file_get_name (stru
             zero if the specified name was invalid.
 */
 int iso_tree_file_set_name (struct iso_tree_file **file,
+			    struct iso_tree_dir **dir,
 			    const char *name);
 
 const char* iso_tree_dir_get_name (struct iso_tree_dir **dir,
Index: libisofs/tree.c
===================================================================
RCS file: /cvs/burn/burn/libisofs/tree.c,v
retrieving revision 1.7
diff -p -u -r1.7 tree.c
--- libisofs/tree.c	24 Feb 2004 18:37:46 -0000	1.7
+++ libisofs/tree.c	5 Mar 2004 05:32:58 -0000
@@ -84,18 +84,12 @@ struct iso_tree_dir **iso_tree_add_dir(s
 				   parent->nchildren);
 	d = &parent->children[parent->nchildren - 1];
 	memset(d, 0, sizeof(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->nchildren--;
-		d = NULL;
-	} else {
-		d->volume = volume;
-		d->parent = parent;
-		d->me = malloc(sizeof(struct iso_tree_dir *));
-		d->volset = parent->volset;
-	}
-
+	
+	d->volume = volume;
+	d->parent = parent;
+	d->me = malloc(sizeof(struct iso_tree_dir *));
+	d->volset = parent->volset;
+		
 	/* since 'parent->children' was set to a new memory location, fix the
 	   'parent' references */
 	for (i = 0; i < parent->nchildren; ++i) {
@@ -105,6 +99,13 @@ struct iso_tree_dir **iso_tree_add_dir(s
 				&parent->children[i];
 		}
 	}
+	
+	if (!iso_tree_dir_set_name(&d, name)) {
+		/* we don't unalloc the end of the array but that's ok :> */
+		parent->nchildren--;
+		free(d->me);
+		d = NULL;
+	}
 
 	return d->me;
 }
@@ -138,7 +139,7 @@ struct iso_tree_file **iso_tree_add_file
 	r = strrchr(path, '/');
 	assert(r);
 
-	if (!iso_tree_file_set_name(&f, r + 1)) {
+	if (!iso_tree_file_set_name(&f, &parent, r + 1)) {
 		/* we don't unalloc the end of the array but that's ok :> */
 		parent->nfiles--;
 		f = NULL;
@@ -189,19 +190,34 @@ const char *iso_tree_file_get_name(struc
 	return NULL;
 }
 
-char *get_iso_name_1(const char *name, const char *ext)
+char *get_iso_name_1(const char *name, const char *ext, int uid)
 {
 	char *out = NULL;
-	char *n, *e;
+	char *n, *nid, id[4], *e;
 
-	/* XXX avoid duplicates */
-	n = iso_d_strndup(name, 8);
-	e = iso_d_strndup(ext, 3);
-	if (strlen(n) || strlen(e))
+	/* ensure a unique name for each file */
+	if (uid > -1) {
+		nid = iso_d_strndup(name, 5);
+		snprintf(id, 4, "%03d", uid);
+		n = malloc(sizeof(char) * 10);
+		memcpy(n, nid, sizeof(char) * 5);
+		memcpy(n + strlen (nid), id, sizeof(char) * 3);
+		n[strlen(nid) + 4] = '\0';
+	} else
+		n = iso_d_strndup(name, 8);
+	if (ext)
+		e = iso_d_strndup(ext, 3);
+	else
+		e = iso_d_strndup("", 1);
+	
+	if (strlen(n) && strlen(e))
 		out = iso_strconcat('.', n, e);
+	else
+		out = iso_d_strndup(n, strlen(n));
 
 	free(n);
 	free(e);
+	
 	return out;
 }
 
@@ -223,28 +239,54 @@ char *get_iso_name_2(const char *name, c
 	return out;
 }
 
-int iso_tree_file_set_name(struct iso_tree_file **dfile, const char *fullname)
+static int file_dup_iso_name_1(struct iso_tree_dir *dir, const char *name)
 {
-	int ret = 0;
+	int i, retval = 0;
+	const char *isoname;
+	
+	if (!dir || !name)
+		return retval;
+	
+	for (i = 0; (i < dir->nfiles) && !retval; ++i) {
+		isoname = dir->files[i].isoname1;
+		if (isoname && !strcmp (isoname, name))
+			retval = 1;
+	}
+	
+	return retval;
+}
+
+int iso_tree_file_set_name(struct iso_tree_file **dfile, 
+			   struct iso_tree_dir **ddir, const char *fullname)
+{
+	int i, ret = 0;
 	char *name = NULL, *ext;
 	char *isoname1 = NULL, *isoname2 = NULL;
 	char *jolietname = NULL, *rrname = NULL;
 	struct iso_tree_file *file;
-
+	
 	if (!(dfile && *dfile))
 		return ret;
+	if (!(ddir && *ddir))
+		return ret;
 	if (!fullname)
 		return ret;
 
 	file = *dfile;
-
+	
 	name = strdup(fullname);
 	iso_split_filename(name, &ext);
 
 	if (!(strlen(name) || strlen(ext)))
 		goto set_name_done;
 
-	isoname1 = get_iso_name_1(name, ext);
+	for (i = -1; (i < 1000) && !isoname1; ++i) {
+		isoname1 = get_iso_name_1(name, ext, i);
+		if (isoname1 && file_dup_iso_name_1(*ddir, isoname1)) {
+			free (isoname1);
+			isoname1 = NULL;
+		}
+	}
 	if (!isoname1)
 		goto set_name_fail;
 	isoname2 = get_iso_name_2(name, ext);
@@ -312,9 +354,26 @@ const char *iso_tree_dir_get_name(struct
 	return NULL;
 }
 
+static int dir_dup_iso_name_1(struct iso_tree_dir *dir, const char *name)
+{
+	int i, retval = 0;
+	const char *isoname;
+	
+	if (!dir || !name)
+		return retval;
+	
+	for (i = 0; (i < dir->nchildren) && !retval; ++i) {
+		isoname = dir->children[i].isoname1;
+		if (isoname && !strcmp (isoname, name))
+			retval = 1;
+	}
+	
+	return retval;
+}
+
 int iso_tree_dir_set_name(struct iso_tree_dir **ddir, const char *name)
 {
-	int ret = 0;
+	int i, ret = 0;
 	char *isoname1 = NULL, *isoname2 = NULL;
 	char *jolietname = NULL, *rrname = NULL;
 	struct iso_tree_dir *dir;
@@ -326,7 +385,14 @@ int iso_tree_dir_set_name(struct iso_tre
 
 	dir = *ddir;
 
-	isoname1 = iso_d_strndup(name, 8);
+	/* XXX Do we need to set dir->isoname = NULL first? */
+	for (i = -1; (i < 1000) && !isoname1; ++i) {
+		isoname1 = get_iso_name_1(name, NULL, i);
+		if (isoname1 && dir_dup_iso_name_1(dir->parent, isoname1)) {
+			free (isoname1);
+			isoname1 = NULL;
+		}
+	}
 	isoname2 = iso_d_strndup(name, 31);
 	jolietname = NULL;
 	rrname = NULL;
Index: libisofs/writer.c
===================================================================
RCS file: /cvs/burn/burn/libisofs/writer.c,v
retrieving revision 1.16
diff -p -u -r1.16 writer.c
--- libisofs/writer.c	24 Feb 2004 18:37:46 -0000	1.16
+++ libisofs/writer.c	5 Mar 2004 05:33:00 -0000
@@ -3,6 +3,7 @@
 #include "writer.h"
 #include "util.h"
 #include "volume.h"
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -17,12 +18,15 @@ enum dir_type
 	DIR_TYPE_NORMAL
 };
 
+static int get_path_table_size(struct iso_tree_dir **ddir);
 static void iso_next_state(struct iso_write_target *target);
 static int iso_source_get_size(struct burn_source *src);
 static void iso_source_free(struct burn_source *src);
 static void iso_target_layout(struct iso_write_target *target);
 static void iso_dir_layout(struct iso_write_target *target,
 			   struct iso_tree_dir **dir);
+static void iso_file_layout(struct iso_write_target *target,
+			    struct iso_tree_dir **dir);
 static int iso_write_system_area(struct iso_write_target *t,
 				 unsigned char *buffer,
 				 enum burn_source_status *err);
@@ -32,29 +36,51 @@ static int iso_write_pri_volume(struct i
 static int iso_write_volume_terminator(struct iso_write_target *t,
 				       unsigned char *buffer,
 				       enum burn_source_status *err);
+static int write_path_table_record(unsigned char *buffer,
+				   struct iso_tree_dir **ddir, int *position,
+				   int lsb);
+static int write_path_table_records(unsigned char *buffer,
+				    struct iso_tree_dir **ddir,
+				    int level, int *position, int lsb);
 static int iso_write_path_table(struct iso_write_target *t,
 				unsigned char *buffer,
 				enum burn_source_status *err, int lsb);
 static int iso_write_dir_record(struct iso_write_target *target,
 				unsigned char *buffer,
 				struct iso_tree_dir **dir, enum dir_type type);
+static int iso_write_file_record(struct iso_write_target *t,
+				 unsigned char *buffer,
+				 struct iso_tree_file **ffile, 
+				 enum dir_type type);
 static void iso_write_file_id(unsigned char *buf, int size,
 			      struct iso_tree_file **f);
+static struct iso_tree_dir **find_dir_at_block(struct iso_tree_dir **ddir, 
+					       int block);
+static struct iso_tree_file **find_file_at_block(struct iso_tree_dir **ddir, 
+						 int block);
+static void write_child_records(struct iso_write_target *t,
+				unsigned char *buffer, 
+				enum burn_source_status *err, 
+				struct iso_tree_dir *dir);
 static int iso_write_dir_records(struct iso_write_target *t,
 				 unsigned char *buffer,
 				 enum burn_source_status *err);
-static int get_path_table_size(struct iso_tree_dir **ddir);
 static int get_directory_record_length(const char *isoname);
+static int copy_file_to_buffer(FILE * fd, unsigned char *buffer, int length);
+static int iso_write_files(struct iso_write_target *t,
+			   unsigned char *buffer,
+			   enum burn_source_status *err);
 
 int get_path_table_size(struct iso_tree_dir **ddir)
 {
+	const char *isoname;
 	int i, size = 0;
 	struct iso_tree_dir *dir = *ddir;
-	const char *isoname;
 
 	assert(dir);
 
 	isoname = iso_tree_dir_get_name(ddir, ISO_FILE_NAME_ISO);
+
 	if (isoname) {
 		/* a path table record is 8 bytes + the length of the
 		   directory identifier */
@@ -65,8 +91,8 @@ int get_path_table_size(struct iso_tree_
 		size += 10;
 	}
 
-	/* pad the field if the directory identifier is an odd number of bytes 
-	 */
+	/* pad the field if the directory identifier is an odd number of
+	   bytes */
 	if (size % 2)
 		++size;
 
@@ -107,6 +133,7 @@ struct burn_source *iso_source_new(struc
 	src->read_sub = NULL;
 	src->get_size = iso_source_get_size;
 	src->data = t;
+
 	return src;
 }
 
@@ -119,6 +146,8 @@ void iso_source_free(struct burn_source 
 
 	iso_volumeset_free(target->volset);
 	free(target);
+
+	return;
 }
 
 int get_directory_record_length(const char *isoname)
@@ -134,74 +163,107 @@ int get_directory_record_length(const ch
 	return size;
 }
 
-void
-iso_dir_layout(struct iso_write_target *target, struct iso_tree_dir **ddir)
+/* fill in the 'logical_block' and 'size' values for each directory */
+void iso_dir_layout(struct iso_write_target *target,
+		    struct iso_tree_dir **ddir)
 {
-	int i, length;
+	int i, length, sectors;
+	const char *name;
 	struct iso_tree_dir *dir = *ddir;
 
-	dir->logical_block = target->logical_block++;
-	length = 0;
+	/* each directory record starts with a record pointing to itself
+	   and another pointing to its parent; combined, they are 68 bytes */
+	length = 68;
 
+	/* calculate the length of this directory */
+	name = iso_tree_dir_get_name(ddir, ISO_FILE_NAME_ISO);
+	if (name)
+		length += get_directory_record_length(name);
+	else
+		length += get_directory_record_length("");
+	
 	for (i = 0; i < dir->nfiles; ++i) {
-		const char *name;
-
-		/* XXX: need to get size of files and all that stuff */
-		dir->files[i].logical_block = 0;
-		dir->files[i].size = 0;
 		name = iso_tree_file_get_name(dir->files[i].me,
 					      ISO_FILE_NAME_ISO);
 		length += get_directory_record_length(name);
 	}
 
 	for (i = 0; i < dir->nchildren; ++i) {
-		const char *name;
-
-		iso_dir_layout(target, dir->children[i].me);
-		name = iso_tree_file_get_name(dir->files[i].me,
-					      ISO_FILE_NAME_ISO);
+		name = iso_tree_dir_get_name(dir->children[i].me,
+					     ISO_FILE_NAME_ISO);
 		length += get_directory_record_length(name);
 	}
 
 	/* 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;
+	sectors = length / target->phys_sector_size;
+	if (length % target->phys_sector_size)
+		sectors++;
+	dir->size = sectors * target->phys_sector_size;
+	dir->logical_block = target->logical_block;
+	target->logical_block += sectors;
+
+	/* now calculate the lengths of its children */
+	for (i = 0; i < dir->nchildren; ++i) {
+		iso_dir_layout(target, dir->children[i].me);
+	}
+	
+	return;
+}
+
+/* fill in the 'logical_block' and 'size' values for each file */
+void iso_file_layout(struct iso_write_target *target,
+		     struct iso_tree_dir **ddir)
+{
+	int i, sectors;
+	struct iso_tree_dir *dir = *ddir;
+
+	for (i = 0; i < dir->nfiles; ++i) {
+		dir->files[i].logical_block = target->logical_block;
+		sectors = dir->files[i].size / target->phys_sector_size;
+		if (dir->files[i].size % target->phys_sector_size)
+			sectors++;
+		target->logical_block += sectors;
+	}
+
+	for (i = 0; i < dir->nchildren; ++i)
+		iso_file_layout(target, dir->children[i].me);
+
+	return;
 }
 
 void iso_target_layout(struct iso_write_target *target)
 {
 	/* logical block numbering starts at 1, not 0 */
 	target->logical_block = 1;
-	target->total_size = 0;
 	/* system area */
 	target->logical_block += 16;
-	target->total_size += 16 * target->phys_sector_size;
 	/* primary volume descriptor */
 	target->logical_block++;
-	target->total_size += target->phys_sector_size;
 	/* volume descriptor terminator */
 	target->logical_block++;
-	target->total_size += target->phys_sector_size;
-
-	/* 16 logical blocks for the System Area plus at least 2 for the Data
-	   Area (primary volume and volume terminator) */
-	target->volume_space_size = 18;
+	
 	target->logical_block_size = 2048;
 	target->path_table_size = get_path_table_size(target->volset->root);
 	/* put a 1-block buffer before each path table */
 	target->l_path_table_pos = 19;
-	target->volume_space_size += 2;
 	target->logical_block += 2;
 	target->total_size += 2 * target->phys_sector_size;
 	/* put a 1-block buffer before each path table */
 	target->m_path_table_pos = 21;
-	target->volume_space_size += 2;
 	target->logical_block += 2;
-	target->total_size += 2 * target->phys_sector_size;
-
+	
 	iso_dir_layout(target, target->volset->root);
+	/* iso_write_dir_records() puts a 1-block buffer between the directory
+	   section and the file section, so increment this accordingly */
+	target->logical_block++;
+	iso_file_layout(target, target->volset->root);
+	
+	target->volume_space_size = target->logical_block + 2;
+	target->total_size = target->volume_space_size * target->phys_sector_size;
+	
+	return;
 }
 
 int iso_source_get_size(struct burn_source *src)
@@ -225,6 +287,7 @@ void iso_next_state(struct iso_write_tar
 		target->state_data.system_area.sectors = 0;
 		break;
 	case ISO_WRITE_PRI_VOL_DESC:
+		target->total_size = target->logical_block - 1;
 		break;
 	case ISO_WRITE_VOL_DESC_TERMINATOR:
 		break;
@@ -237,13 +300,18 @@ void iso_next_state(struct iso_write_tar
 	case ISO_WRITE_DIR_RECORDS:
 		target->state_data.dir_records.sectors = 0;
 		break;
+	case ISO_WRITE_FILES:
+		target->state_data.dir_records.sectors = 0;
+		break;
 	case ISO_WRITE_DONE:
 		break;
 	}
+
+	return;
 }
 
-int
-iso_source_generate(struct burn_source *src, unsigned char *buffer, int size)
+int iso_source_generate(struct burn_source *src, unsigned char *buffer,
+			int size)
 {
 	int next = 0;
 	enum burn_source_status err = BURN_SOURCE_OK;
@@ -284,6 +352,9 @@ iso_source_generate(struct burn_source *
 	case ISO_WRITE_DIR_RECORDS:
 		next = iso_write_dir_records(target, buffer, &err);
 		break;
+	case ISO_WRITE_FILES:
+		next = iso_write_files(target, buffer, &err);
+		break;
 	case ISO_WRITE_DONE:
 		err = BURN_SOURCE_EOF;
 		break;
@@ -296,9 +367,8 @@ iso_source_generate(struct burn_source *
 }
 
 /* writes 16 sectors of '0' */
-int
-iso_write_system_area(struct iso_write_target *t,
-		      unsigned char *buffer, enum burn_source_status *err)
+int iso_write_system_area(struct iso_write_target *t,
+			  unsigned char *buffer, enum burn_source_status *err)
 {
 	struct iso_state_system_area *state = &t->state_data.system_area;
 
@@ -307,9 +377,8 @@ iso_write_system_area(struct iso_write_t
 }
 
 /* writes the primary volume descriptor */
-int
-iso_write_pri_volume(struct iso_write_target *t,
-		     unsigned char *buffer, enum burn_source_status *err)
+int iso_write_pri_volume(struct iso_write_target *t,
+			 unsigned char *buffer, enum burn_source_status *err)
 {
 	/* volume descriptor type (8.4.1) */
 	buffer[0] = 1;
@@ -396,10 +465,9 @@ void iso_write_file_id(unsigned char *bu
 			    (*f)->version);
 }
 
-int
-iso_write_dir_record(struct iso_write_target *t,
-		     unsigned char *buffer,
-		     struct iso_tree_dir **ddir, enum dir_type type)
+int iso_write_dir_record(struct iso_write_target *t,
+			 unsigned char *buffer,
+			 struct iso_tree_dir **ddir, enum dir_type type)
 {
 	int len_fi;
 	const char *fi = NULL;
@@ -455,19 +523,18 @@ iso_write_dir_record(struct iso_write_ta
 }
 
 /* write the file record as per (9.1) */
-int
-iso_write_file_record(struct iso_write_target *t,
-		      unsigned char *buffer,
-		      struct iso_tree_file **ffile, enum dir_type type)
+int iso_write_file_record(struct iso_write_target *t,
+			  unsigned char *buffer,
+			  struct iso_tree_file **ffile, enum dir_type type)
 {
 	int len_fi;
 	const char *fi = NULL;
 	int sz;
 	struct iso_tree_file *file = *ffile;
 
-	if (type != DIR_TYPE_NORMAL) {
+	if (type != DIR_TYPE_NORMAL)
 		len_fi = 1;
-	} else {
+	else {
 		fi = iso_tree_file_get_name(ffile, ISO_FILE_NAME_ISO);
 		len_fi = strlen(fi);
 	}
@@ -513,10 +580,9 @@ iso_write_file_record(struct iso_write_t
 }
 
 /* writes the volume descriptor set terminator */
-int
-iso_write_volume_terminator(struct iso_write_target *t,
-			    unsigned char *buffer,
-			    enum burn_source_status *err)
+int iso_write_volume_terminator(struct iso_write_target *t,
+				unsigned char *buffer, 
+				enum burn_source_status *err)
 {
 	/* volume descriptor type (8.3.1) */
 	buffer[0] = 255;
@@ -531,9 +597,8 @@ iso_write_volume_terminator(struct iso_w
 }
 
 /* write the path record for 'ddir' into 'buffer' */
-int
-write_path_table_record(unsigned char *buffer,
-			struct iso_tree_dir **ddir, int *position, int lsb)
+int write_path_table_record(unsigned char *buffer,
+			    struct iso_tree_dir **ddir, int *position, int lsb)
 {
 	int len, bytes_written;
 	short parent_position;
@@ -588,12 +653,11 @@ write_path_table_record(unsigned char *b
  * 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. */
-int
-write_path_table_records(unsigned char *buffer,
-			 struct iso_tree_dir **ddir,
-			 int level, int *position, int lsb)
+int write_path_table_records(unsigned char *buffer,
+			     struct iso_tree_dir **ddir,
+			     int level, int *position, int lsb)
 {
-	int offset;
+	int i, offset;
 	struct iso_tree_dir *dir = *ddir;
 
 	/* ISO9660 only allows directories to be nested 8-deep */
@@ -603,15 +667,12 @@ write_path_table_records(unsigned char *
 	if (!level) {
 		offset = write_path_table_record(buffer, ddir, position, lsb);
 	} else {
-		int i;
-
 		offset = 0;
 		for (i = 0; i < dir->nchildren; ++i) {
-			offset +=
-				write_path_table_records(buffer + offset,
-							 dir->children[i].me,
-							 level - 1,
-							 position, lsb);
+			offset += write_path_table_records(buffer + offset,
+							   dir->children[i].me,
+							   level - 1,
+							   position, lsb);
 		}
 	}
 
@@ -619,10 +680,9 @@ write_path_table_records(unsigned char *
 }
 
 /* writes set of path table records */
-int
-iso_write_path_table(struct iso_write_target *t,
-		     unsigned char *buffer,
-		     enum burn_source_status *err, int lsb)
+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;
@@ -650,26 +710,38 @@ struct iso_tree_dir **find_dir_at_block(
 	struct iso_tree_dir *dir = *ddir;
 	struct iso_tree_dir **to_write = NULL;
 
-	if (dir->logical_block == block) {
+	if (dir->logical_block == block)
 		to_write = ddir;
-	} else {
-		for (i = 0; (i < dir->nchildren) && !to_write; ++i) {
-			to_write = find_dir_at_block(dir->children[i].me,
-						     block);
-		}
+
+	for (i = 0; (i < dir->nchildren) && !to_write; ++i) {
+		to_write = find_dir_at_block(dir->children[i].me, block);
 	}
 
-	if (to_write)
-		return to_write;
-	else
-		return NULL;
+	return to_write;
+}
+
+struct iso_tree_file **find_file_at_block(struct iso_tree_dir **ddir, int block)
+{
+	int i;
+	struct iso_tree_dir *dir = *ddir;
+	struct iso_tree_file **to_write = NULL;
+
+	for (i = 0; (i < dir->nfiles) && !to_write; ++i) {
+		if (dir->files[i].logical_block == block)
+			to_write = dir->files[i].me;
+	}
+
+	for (i = 0; (i < dir->nchildren) && !to_write; ++i) {
+		to_write = find_file_at_block(dir->children[i].me, block);
+	}
+
+	return to_write;
 }
 
 /* write the records for children of 'dir' */
-void
-write_child_records(struct iso_write_target *t,
-		    unsigned char *buffer,
-		    enum burn_source_status *err, struct iso_tree_dir *dir)
+void write_child_records(struct iso_write_target *t,
+			 unsigned char *buffer,
+			 enum burn_source_status *err, struct iso_tree_dir *dir)
 {
 	int file_counter, dir_counter, order, offset;
 
@@ -690,7 +762,6 @@ write_child_records(struct iso_write_tar
 				 ISO_FILE_NAME_ISO);
 			order = strcmp(dirname, filename);
 		} else {
-
 			if (file_counter < dir->nfiles)
 				/* only files are left */
 				order = 1;
@@ -700,15 +771,18 @@ write_child_records(struct iso_write_tar
 		}
 
 		if (order < 0) {
-			offset += iso_write_dir_record
-				(t, buffer + offset,
-				 dir->children[dir_counter].me,
-				 DIR_TYPE_NORMAL);
+			offset += iso_write_dir_record(t,
+						       buffer + offset,
+						       dir->
+						       children[dir_counter].
+						       me, DIR_TYPE_NORMAL);
 			dir_counter++;
 		} else {
-			offset += iso_write_file_record
-				(t, buffer + offset,
-				 dir->files[file_counter].me, DIR_TYPE_NORMAL);
+			offset += iso_write_file_record(t,
+							buffer + offset,
+							dir->
+							files[file_counter].me,
+							DIR_TYPE_NORMAL);
 			file_counter++;
 		}
 
@@ -718,14 +792,13 @@ write_child_records(struct iso_write_tar
 }
 
 /* write out the next directory record */
-int
-iso_write_dir_records(struct iso_write_target *t,
-		      unsigned char *buffer, enum burn_source_status *err)
+int iso_write_dir_records(struct iso_write_target *t,
+			  unsigned char *buffer, enum burn_source_status *err)
 {
 	int finished, offset;
 	struct iso_tree_dir **ddir, *dir;
 	struct iso_state_dir_records *state = &t->state_data.dir_records;
-
+	
 	finished = 0;		/* set to 1 when all directory records have
 				   been written */
 
@@ -733,11 +806,10 @@ iso_write_dir_records(struct iso_write_t
 		/* t->logical_block is the next block to write.  find the dir
 		   record which belongs there and write it out.  if none
 		   exists, we're done writing the directory records. */
-
+		
 		ddir = find_dir_at_block(t->volset->root, t->logical_block);
-		if (!ddir) {
-			finished = 1;
-		} else {
+		
+		if (ddir) {
 			/* 1) write the record for this directory 2) write the 
 			   record for the parent directory 3) write the
 			   records for all child files and directories */
@@ -747,24 +819,104 @@ iso_write_dir_records(struct iso_write_t
 						      ddir, DIR_TYPE_SELF);
 			if (!dir->parent) {
 				/* this is the root directory */
-				offset +=
-					iso_write_dir_record(t,
-							     buffer + offset,
-							     ddir,
-							     DIR_TYPE_PARENT);
+				offset += iso_write_dir_record(t,
+							       buffer + offset,
+							       ddir,
+							       DIR_TYPE_PARENT);
 			} else {
-				offset +=
-					iso_write_dir_record(t,
-							     buffer + offset,
-							     dir->parent->me,
-							     DIR_TYPE_PARENT);
+				offset += iso_write_dir_record(t,
+							       buffer + offset,
+							       dir->parent->me,
+							       DIR_TYPE_PARENT);
 			}
 
 			write_child_records(t, buffer + offset, err, dir);
 
-			t->logical_block++;
+			/* dir->size should always be a multiple of
+			   t->phys_sector_size */
+			t->logical_block += (dir->size / t->phys_sector_size);
+		} else {
+			/* we just wrote out 2048 0's, so we still need to
+			   increment this */
+			t->logical_block++; 
+			finished = 1;
 		}
 	}
 
 	return finished;
 }
+
+int copy_file_to_buffer(FILE * fd, unsigned char *buffer, int length)
+{
+	int read;
+
+	read = fread(buffer, 1, length, fd);
+
+	return read;
+}
+
+int iso_write_files(struct iso_write_target *t,
+		    unsigned char *buffer, enum burn_source_status *err)
+{
+	FILE *fd;
+	int finished, sectors;
+	struct iso_tree_file **ffile, *file;
+	struct iso_state_files *state = &t->state_data.files;
+	
+	finished = 0;
+
+	if (state->sectors) {
+		/* continue writing the file at 't->logical_block' to
+		   'buffer', then incremenet 't->logical_block' to the next
+		   file section. */
+
+		fd = t->current_fd;
+		file = *(t->current_file);
+
+		/* copy one sector of 'ffile' into 'buffer' */
+		state->sectors +=
+			copy_file_to_buffer(fd, buffer, t->phys_sector_size);
+
+		if (feof(fd)) {
+			fclose(fd);
+			state->sectors = 0;
+			sectors = file->size / t->phys_sector_size;
+			if (file->size % t->phys_sector_size)
+				sectors++;
+			t->logical_block += sectors;
+		}
+	} else {
+		/* start writing the file at 't->logical_block' to 'buffer'.
+		   if none exists, we are done. */
+		ffile = find_file_at_block(t->volset->root, t->logical_block);
+		if (ffile) {
+			t->current_file = ffile;
+			file = *ffile;
+			fd = fopen(file->path, "r");
+			t->current_fd = fd;
+
+			if (fd) {
+				state->sectors += copy_file_to_buffer(fd,
+								      buffer,
+								      t->
+								      phys_sector_size);
+			}
+
+			if (feof(fd)) {
+				fclose(fd);
+				fd = NULL;
+			}
+
+			if (!fd) {
+				state->sectors = 0;
+				sectors = file->size / t->phys_sector_size;
+				if (file->size % t->phys_sector_size)
+					sectors++;
+				t->logical_block += sectors;
+			}
+		} else
+			finished = 1;
+	}
+
+	return finished;
+}
Index: libisofs/writer.h
===================================================================
RCS file: /cvs/burn/burn/libisofs/writer.h,v
retrieving revision 1.11
diff -p -u -r1.11 writer.h
--- libisofs/writer.h	24 Feb 2004 18:37:46 -0000	1.11
+++ libisofs/writer.h	5 Mar 2004 05:33:00 -0000
@@ -5,6 +5,7 @@
 
 #include "libisofs.h"
 
+#include <stdio.h>
 #include <string.h>
 #include <time.h>
 
@@ -18,6 +19,7 @@ enum iso_write_state
 	ISO_WRITE_L_PATH_TABLE,
 	ISO_WRITE_M_PATH_TABLE,
 	ISO_WRITE_DIR_RECORDS,
+	ISO_WRITE_FILES,
 
 	ISO_WRITE_DONE
 };
@@ -25,13 +27,13 @@ enum iso_write_state
 /** File Flags (9.1.6) */
 enum
 {
+	ISO_FILE_FLAG_NORMAL = 0,
 	ISO_FILE_FLAG_HIDDEN = 1 << 0,
 	ISO_FILE_FLAG_DIRECTORY = 1 << 1,
 	ISO_FILE_FLAG_ASSOCIATED = 1 << 2,
 	ISO_FILE_FLAG_RECORD = 1 << 3,
 	ISO_FILE_FLAG_PROTECTION = 1 << 4,
-	ISO_FILE_FLAG_MULTIEXTENT = 1 << 7,
-	ISO_FILE_FLAG_NORMAL = 0
+	ISO_FILE_FLAG_MULTIEXTENT = 1 << 7
 };
 
 struct iso_write_target
@@ -60,6 +62,9 @@ struct iso_write_target
 	int l_path_table_pos;
 	/* Locations of Type M Path Table (Logical Block Number) */
 	int m_path_table_pos;
+	/* Current file being written in iso_write_files() */
+	struct iso_tree_file **current_file;
+	FILE *current_fd;
 
 	/* what we're doing when the generate function gets called next */
 	enum iso_write_state state;
@@ -83,6 +88,12 @@ struct iso_write_target
 			   been written */
 			int sectors;
 		} dir_records;
+		struct iso_state_files
+		{
+			/* how many sectors in the current file have been
+			   written */
+			int sectors;
+		} files;
 	} state_data;
 };
 

--=-LUoi30Hkw15Qt146VP6t--