Removed remaining signs of libisofs in libburn tree

ZeroThreeEight
Mario Danic 16 years ago
parent 4f83818ff8
commit 16cbb18f15
  1. 11
      libisofs-1.pc.in
  2. 4
      libisofs/Makefile
  3. 49
      libisofs/Makefile.am
  4. 694
      libisofs/ecma119.c
  5. 267
      libisofs/ecma119.h
  6. 312
      libisofs/ecma119_tree.c
  7. 95
      libisofs/ecma119_tree.h
  8. 42
      libisofs/exclude.c
  9. 12
      libisofs/exclude.h
  10. 158
      libisofs/hash.c
  11. 46
      libisofs/hash.h
  12. 379
      libisofs/joliet.c
  13. 84
      libisofs/joliet.h
  14. 225
      libisofs/libisofs.h
  15. 300
      libisofs/rockridge.c
  16. 26
      libisofs/rockridge.h
  17. 280
      libisofs/susp.c
  18. 62
      libisofs/susp.h
  19. 223
      libisofs/tree.c
  20. 159
      libisofs/tree.h
  21. 584
      libisofs/util.c
  22. 121
      libisofs/util.h
  23. 189
      libisofs/volume.c
  24. 45
      libisofs/volume.h
  25. 107
      test/iso.c
  26. 297
      test/iso.py

@ -1,11 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libisofs
Description: ISO9660 filesystem creation library
Version: @VERSION@
Requires:
Libs: -L${libdir} -lisofs
Cflags: -I${includedir}/libburn

@ -1,4 +0,0 @@
all clean:
$(MAKE) -C .. -$(MAKEFLAGS) $@
.PHONY: all clean

@ -1,49 +0,0 @@
pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn
##bin_PROGRAMS = test
lib_LTLIBRARIES = libisofs.la
libisofs_la_SOURCES = \
tree.h \
tree.c \
volume.h \
volume.c \
util.h \
util.c \
ecma119.c \
ecma119.h \
ecma119_tree.c \
ecma119_tree.h \
susp.h \
susp.c \
rockridge.h \
rockridge.c \
joliet.c \
joliet.h
libinclude_HEADERS = libisofs.h
##test_SOURCES = test.c
##test_LDADD = libisofs.la
##noinst_PROGRAMS = test
##test_SOURCES = test.c
##test_LDADD = $(libisofs_la_OBJECTS)
##INCLUDES = -I../burn/libburn
## ========================================================================= ##
indent_files = $(libisofs_la_SOURCES)
indent: $(indent_files)
indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
-cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
-lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
-sbi0 -nsc -ts8 -npcs -ncdb -fca \
$^
.PHONY: indent
## ========================================================================= ##

