[Libburn] libisofs patch (3rd revision)
Todd Kulesza
todd@dropline.net
Mon, 23 Feb 2004 00:40:15 -0500
--=-fMZma97fpKrRtkm/7Dmr
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
OK, last patch for tonight, I promise... This one adds support for
writing the directory and file structure. All that remains is to write
the files themselves and libisofs will be (sort of) functional; it
should be able to write level-1 ISOs, at any rate. Right now the files
it writes are all of size 0:
root@llyr:/home/fflew# ls -l /mnt/tmp/
total 6
-r-xr-xr-x 1 root root 0 Feb 23 00:21 anothertest2_txt*
-r-xr-xr-x 1 root root 0 Feb 23 00:21 anothertest_txt*
dr-xr-xr-x 1 root root 2048 Feb 23 00:21 folder1/
dr-xr-xr-x 1 root root 2048 Feb 23 00:21 folder2/
dr-xr-xr-x 1 root root 2048 Feb 23 00:21 folder3/
-r-xr-xr-x 1 root root 0 Feb 23 00:21 test_txt*
-r-xr-xr-x 1 root root 0 Feb 23 00:21
zinstallpkg_0_4_1_i686_1nis_tgz*
root@llyr:/home/fflew#
I've tried to keep the coding style consistent with what already existed
in libisofs. Let me know if there's anything to clean up or styled
differently.
Todd
On Sun, 2004-02-22 at 17:39, Todd Kulesza wrote:
> Here's another cumulative patch. It includes all of the changes from my
> last two, plus partial support for writing out directory records.
> libisofs can finally create ISO images which are successfully detected
> as valid ISO9660 filesystems! (they're completely empty filesystems, but
> still... ;)
>
> Todd
>
> On Mon, 2004-02-16 at 01:55, Todd Kulesza wrote:
> > 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
> > >
> > >
--=-fMZma97fpKrRtkm/7Dmr
Content-Disposition: attachment; filename=libisofs.diff
Content-Type: text/x-patch; name=libisofs.diff; charset=UTF-8
Content-Transfer-Encoding: 7bit
? 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 23 Feb 2004 05:33:30 -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 23 Feb 2004 05:33:31 -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 23 Feb 2004 05:33:31 -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 23 Feb 2004 05:33:32 -0000
@@ -10,6 +10,13 @@
#define APPLICATION_ID "LIBBURN SUITE (C) 2002 D.FOREMAN/B.JANSENS"
+enum dir_type
+{
+ DIR_TYPE_SELF,
+ DIR_TYPE_PARENT,
+ DIR_TYPE_NORMAL
+};
+
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);
@@ -31,9 +38,13 @@ static int iso_write_path_table (struct
int lsb);
static int iso_write_dir_record (struct iso_write_target *target,
unsigned char *buffer,
- struct iso_tree_dir **dir);
+ struct iso_tree_dir **dir,
+ enum dir_type type);
static void iso_write_file_id (unsigned char *buf, int size,
struct iso_tree_file **f);
+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)
@@ -43,8 +54,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 +64,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 +121,47 @@ 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) {
+ /* XXX: need to get size of files and all that stuff */
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
@@ -145,12 +185,12 @@ iso_target_layout (struct iso_write_targ
target->volume_space_size = 18;
target->logical_block_size = 2048;
target->path_table_size = get_path_table_size (target->volset->root);
- /* leave a 1-block buffer after each path table */
+ /* 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;
- /* leave a 1-block buffer after each path table */
+ /* put a 1-block buffer before each path table */
target->m_path_table_pos = 21;
target->volume_space_size += 2;
target->logical_block += 2;
@@ -193,6 +233,9 @@ iso_next_state (struct iso_write_target
case ISO_WRITE_M_PATH_TABLE:
target->state_data.path_tables.sectors = 0;
break;
+ case ISO_WRITE_DIR_RECORDS:
+ target->state_data.dir_records.sectors = 0;
+ break;
case ISO_WRITE_DONE:
break;
}
@@ -211,11 +254,13 @@ iso_source_generate (struct burn_source
src->read_sub == NULL &&
src->get_size == iso_source_get_size);
-
/* make sure the app didn't fuck up badly. */
if (size != target->phys_sector_size)
return BURN_SOURCE_FAILED; /* XXX better code */
+ /* make sure 'buffer' doesn't have anything in it */
+ memset (buffer, 0, size);
+
switch (target->state)
{
case ISO_WRITE_BEFORE:
@@ -225,6 +270,9 @@ iso_source_generate (struct burn_source
next = iso_write_system_area (target, buffer, &err);
break;
case ISO_WRITE_PRI_VOL_DESC:
+ /* set target->logical_block to the logical block containing
+ * the root directory record */
+ target->logical_block = 23;
next = iso_write_pri_volume (target, buffer, &err);
break;
case ISO_WRITE_VOL_DESC_TERMINATOR:
@@ -236,6 +284,9 @@ iso_source_generate (struct burn_source
case ISO_WRITE_M_PATH_TABLE:
next = iso_write_path_table (target, buffer, &err, 0);
break;
+ case ISO_WRITE_DIR_RECORDS:
+ next = iso_write_dir_records (target, buffer, &err);
+ break;
case ISO_WRITE_DONE:
err = BURN_SOURCE_EOF;
break;
@@ -302,7 +353,7 @@ iso_write_pri_volume (struct iso_write_t
/* location of optional occurance of type m path table (8.4.17) */
iso_msb (&buffer[152], 0, 4);
/* directory record for root directory (8.4.18) */
- iso_write_dir_record (t, &buffer[156], t->volset->root);
+ iso_write_dir_record (t, &buffer[156], t->volset->root, DIR_TYPE_SELF);
/* volume set identifier (8.4.19) */
iso_d_strcpy (&buffer[190], 128, t->volset->volumeset_id);
/* publisher identifier (8.4.20) */
@@ -355,16 +406,18 @@ iso_write_file_id (unsigned char *buf, i
int
iso_write_dir_record (struct iso_write_target *t,
unsigned char *buffer,
- struct iso_tree_dir **ddir)
+ struct iso_tree_dir **ddir,
+ enum dir_type type)
{
int len_fi;
const char *fi = NULL;
int sz;
struct iso_tree_dir *dir = *ddir;
- if (!dir->fullname)
+ if (type != DIR_TYPE_NORMAL)
len_fi = 1;
else {
+ assert (dir->parent);
fi = iso_tree_dir_get_name (ddir, ISO_FILE_NAME_ISO);
len_fi = strlen (fi);
}
@@ -392,10 +445,72 @@ iso_write_dir_record (struct iso_write_t
/* length of file identifier (9.1.10) */
buffer[32] = len_fi;
/* file identifier */
- if (!dir->fullname)
+ if (type == DIR_TYPE_SELF)
buffer[33] = 0;
else
- iso_d_strcpy (&buffer[33], len_fi, fi);
+ {
+ if (type == DIR_TYPE_PARENT)
+ buffer[33] = 1;
+ else
+ iso_d_strcpy (&buffer[33], len_fi, fi);
+ }
+ if (!(len_fi % 2))
+ buffer[33 + len_fi] = 0;
+
+ return sz;
+}
+
+/* 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 len_fi;
+ const char *fi = NULL;
+ int sz;
+ struct iso_tree_file *file = *ffile;
+
+ if (type != DIR_TYPE_NORMAL)
+ len_fi = 1;
+ else {
+ fi = iso_tree_file_get_name (ffile, ISO_FILE_NAME_ISO);
+ len_fi = strlen (fi);
+ }
+
+ sz = 33 + len_fi + !(len_fi % 2);
+
+ /* length of directory record (9.1.1) */
+ buffer[0] = sz;
+ /* extended attribute record length (9.1.2) */
+ buffer[1] = 0; /* XXX allow for extended attribute records */
+ /* location of extent (9.1.3) */
+ iso_bb (&buffer[2], file->logical_block, 4);
+ /* data length (9.1.4) */
+ iso_bb (&buffer[10], file->size, 4);
+ /* recording date and time (9.1.5) */
+ iso_datetime_7(&buffer[18], t->now);
+ /* file flags (9.1.6) */
+ buffer[25] = ISO_FILE_FLAG_NORMAL;
+ /* file unit size (9.1.7) */
+ buffer[26] = 0; /* XXX support this shit? */
+ /* interleave gap size (9.1.8) */
+ buffer[27] = 0; /* XXX support this shit? */
+ /* volume sequence number (9.1.9) */
+ iso_bb (&buffer[28], file->volume + 1, 2);
+ /* length of file identifier (9.1.10) */
+ buffer[32] = len_fi;
+ /* file identifier */
+ if (type == DIR_TYPE_SELF)
+ buffer[33] = 0;
+ else
+ {
+ if (type == DIR_TYPE_PARENT)
+ buffer[33] = 1;
+ else
+ iso_d_strcpy (&buffer[33], len_fi, fi);
+ }
if (!(len_fi % 2))
buffer[33 + len_fi] = 0;
@@ -420,21 +535,261 @@ 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);
}
+
+static struct iso_tree_dir **
+find_dir_at_block (struct iso_tree_dir **ddir,
+ int block)
+{
+ int i;
+ struct iso_tree_dir *dir = *ddir;
+ struct iso_tree_dir **to_write = NULL;
+
+ 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);
+ }
+ }
+
+ if (to_write)
+ return to_write;
+ else
+ return NULL;
+}
+
+/* write the records for children of 'dir' */
+static 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;
+
+ file_counter = dir_counter = offset = 0;
+
+ while ((file_counter < dir->nfiles) ||
+ (dir_counter < dir->nchildren))
+ {
+ /* if there are files and dirs, compare them
+ * to figure out which comes 1st alphabetically */
+ if ((file_counter < dir->nfiles) &&
+ (dir_counter < dir->nchildren))
+ {
+ order = strcmp (
+ dir->children[dir_counter].isoname1,
+ dir->files[file_counter].isoname1);
+ }
+ else
+ {
+
+ if (file_counter < dir->nfiles)
+ /* only files are left */
+ order = 1;
+ else
+ /* only dirs are left */
+ order = -1;
+ }
+
+ if (order < 0)
+ {
+ 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);
+ file_counter++;
+ }
+
+ }
+
+ return;
+}
+
+/* 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 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 */
+
+ if (state->sectors++)
+ {
+ /* 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)
+ {
+ /* 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
+ */
+ dir = *ddir;
+ offset = iso_write_dir_record (t,
+ buffer,
+ ddir,
+ DIR_TYPE_SELF);
+ if (!dir->parent)
+ {
+ /* this is the root directory */
+ 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);
+ }
+
+ write_child_records (t, buffer + offset, err, dir);
+
+ t->logical_block++;
+ }
+ else
+ finished = 1;
+ }
+
+ return finished;
+}
Index: libisofs/writer.h
===================================================================
RCS file: /cvs/burn/burn/libisofs/writer.h,v
retrieving revision 1.10
diff -p -u -r1.10 writer.h
--- libisofs/writer.h 10 Feb 2004 12:45:20 -0000 1.10
+++ libisofs/writer.h 23 Feb 2004 05:33:32 -0000
@@ -17,6 +17,7 @@ enum iso_write_state
ISO_WRITE_VOL_DESC_TERMINATOR,
ISO_WRITE_L_PATH_TABLE,
ISO_WRITE_M_PATH_TABLE,
+ ISO_WRITE_DIR_RECORDS,
ISO_WRITE_DONE
};
@@ -29,7 +30,8 @@ enum
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_MULTIEXTENT = 1 << 7,
+ ISO_FILE_FLAG_NORMAL = 0
};
struct iso_write_target
@@ -45,7 +47,8 @@ struct iso_write_target
/* size of the total output */
int total_size;
- /* the next available logical block */
+ /* when compiling the iso, this is the next available logical block.
+ * when writing the iso, this is the next block to write. */
int logical_block;
/* The number of Logical Blocks for the Volume Space */
int volume_space_size;
@@ -71,6 +74,11 @@ struct iso_write_target
written */
int sectors;
} path_tables;
+ struct iso_state_dir_records {
+ /* how many sectors in the directory records area have
+ been written */
+ int sectors;
+ } dir_records;
} state_data;
};
--=-fMZma97fpKrRtkm/7Dmr--