[Libburn] libisofs cleanup & crash fix (now with file support!)
Todd Kulesza
todd@dropline.net
Thu, 26 Feb 2004 00:27:23 -0500
--=-GD+3Et5FTDFAvTfqQc7m
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
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
--=-GD+3Et5FTDFAvTfqQc7m
Content-Disposition: attachment; filename=libisofs.diff
Content-Type: text/x-patch; name=libisofs.diff; charset=UTF-8
Content-Transfer-Encoding: 7bit
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 26 Feb 2004 05:24:56 -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 26 Feb 2004 05:24:56 -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;
};
--=-GD+3Et5FTDFAvTfqQc7m--