@ -1,694 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <err.h>
#include "ecma119.h"
#include "ecma119_tree.h"
#include "susp.h"
#include "rockridge.h"
#include "joliet.h"
#include "volume.h"
#include "tree.h"
#include "util.h"
#include "libisofs.h"
#include "libburn/libburn.h"
/* burn-source compatible stuff */
static int
bs_read(struct burn_source *bs, unsigned char *buf, int size);
static off_t
bs_get_size(struct burn_source *bs);
static void
bs_free_data(struct burn_source *bs);
typedef void (*write_fn)(struct ecma119_write_target*, uint8_t*);
/* return true if the given state is only required for Joliet volumes */
static int
is_joliet_state(enum ecma119_write_state);
static void
next_state(struct ecma119_write_target *t);
/* write t->state_data to the buf, one block at a time */
static void
write_data_chunk(struct ecma119_write_target *t, uint8_t *buf);
/* writing functions. All these functions assume the buf is large enough */
static void
write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
static void
write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf);
static void
write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf);
static void
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
static void
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
static void
write_one_dir_record(struct ecma119_write_target *t,
struct ecma119_tree_node *dir,
int file_id,
uint8_t *buf);
static void
write_one_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *dir,
uint8_t *buf);
static void
write_dirs(struct ecma119_write_target *t, uint8_t *buf);
/* wrapper functions for writing */
static void wr_system_area(struct ecma119_write_target*, uint8_t*);
static void wr_pri_vol_desc(struct ecma119_write_target*, uint8_t*);
static void wr_vol_desc_term(struct ecma119_write_target*, uint8_t*);
static void wr_l_path_table(struct ecma119_write_target*, uint8_t*);
static void wr_m_path_table(struct ecma119_write_target*, uint8_t*);
static void wr_dir_records(struct ecma119_write_target*, uint8_t*);
static void wr_files(struct ecma119_write_target*, uint8_t*);
static const write_fn writers[] =
{
NULL,
wr_system_area,
wr_pri_vol_desc,
joliet_wr_sup_vol_desc,
wr_vol_desc_term,
wr_l_path_table,
wr_m_path_table,
joliet_wr_l_path_table,
joliet_wr_m_path_table,
wr_dir_records,
joliet_wr_dir_records,
wr_files
};
/* When a writer is created, we
* 1) create an ecma119 tree
* 2) add SUSP fields (if necessary)
* 3) calculate the size and position of all nodes in the tree
* 4) finalize SUSP fields (if necessary)
*/
static void
add_susp_fields_rec(struct ecma119_write_target *t,
struct ecma119_tree_node *node)
{
size_t i;
if (!node->iso_self)
return;
rrip_add_PX(t, node);
rrip_add_NM(t, node);
rrip_add_TF(t, node);
if (node->iso_self->attrib.st_rdev)
rrip_add_PN(t, node);
if (S_ISLNK(node->iso_self->attrib.st_mode))
rrip_add_SL(t, node);
if (node->type == ECMA119_FILE && node->file.real_me)
rrip_add_CL(t, node);
if (node->type == ECMA119_DIR
&& node->dir.real_parent != node->parent) {
rrip_add_RE(t, node);
rrip_add_PL(t, node);
}
susp_add_CE(t, node);
if (node->type == ECMA119_DIR) {
for (i = 0; i < node->dir.nchildren; i++) {
add_susp_fields_rec(t, node->dir.children[i]);
}
}
}
static void
add_susp_fields(struct ecma119_write_target *t)
{
susp_add_SP(t, t->root);
rrip_add_ER(t, t->root);
add_susp_fields_rec(t, t->root);
}
/**
* Fill out the dir.len and dir.CE_len fields for each
* ecma119_tree_node that is a directory. Also calculate the total number of
* directories and the number of files for which we need to write out data.
* (dirlist_len and filelist_len)
*/
static void
calc_dir_size(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
assert(dir->type == ECMA119_DIR);
t->dirlist_len++;
dir->dir.len = 34 + dir->dir.self_susp.non_CE_len
+ 34 + dir->dir.parent_susp.non_CE_len;
dir->dir.CE_len = dir->dir.self_susp.CE_len
+ dir->dir.parent_susp.CE_len;
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
dir->dir.len += ch->dirent_len + ch->susp.non_CE_len;
dir->dir.CE_len += ch->susp.CE_len;
}
t->total_dir_size += round_up(dir->dir.len + dir->dir.CE_len,
t->block_size);
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
struct iso_tree_node *iso = ch->iso_self;
if (ch->type == ECMA119_DIR) {
calc_dir_size(t, ch);
} else if (iso && iso->attrib.st_size
&& iso->loc.type == LIBISO_FILESYS
&& iso->loc.path) {
t->filelist_len++;
}
}
}
/**
* Fill out the block field in each ecma119_tree_node that is a directory and
* fill out t->dirlist.
*/
static void
calc_dir_pos(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
assert(dir->type == ECMA119_DIR);
/* we don't need to set iso_self->block since each tree writes
* its own directories */
dir->block = t->curblock;
t->curblock += div_up(dir->dir.len + dir->dir.CE_len, t->block_size);
t->dirlist[t->curfile++] = dir;
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_DIR)
calc_dir_pos(t, ch);
}
/* reset curfile when we're finished */
if (!dir->parent) {
t->curfile = 0;
}
}
/**
* Fill out the block field for each ecma119_tree_node that is a file and fill
* out t->filelist.
*/
static void
calc_file_pos(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
assert(dir->type == ECMA119_DIR);
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_FILE && ch->iso_self) {
struct iso_tree_node *iso = ch->iso_self;
off_t size = iso->attrib.st_size;
iso->block = ch->block = t->curblock;
t->curblock += div_up(size, t->block_size);
if (size && iso->loc.type == LIBISO_FILESYS
&& iso->loc.path)
t->filelist[t->curfile++] = ch;
}
}
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_DIR)
calc_file_pos(t, ch);
}
/* reset curfile when we're finished */
if (!dir->parent) {
t->curfile = 0;
}
}
struct ecma119_write_target*
ecma119_target_new(struct iso_volset *volset,
int volnum,
int level,
int flags)
{
struct ecma119_write_target *t =
calloc(1, sizeof(struct ecma119_write_target));
size_t i, j, cur;
struct iso_tree_node *iso_root = volset->volume[volnum]->root;
volset->refcount++;
t->root = ecma119_tree_create(t, iso_root);
t->joliet = (flags & ECMA119_JOLIET) ? 1 : 0;
if (t->joliet)
t->joliet_root = joliet_tree_create(t, iso_root);
t->volset = volset;
t->volnum = volnum;
t->now = time(NULL);
t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1 : 0;
t->iso_level = level;
t->block_size = 2048;
if (t->rockridge)
add_susp_fields(t);
calc_dir_size(t, t->root);
if (t->joliet) {
joliet_calc_dir_size(t, t->joliet_root);
t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len);
t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len);
}
t->dirlist = calloc(1, sizeof(void*) * t->dirlist_len);
t->pathlist = calloc(1, sizeof(void*) * t->dirlist_len);
t->filelist = calloc(1, sizeof(void*) * t->filelist_len);
/* fill out the pathlist */
t->pathlist[0] = t->root;
t->path_table_size = 10; /* root directory record */
cur = 1;
for (i = 0; i < t->dirlist_len; i++) {
struct ecma119_tree_node *dir = t->pathlist[i];
for (j = 0; j < dir->dir.nchildren; j++) {
struct ecma119_tree_node *ch = dir->dir.children[j];
if (ch->type == ECMA119_DIR) {
size_t len = 8 + strlen(ch->name);
t->pathlist[cur++] = ch;
t->path_table_size += len + len % 2;
}
}
}
t->curblock = 16 /* system area */
+ 1 /* volume desc */
+ 1; /* volume desc terminator */
if (t->joliet) /* supplementary vol desc */
t->curblock += div_up (2048, t->block_size);
t->l_path_table_pos = t->curblock;
t->curblock += div_up(t->path_table_size, t->block_size);
t->m_path_table_pos = t->curblock;
t->curblock += div_up(t->path_table_size, t->block_size);
if (t->joliet) {
joliet_prepare_path_tables(t);
t->l_path_table_pos_joliet = t->curblock;
t->curblock += div_up(t->path_table_size_joliet, t->block_size);
t->m_path_table_pos_joliet = t->curblock;
t->curblock += div_up(t->path_table_size_joliet, t->block_size);
}
calc_dir_pos(t, t->root);
if (t->joliet)
joliet_calc_dir_pos(t, t->joliet_root);
calc_file_pos(t, t->root);
if (t->joliet)
joliet_update_file_pos (t, t->joliet_root);
if (t->rockridge) {
susp_finalize(t, t->root);
rrip_finalize(t, t->root);
}
t->total_size = t->curblock * t->block_size;
t->vol_space_size = t->curblock;
/* prepare for writing */
t->curblock = 0;
t->state = ECMA119_WRITE_SYSTEM_AREA;
return t;
}
static int
is_joliet_state(enum ecma119_write_state state)
{
return state == ECMA119_WRITE_SUP_VOL_DESC_JOLIET
|| state == ECMA119_WRITE_L_PATH_TABLE_JOLIET
|| state == ECMA119_WRITE_M_PATH_TABLE_JOLIET
|| state == ECMA119_WRITE_DIR_RECORDS_JOLIET;
}
static void
next_state(struct ecma119_write_target *t)
{
t->state++;
while (!t->joliet && is_joliet_state(t->state))
t->state++;
printf ("now in state %d, curblock=%d\n", (int)t->state, (int)t->curblock);
}
static void
wr_system_area(struct ecma119_write_target *t, uint8_t *buf)
{
memset(buf, 0, t->block_size);
if (t->curblock == 15) {
next_state(t);
}
}
static void
wr_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_pri_vol_desc, 2048, buf);
}
static void
wr_vol_desc_term(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_vol_desc_terminator, 2048, buf);
}
static void
wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_l_path_table, t->path_table_size, buf);
}
static void
wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_m_path_table, t->path_table_size, buf);
}
static void
wr_dir_records(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_dirs, t->total_dir_size, buf);
}
static void
wr_files(struct ecma119_write_target *t, uint8_t *buf)
{
struct state_files *f_st = &t->state_files;
size_t nread;
struct ecma119_tree_node *f = t->filelist[f_st->file];
const char *path = f->iso_self->loc.path;
if (!f_st->fd) {
f_st->data_len = f->iso_self->attrib.st_size;
f_st->fd = fopen(path, "r");
if (!f_st->fd)
err(1, "couldn't open %s for reading", path);
assert(t->curblock == f->block);
}
nread = fread(buf, 1, t->block_size, f_st->fd);
f_st->pos += t->block_size;
if (nread < 0)
warn("problem reading from %s", path);
else if (nread != t->block_size && f_st->pos < f_st->data_len)
warnx("incomplete read from %s", path);
if (f_st->pos >= f_st->data_len) {
fclose(f_st->fd);
f_st->fd = 0;
f_st->pos = 0;
f_st->file++;
if (f_st->file >= t->filelist_len)
next_state(t);
}
}
static void
write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf;
struct iso_volume *volume = t->volset->volume[t->volnum];
char *vol_id = str2ascii(volume->volume_id);
char *pub_id = str2ascii(volume->publisher_id);
char *data_id = str2ascii(volume->data_preparer_id);
char *volset_id = str2ascii(t->volset->volset_id);
vol->vol_desc_type[0] = 1;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->system_id, "SYSID", 5);
if (vol_id)
strncpy((char*)vol->volume_id, vol_id, 32);
iso_bb(vol->vol_space_size, t->vol_space_size, 4);
iso_bb(vol->vol_set_size, t->volset->volset_size, 2);
iso_bb(vol->vol_seq_number, t->volnum + 1, 2);
iso_bb(vol->block_size, t->block_size, 2);
iso_bb(vol->path_table_size, t->path_table_size, 4);
iso_lsb(vol->l_path_table_pos, t->l_path_table_pos, 4);
iso_msb(vol->m_path_table_pos, t->m_path_table_pos, 4);
write_one_dir_record(t, t->root, 3, vol->root_dir_record);
strncpy((char*)vol->vol_set_id, volset_id, 128);
strncpy((char*)vol->publisher_id, pub_id, 128);
strncpy((char*)vol->data_prep_id, data_id, 128);
strncpy((char*)vol->application_id, "APPID", 128);
iso_datetime_17(vol->vol_creation_time, t->now);
iso_datetime_17(vol->vol_modification_time, t->now);
iso_datetime_17(vol->vol_effective_time, t->now);
vol->file_structure_version[0] = 1;
free(vol_id);
free(volset_id);
free(pub_id);
free(data_id);
}
static void
write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf)
{
struct ecma119_vol_desc_terminator *vol =
(struct ecma119_vol_desc_terminator*) buf;
vol->vol_desc_type[0] = 255;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
}
static void
write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf)
{
void (*write_int)(uint8_t*, uint32_t, int) = l_type ? iso_lsb
: iso_msb;
size_t i;
struct ecma119_path_table_record *rec;
struct ecma119_tree_node *dir;
int parent = 0;
for (i = 0; i < t->dirlist_len; i++) {
dir = t->pathlist[i];
while ((i) && t->pathlist[parent] != dir->parent)
parent++;
assert(parent < i || i == 0);
rec = (struct ecma119_path_table_record*) buf;
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
rec->len_xa[0] = 0;
write_int(rec->block, dir->block, 4);
write_int(rec->parent, parent + 1, 2);
if (dir->parent)
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
}
}
static void
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
write_path_table(t, 1, buf);
}
static void
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
write_path_table(t, 0, buf);
}
/* if file_id is >= 0, we use it instead of the filename. As a magic number,
* file_id == 3 means that we are writing the root directory record (in order
* to distinguish it from the "." entry in the root directory) */
static void
write_one_dir_record(struct ecma119_write_target *t,
struct ecma119_tree_node *node,
int file_id,
uint8_t *buf)
{
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->name);
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
uint32_t len = (node->type == ECMA119_DIR) ? node->dir.len
: node->file.real_me ? 0 : node->iso_self->attrib.st_size;
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
/* we don't write out susp fields for the root node */
if (t->rockridge) {
if (file_id == 0) {
susp_write(t, &node->dir.self_susp, &buf[len_dr]);
len_dr += node->dir.self_susp.non_CE_len;
} else if (file_id == 1) {
susp_write(t, &node->dir.parent_susp, &buf[len_dr]);
len_dr += node->dir.parent_susp.non_CE_len;
} else if (file_id < 0) {
susp_write(t, &node->susp, &buf[len_dr]);
len_dr += node->susp.non_CE_len;
}
}
if (file_id == 1 && node->parent)
node = node->parent;
rec->len_dr[0] = len_dr;
iso_bb(rec->block, node->block, 4);
iso_bb(rec->length, len, 4);
iso_datetime_7(rec->recording_time, t->now);
rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
iso_bb(rec->vol_seq_number, t->volnum + 1, 2);
rec->len_fi[0] = len_fi;
memcpy(rec->file_id, name, len_fi);
}
static void
write_one_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *dir,
uint8_t *buf)
{
size_t i;
uint8_t *orig_buf = buf;
assert(dir->type == ECMA119_DIR);
/* write the "." and ".." entries first */
write_one_dir_record(t, dir, 0, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
write_one_dir_record(t, dir, 1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
for (i = 0; i < dir->dir.nchildren; i++) {
write_one_dir_record(t, dir->dir.children[i], -1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
}
/* write the susp continuation areas */
if (t->rockridge) {
susp_write_CE(t, &dir->dir.self_susp, buf);
buf += dir->dir.self_susp.CE_len;
susp_write_CE(t, &dir->dir.parent_susp, buf);
buf += dir->dir.parent_susp.CE_len;
for (i = 0; i < dir->dir.nchildren; i++) {
susp_write_CE(t, &dir->dir.children[i]->susp, buf);
buf += dir->dir.children[i]->susp.CE_len;
}
}
assert (buf - orig_buf == dir->dir.len + dir->dir.CE_len);
}
static void
write_dirs(struct ecma119_write_target *t, uint8_t *buf)
{
size_t i;
struct ecma119_tree_node *dir;
for (i = 0; i < t->dirlist_len; i++) {
dir = t->dirlist[i];
write_one_dir(t, dir, buf);
buf += round_up(dir->dir.len + dir->dir.CE_len, t->block_size);
}
}
void
ecma119_start_chunking(struct ecma119_write_target *t,
write_fn writer,
off_t data_size,
uint8_t *buf)
{
if (data_size != t->state_data_size) {
data_size = round_up(data_size, t->block_size);
t->state_data = realloc(t->state_data, data_size);
t->state_data_size = data_size;
}
memset(t->state_data, 0, t->state_data_size);
t->state_data_off = 0;
t->state_data_valid = 1;
writer(t, t->state_data);
write_data_chunk(t, buf);
}
static void
write_data_chunk(struct ecma119_write_target *t, uint8_t *buf)
{
memcpy(buf, t->state_data + t->state_data_off, t->block_size);
t->state_data_off += t->block_size;
if (t->state_data_off >= t->state_data_size) {
assert (t->state_data_off <= t->state_data_size);
t->state_data_valid = 0;
next_state(t);
}
}
static int
bs_read(struct burn_source *bs, unsigned char *buf, int size)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
if (size != t->block_size) {
warnx("you must read data in block-sized chunks (%d bytes)",
(int)t->block_size);
return 0;
} else if (t->curblock >= t->vol_space_size) {
return 0;
}
if (t->state_data_valid)
write_data_chunk(t, buf);
else
writers[t->state](t, buf);
t->curblock++;
return size;
}
static off_t
bs_get_size(struct burn_source *bs)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
return t->total_size;
}
static void
bs_free_data(struct burn_source *bs)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
ecma119_tree_free(t->root);
free(t->dirlist);
free(t->pathlist);
free(t->dirlist_joliet);
free(t->pathlist_joliet);
free(t->filelist);
free(t->state_data);
if (t->state_files.fd)
fclose(t->state_files.fd);
}
struct burn_source *iso_source_new_ecma119(struct iso_volset *volset,
int volnum,
int level,
int flags)
{
struct burn_source *ret = calloc(1, sizeof(struct burn_source));
ret->refcount = 1;
ret->read = bs_read;
ret->get_size = bs_get_size;
ret->free_data = bs_free_data;
ret->data = ecma119_target_new(volset, volnum, level, flags);
return ret;
}

@ -1,267 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file ecma119.h
*
* Structures and definitions used for writing an emca119 (ISO9660) compatible
* volume.
*/
#ifndef LIBISO_ECMA119_H
#define LIBISO_ECMA119_H
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h> /* for FILE */
#include <sys/types.h>
#include "susp.h"
struct ecma119_tree_node;
struct joliet_tree_node;
/**
* The possible states that the ecma119 writer can be in.
*/
enum ecma119_write_state
{
ECMA119_WRITE_BEFORE,
ECMA119_WRITE_SYSTEM_AREA,
ECMA119_WRITE_PRI_VOL_DESC,
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
ECMA119_WRITE_VOL_DESC_TERMINATOR,
ECMA119_WRITE_L_PATH_TABLE,
ECMA119_WRITE_M_PATH_TABLE,
ECMA119_WRITE_L_PATH_TABLE_JOLIET,
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
ECMA119_WRITE_DIR_RECORDS,
ECMA119_WRITE_DIR_RECORDS_JOLIET,
ECMA119_WRITE_FILES,
ECMA119_WRITE_DONE
};
/**
* Data describing the state of the ecma119 writer. Everything here should be
* considered private!
*/
struct ecma119_write_target
{
struct ecma119_tree_node *root;
struct joliet_tree_node *joliet_root;
struct iso_volset *volset;
int volnum;
time_t now; /**< Time at which writing began. */
off_t total_size; /**< Total size of the output. This only
* includes the current volume. */
uint32_t vol_space_size;
unsigned int rockridge:1;
unsigned int joliet:1;
unsigned int iso_level:2;
int curblock;
uint16_t block_size;
uint32_t path_table_size;
uint32_t path_table_size_joliet;
uint32_t l_path_table_pos;
uint32_t m_path_table_pos;
uint32_t l_path_table_pos_joliet;
uint32_t m_path_table_pos_joliet;
uint32_t total_dir_size;
uint32_t total_dir_size_joliet;
struct ecma119_tree_node **dirlist;
/**< A pre-order list of directories
* (this is the order in which we write
* out directory records).
*/
struct ecma119_tree_node **pathlist;
/**< A breadth-first list of
* directories. This is used for
* writing out the path tables.
*/
size_t dirlist_len; /**< The length of the previous 2 lists.
*/
struct ecma119_tree_node **filelist;
/**< A pre-order list of files with
* non-NULL paths and non-zero sizes.
*/
size_t filelist_len; /* Length of the previous list. */
int curfile; /**< Used as a helper field for writing
out filelist and dirlist */
/* Joliet versions of the above lists. Since Joliet doesn't require
* directory relocation, the order of these lists might be different
* from the lists above (but they will be the same length).
*/
struct joliet_tree_node **dirlist_joliet;
struct joliet_tree_node **pathlist_joliet;
enum ecma119_write_state state; /* The current state of the writer. */
/* Most writers work by
* 1) making sure state_data is big enough for their data
* 2) writing _all_ their data into state_data
* 3) relying on write_data_chunk to write the data block
* by block.
*/
uint8_t *state_data;
off_t state_data_size;
off_t state_data_off;
int state_data_valid;
/* for writing out files */
struct state_files {
off_t pos; /* The number of bytes we have written
* so far in the current file.
*/
off_t data_len;/* The number of bytes in the currently
* open file.
*/
FILE *fd; /* The currently open file. */
int file; /* The index in filelist that we are
* currently writing (or about to write). */
} state_files;
};
/**
* Create a new ecma119_write_target from the given volume number of the
* given volume set.
*
* \pre \p volnum is less than \p volset-\>volset_size.
* \post For each node in the tree, writer_data has been allocated.
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
*/
struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset,
int volnum,
int level,
int flags);
#define BP(a,b) [(b) - (a) + 1]
struct ecma119_pri_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t unused1 BP(8, 8);
uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88);
uint8_t unused3 BP(89, 120);
uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_sup_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t vol_flags BP(8, 8);
uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88);
uint8_t esc_sequences BP(89, 120);
uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_vol_desc_terminator
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t reserved BP(8, 2048);
};
struct ecma119_dir_record
{
uint8_t len_dr BP(1, 1);
uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 10);
uint8_t length BP(11, 18);
uint8_t recording_time BP(19, 25);
uint8_t flags BP(26, 26);
uint8_t file_unit_size BP(27, 27);
uint8_t interleave_gap_size BP(28, 28);
uint8_t vol_seq_number BP(29, 32);
uint8_t len_fi BP(33, 33);
uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */
/* padding field (if len_fi is even) */
/* system use (len_dr - len_su + 1 to len_dr) */
};
struct ecma119_path_table_record
{
uint8_t len_di BP(1, 1);
uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 6);
uint8_t parent BP(7, 8);
uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */
/* padding field (if len_di is odd) */
};
/**
* A utility function for writers that want to write their data all at once
* rather than block-by-block. This creates a buffer of size \p size, passes
* it to the given writer, then hands out block-sized chunks.
*/
void
ecma119_start_chunking(struct ecma119_write_target *t,
void (*)(struct ecma119_write_target*, uint8_t*),
off_t size,
uint8_t *buf);
#endif /* LIBISO_ECMA119_H */

@ -1,312 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <assert.h>
#include "ecma119.h"
#include "ecma119_tree.h"
#include "tree.h"
#include "util.h"
static size_t calc_dirent_len(struct ecma119_tree_node *n)
{
int ret = n->name ? strlen(n->name) + 33 : 34;
if (ret % 2) ret++;
return ret;
}
static struct ecma119_tree_node*
create_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
assert(t && (!parent || parent->type == ECMA119_DIR)
&& iso && S_ISDIR(iso->attrib.st_mode));
ret = calloc(1, sizeof(struct ecma119_tree_node));
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_dirid(iso->name)
: iso_2_dirid(iso->name))
: NULL;
ret->dirent_len = calc_dirent_len(ret);
ret->iso_self = iso;
ret->target = t;
ret->type = ECMA119_DIR;
ret->parent = ret->dir.real_parent = parent;
ret->dir.depth = parent ? parent->dir.depth + 1 : 1;
ret->dir.nchildren = iso->nchildren;
ret->dir.children = calloc(1, sizeof(void*) * iso->nchildren);
return ret;
}
static struct ecma119_tree_node*
create_file(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
assert(t && iso && parent && parent->type == ECMA119_DIR);
ret = calloc(1, sizeof(struct ecma119_tree_node));
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_fileid(iso->name)
: iso_2_fileid(iso->name))
: NULL;
ret->dirent_len = calc_dirent_len(ret);
ret->parent = parent;
ret->iso_self = iso;
ret->target = t;
ret->type = ECMA119_FILE;
return ret;
}
static struct ecma119_tree_node*
create_tree(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
size_t i;
assert(t && iso);
ret = (S_ISDIR(iso->attrib.st_mode) ? create_dir : create_file)
(t, parent, iso);
for (i = 0; i < iso->nchildren; i++) {
ret->dir.children[i] = create_tree(t, ret, iso->children[i]);
}
return ret;
}
void
ecma119_tree_free(struct ecma119_tree_node *root)
{
size_t i;
if (root->type == ECMA119_DIR) {
for (i=0; i < root->dir.nchildren; i++) {
ecma119_tree_free(root->dir.children[i]);
}
free(root->dir.children);
}
free(root->name);
free(root);
}
static size_t
max_child_name_len(struct ecma119_tree_node *root)
{
size_t ret = 0, i;
assert(root->type == ECMA119_DIR);
for (i=0; i < root->dir.nchildren; i++) {
size_t len = strlen(root->dir.children[i]->name);
ret = MAX(ret, len);
}
return ret;
}
static void
reparent(struct ecma119_tree_node *child,
struct ecma119_tree_node *parent)
{
int found = 0;
size_t i;
struct ecma119_tree_node *placeholder;
assert(child && parent && parent->type == ECMA119_DIR && child->parent);
/* replace the child in the original parent with a placeholder */
for (i=0; i < child->parent->dir.nchildren; i++) {
if (child->parent->dir.children[i] == child) {
placeholder = create_file(child->target,
child->parent,
child->iso_self);
placeholder->file.real_me = child;
child->parent->dir.children[i] = placeholder;
found = 1;
break;
}
}
assert(found);
/* add the child to its new parent */
child->parent = parent;
parent->dir.nchildren++;
parent->dir.children = realloc( parent->dir.children,
sizeof(void*) * parent->dir.nchildren );
parent->dir.children[parent->dir.nchildren-1] = child;
}
/**
* Reorder the tree, if necessary, to ensure that
* - the depth is at most 8
* - each path length is at most 255 characters
*/
static void
reorder_tree(struct ecma119_tree_node *root,
struct ecma119_tree_node *cur)
{
size_t max_path;
assert(root && cur && cur->type == ECMA119_DIR);
cur->dir.depth = cur->parent ? cur->parent->dir.depth + 1 : 1;
cur->dir.path_len = cur->parent ? cur->parent->dir.path_len
+ strlen(cur->name) : 0;
max_path = cur->dir.path_len + cur->dir.depth + max_child_name_len(cur);
if (cur->dir.depth > 8 || max_path > 255) {
reparent(cur, root);
/* we are appended to the root's children now, so there is no
* need to recurse (the root will hit us again) */
} else {
size_t i;
for (i=0; i < cur->dir.nchildren; i++) {
if (cur->dir.children[i]->type == ECMA119_DIR)
reorder_tree(root, cur->dir.children[i]);
}
}
}
static int
cmp_node(const void *f1, const void *f2)
{
struct ecma119_tree_node *f = *((struct ecma119_tree_node**)f1);
struct ecma119_tree_node *g = *((struct ecma119_tree_node**)f2);
return strcmp(f->name, g->name);
}
static void
sort_tree(struct ecma119_tree_node *root)
{
size_t i;
assert(root && root->type == ECMA119_DIR);
qsort(root->dir.children, root->dir.nchildren, sizeof(void*), cmp_node);
for (i=0; i < root->dir.nchildren; i++) {
if (root->dir.children[i]->type == ECMA119_DIR)
sort_tree(root->dir.children[i]);
}
}
/**
* Change num_change characters of the given filename in order to ensure the
* name is unique. If the name is short enough (depending on the ISO level),
* we can append the characters instead of changing them.
*
* \p seq_num is the index of this file in the sequence of identical filenames.
*
* For example, seq_num=3, num_change=2, name="HELLOTHERE.TXT" changes name to
* "HELLOTHE03.TXT"
*/
static void
mangle_name(char **name, int num_change, int level, int seq_num)
{
char *dot = strrchr(*name, '.');
char *semi = strrchr(*name, ';');
size_t len = strlen(*name);
char base[len+1], ext[len+1];
char fmt[12];
size_t baselen, extlen;
if (num_change >= len) {
return;
}
strncpy(base, *name, len+1);
if (dot) {
base[dot - *name] = '\0';
strncpy(ext, dot+1, len+1);
if (semi) {
ext[semi - dot - 1] = '\0';
}
} else {
base[len-2] = '\0';
ext[0] = '\0';
}
baselen = strlen(base);
extlen = strlen(ext);
if (level == 1 && baselen + num_change > 8) {
base[8 - num_change] = '\0';
} else if (level != 1 && baselen + extlen + num_change > 30) {
base[30 - extlen - num_change] = '\0';
}
sprintf(fmt, "%%s%%0%1dd.%%s;1", num_change);
*name = realloc(*name, baselen + extlen + num_change + 4);
sprintf(*name, fmt, base, seq_num, ext);
}
static void
mangle_all(struct ecma119_tree_node *dir)
{
size_t i, j, k;
struct ecma119_dir_info d = dir->dir;
size_t n_change;
int changed;
assert(dir->type == ECMA119_DIR);
do {
changed = 0;
for (i=0; i < d.nchildren; i++) {
/* find the number of consecutive equal names */
j = 1;
while ( i+j < d.nchildren &&
!strcmp(d.children[i]->name,
d.children[i+j]->name) )
j++;
if (j == 1) continue;
/* mangle the names */
changed = 1;
n_change = j / 10 + 1;
for (k=0; k < j; k++) {
mangle_name(&(d.children[i+k]->name),
n_change,
dir->target->iso_level,
k);
d.children[i+k]->dirent_len =
calc_dirent_len(d.children[i+k]);
}
/* skip ahead by the number of mangled names */
i += j - 1;
}
} while (changed);
for (i=0; i < d.nchildren; i++) {
if (d.children[i]->type == ECMA119_DIR)
mangle_all(d.children[i]);
}
}
struct ecma119_tree_node*
ecma119_tree_create(struct ecma119_write_target *t,
struct iso_tree_node *iso_root)
{
t->root = create_tree(t, NULL, iso_root);
reorder_tree(t->root, t->root);
sort_tree(t->root);
mangle_all(t->root);
return t->root;
}
void
ecma119_tree_print(struct ecma119_tree_node *root, int spaces)
{
size_t i;
char sp[spaces+1];
memset(sp, ' ', spaces);
sp[spaces] = '\0';
printf("%s%s\n", sp, root->name);
if (root->type == ECMA119_DIR)
for (i=0; i < root->dir.