[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freedesktop-libburn
Subject:    [Libburn] libisofs cleanup & crash fix
From:       Todd Kulesza <todd () dropline ! net>
Date:       2004-02-25 23:05:26
Message-ID: 1077750326.19653.11.camel () llyr ! dropline ! net
[Download RAW message or body]

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

["libisofs.diff" (libisofs.diff)]

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	25 Feb 2004 22:55:11 -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,8 +163,9 @@ 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;
 	struct iso_tree_dir *dir = *ddir;
@@ -146,9 +176,6 @@ iso_dir_layout(struct iso_write_target *
 	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);
@@ -157,10 +184,11 @@ iso_dir_layout(struct iso_write_target *
 	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);
+
+		iso_dir_layout(target, dir->children[i].me);
 	}
 
 	/* dir->size is the number of bytes needed to hold the directory
@@ -168,6 +196,27 @@ iso_dir_layout(struct iso_write_target *
 	   all of the bytes of a physical sector. */
 	dir->size = ((length / target->phys_sector_size) + 1)
 		* target->phys_sector_size;
+
+	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;
+	struct iso_tree_dir *dir = *ddir;
+
+	for (i = 0; i < dir->nfiles; ++i) {
+		dir->files[i].logical_block = target->logical_block;
+		target->logical_block +=
+			((dir->files[i].size / target->phys_sector_size) + 1);
+	}
+
+	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)
@@ -202,6 +251,7 @@ void iso_target_layout(struct iso_write_
 	target->total_size += 2 * target->phys_sector_size;
 
 	iso_dir_layout(target, target->volset->root);
+	iso_file_layout(target, target->volset->root);
 }
 
 int iso_source_get_size(struct burn_source *src)
@@ -237,13 +287,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 +339,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 +354,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 +364,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 +452,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 +510,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 +567,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 +584,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 +640,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 +654,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 +667,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 +697,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 +749,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 +758,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,9 +779,8 @@ 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;
@@ -735,9 +795,7 @@ iso_write_dir_records(struct iso_write_t
 		   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,23 +805,96 @@ 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
+			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;
+	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;
+			t->logical_block +=
+				((file->size / t->phys_sector_size) + 1);
 		}
+	} 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;
+				t->logical_block +=
+					((file->size / t->phys_sector_size) +
+					 1);
+			}
+		} 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	25 Feb 2004 22:55:11 -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;
 };
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic