Removed remaining signs of libisofs in libburn tree
This commit is contained in:
parent
f598859c31
commit
e41a227b64
@ -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.nchildren; i++)
|
|
||||||
ecma119_tree_print(root->dir.children[i], spaces+2);
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file ecma119_tree.h
|
|
||||||
*
|
|
||||||
* Declarations for creating, modifying and printing filesystem trees that
|
|
||||||
* are compatible with ecma119.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBISO_ECMA119_TREE_H
|
|
||||||
#define LIBISO_ECMA119_TREE_H
|
|
||||||
|
|
||||||
struct ecma119_write_target;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ECMA119_FILE,
|
|
||||||
ECMA119_DIR
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ecma119_dir_info {
|
|
||||||
struct susp_info self_susp; /**< susp entries for "." */
|
|
||||||
struct susp_info parent_susp; /**< susp entries for ".." */
|
|
||||||
|
|
||||||
size_t len; /**< sum of the lengths of children's
|
|
||||||
* Directory Records (including SU) */
|
|
||||||
size_t CE_len; /**< sum of the lengths of children's
|
|
||||||
* SUSP CE areas */
|
|
||||||
|
|
||||||
int depth;
|
|
||||||
size_t path_len; /**< The length of a path up to, and
|
|
||||||
* including, this directory. This
|
|
||||||
* cannot exceed 255. */
|
|
||||||
size_t nchildren;
|
|
||||||
struct ecma119_tree_node **children;
|
|
||||||
|
|
||||||
struct ecma119_tree_node *real_parent;
|
|
||||||
/**< The parent before relocation */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ecma119_file_info
|
|
||||||
{
|
|
||||||
struct ecma119_tree_node *real_me;
|
|
||||||
/**< If this is non-NULL, the file is
|
|
||||||
* a placeholder for a relocated
|
|
||||||
* directory and this field points to
|
|
||||||
* that relocated directory.
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A node for a tree containing all the information necessary for writing
|
|
||||||
* an ISO9660 volume.
|
|
||||||
*/
|
|
||||||
struct ecma119_tree_node
|
|
||||||
{
|
|
||||||
char *name; /**< in ASCII, conforming to the
|
|
||||||
* current ISO level. */
|
|
||||||
size_t dirent_len; /**< Length of the directory record,
|
|
||||||
* not including SU. */
|
|
||||||
size_t block;
|
|
||||||
|
|
||||||
struct ecma119_tree_node *parent;
|
|
||||||
struct iso_tree_node *iso_self;
|
|
||||||
struct ecma119_write_target *target;
|
|
||||||
|
|
||||||
struct susp_info susp;
|
|
||||||
|
|
||||||
int type; /**< file or directory */
|
|
||||||
/* union {*/
|
|
||||||
struct ecma119_dir_info dir;
|
|
||||||
struct ecma119_file_info file;
|
|
||||||
/* };*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new ecma119_tree that corresponds to the tree represented by
|
|
||||||
* \p iso_root.
|
|
||||||
*/
|
|
||||||
struct ecma119_tree_node*
|
|
||||||
ecma119_tree_create(struct ecma119_write_target *target,
|
|
||||||
struct iso_tree_node *iso_root);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free an ecma119 tree.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ecma119_tree_free(struct ecma119_tree_node *root);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print an ecma119 tree.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ecma119_tree_print(struct ecma119_tree_node *root, int spaces);
|
|
||||||
|
|
||||||
#endif /* LIBISO_ECMA119_TREE_H */
|
|
@ -1,42 +0,0 @@
|
|||||||
#include "hash.h"
|
|
||||||
#include "exclude.h"
|
|
||||||
|
|
||||||
static struct iso_hash_node *table[HASH_NODES]={0,};
|
|
||||||
static int num=0;
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_exclude_add_path(const char *path)
|
|
||||||
{
|
|
||||||
if (!path)
|
|
||||||
return;
|
|
||||||
|
|
||||||
num += iso_hash_insert(table, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_exclude_remove_path(const char *path)
|
|
||||||
{
|
|
||||||
if (!num || !path)
|
|
||||||
return;
|
|
||||||
|
|
||||||
num -= iso_hash_remove(table, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_exclude_empty(void)
|
|
||||||
{
|
|
||||||
if (!num)
|
|
||||||
return;
|
|
||||||
|
|
||||||
iso_hash_empty(table);
|
|
||||||
num=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
iso_exclude_lookup(const char *path)
|
|
||||||
{
|
|
||||||
if (!num || !path)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return iso_hash_lookup(table, path);
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef ISO_EXCLUDE_H
|
|
||||||
#define ISO_EXCLUDE_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a path to ignore when adding a directory recursively.
|
|
||||||
*
|
|
||||||
* \param path The path, on the local filesystem, of the file.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
iso_exclude_lookup(const char *path);
|
|
||||||
|
|
||||||
#endif /* ISO_EXCLUDE */
|
|
@ -1,158 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "hash.h"
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
iso_hash_path(const char *path)
|
|
||||||
{
|
|
||||||
unsigned int hash_num=0;
|
|
||||||
const char *c;
|
|
||||||
|
|
||||||
c=path;
|
|
||||||
while(*c)
|
|
||||||
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
|
|
||||||
|
|
||||||
return hash_num % HASH_NODES;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
iso_hash_lookup(struct iso_hash_node **table, const char *path)
|
|
||||||
{
|
|
||||||
struct iso_hash_node *node;
|
|
||||||
unsigned int hash_num;
|
|
||||||
|
|
||||||
hash_num = iso_hash_path(path);
|
|
||||||
|
|
||||||
node=table[hash_num];
|
|
||||||
|
|
||||||
if (!node)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!strcmp(path, node->path))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
while (node->next) {
|
|
||||||
node=node->next;
|
|
||||||
|
|
||||||
if (!strcmp(path, node->path))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct iso_hash_node*
|
|
||||||
iso_hash_node_new (const char *path)
|
|
||||||
{
|
|
||||||
struct iso_hash_node *node;
|
|
||||||
|
|
||||||
/*create an element to be inserted in the hash table */
|
|
||||||
node=malloc(sizeof(struct iso_hash_node));
|
|
||||||
node->path=strdup(path);
|
|
||||||
node->next=NULL;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
iso_hash_insert(struct iso_hash_node **table, const char *path)
|
|
||||||
{
|
|
||||||
struct iso_hash_node *node;
|
|
||||||
unsigned int hash_num;
|
|
||||||
|
|
||||||
/* find the hash number */
|
|
||||||
hash_num = iso_hash_path(path);
|
|
||||||
|
|
||||||
/* insert it */
|
|
||||||
node = table[hash_num];
|
|
||||||
|
|
||||||
/* unfortunately, we can't safely consider that a path
|
|
||||||
* won't be twice in the hash table so make sure it
|
|
||||||
* doesn't already exists */
|
|
||||||
if (!node) {
|
|
||||||
table[hash_num]=iso_hash_node_new(path);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if it's already in, we don't do anything */
|
|
||||||
if (!strcmp(path, node->path))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (node->next) {
|
|
||||||
node = node->next;
|
|
||||||
|
|
||||||
/* if it's already in, we don't do anything */
|
|
||||||
if (!strcmp (path, node->path))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->next = iso_hash_node_new(path);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
iso_hash_node_free(struct iso_hash_node *node)
|
|
||||||
{
|
|
||||||
free(node->path);
|
|
||||||
free(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
iso_hash_remove(struct iso_hash_node **table, const char *path)
|
|
||||||
{
|
|
||||||
unsigned int hash_num;
|
|
||||||
struct iso_hash_node *node;
|
|
||||||
|
|
||||||
hash_num = iso_hash_path(path);
|
|
||||||
|
|
||||||
node=table[hash_num];
|
|
||||||
if (!node)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!strcmp(path, node->path)) {
|
|
||||||
table[hash_num]=node->next;
|
|
||||||
iso_hash_node_free(node);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (node->next) {
|
|
||||||
struct iso_hash_node *prev;
|
|
||||||
|
|
||||||
prev = node;
|
|
||||||
node = node->next;
|
|
||||||
|
|
||||||
if (!strcmp (path, node->path)) {
|
|
||||||
prev->next=node->next;
|
|
||||||
iso_hash_node_free(node);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_hash_empty(struct iso_hash_node **table)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i < HASH_NODES; i++) {
|
|
||||||
struct iso_hash_node *node;
|
|
||||||
|
|
||||||
node=table[i];
|
|
||||||
if (!node)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
table[i]=NULL;
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct iso_hash_node *next;
|
|
||||||
|
|
||||||
next=node->next;
|
|
||||||
iso_hash_node_free(node);
|
|
||||||
node=next;
|
|
||||||
} while (node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
#ifndef ISO_HASH_H
|
|
||||||
#define ISO_HASH_H
|
|
||||||
|
|
||||||
struct iso_hash_node {
|
|
||||||
struct iso_hash_node *next;
|
|
||||||
char *path;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HASH_NODES 128
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches in the hash table if the path exists.
|
|
||||||
*
|
|
||||||
* \param table The hash table.
|
|
||||||
* \param path The path of the file to look for.
|
|
||||||
*
|
|
||||||
* \return 1 if the path exists in the hash table, 0 otherwise.
|
|
||||||
*/
|
|
||||||
int iso_hash_lookup(struct iso_hash_node **table, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a new path in the hash table.
|
|
||||||
*
|
|
||||||
* \param table The hash table.
|
|
||||||
* \param path The path of a file to add to the hash table.
|
|
||||||
*
|
|
||||||
* \return 1 if the file wasn't already in the hash table, 0 otherwise.
|
|
||||||
*/
|
|
||||||
int iso_hash_insert(struct iso_hash_node **table, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a path from the hash table.
|
|
||||||
*
|
|
||||||
* \param table The hash table.
|
|
||||||
* \param path The path of a file to remove from the hash table.
|
|
||||||
*
|
|
||||||
* \return 1 if the file was found and removed, 0 otherwise.
|
|
||||||
*/
|
|
||||||
int iso_hash_remove(struct iso_hash_node **table, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Empty the hash table.
|
|
||||||
*/
|
|
||||||
void iso_hash_empty(struct iso_hash_node **table);
|
|
||||||
|
|
||||||
#endif /* ISO_HASH_H */
|
|
@ -1,379 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
#include "joliet.h"
|
|
||||||
#include "ecma119.h"
|
|
||||||
#include "ecma119_tree.h"
|
|
||||||
#include "tree.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "volume.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static struct joliet_tree_node*
|
|
||||||
create_node(struct ecma119_write_target *t,
|
|
||||||
struct joliet_tree_node *parent,
|
|
||||||
struct iso_tree_node *iso)
|
|
||||||
{
|
|
||||||
struct joliet_tree_node *ret =
|
|
||||||
calloc(1, sizeof(struct joliet_tree_node));
|
|
||||||
|
|
||||||
ret->name = iso_j_id(iso->name);
|
|
||||||
ret->dirent_len = 34 + (ret->name ? ucslen(ret->name) * 2 : 0);
|
|
||||||
ret->len = iso->attrib.st_size; /* for dirs, we'll change this */
|
|
||||||
ret->block = iso->block; /* only actually for files, not dirs */
|
|
||||||
ret->parent = parent;
|
|
||||||
ret->iso_self = iso;
|
|
||||||
ret->target = t;
|
|
||||||
ret->nchildren = iso->nchildren;
|
|
||||||
if (ret->nchildren)
|
|
||||||
ret->children = calloc(sizeof(void*), ret->nchildren);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct joliet_tree_node*
|
|
||||||
create_tree(struct ecma119_write_target *t,
|
|
||||||
struct joliet_tree_node *parent,
|
|
||||||
struct iso_tree_node *iso_root)
|
|
||||||
{
|
|
||||||
struct joliet_tree_node *root = create_node(t, parent, iso_root);
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < root->nchildren; i++) {
|
|
||||||
struct iso_tree_node *iso_ch = iso_root->children[i];
|
|
||||||
if (ISO_ISDIR(iso_ch))
|
|
||||||
root->children[i] = create_tree(t, root, iso_ch);
|
|
||||||
else
|
|
||||||
root->children[i] = create_node(t, root, iso_ch);
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
cmp_node(const void *f1, const void *f2)
|
|
||||||
{
|
|
||||||
struct joliet_tree_node *f = *((struct joliet_tree_node**)f1);
|
|
||||||
struct joliet_tree_node *g = *((struct joliet_tree_node**)f2);
|
|
||||||
return ucscmp(f->name, g->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sort_tree(struct joliet_tree_node *root)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
assert(root && ISO_ISDIR(root->iso_self));
|
|
||||||
|
|
||||||
qsort(root->children, root->nchildren, sizeof(void*), cmp_node);
|
|
||||||
for (i = 0; i < root->nchildren; i++)
|
|
||||||
if (ISO_ISDIR(root->children[i]->iso_self))
|
|
||||||
sort_tree(root->children[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_prepare_path_tables(struct ecma119_write_target *t)
|
|
||||||
{
|
|
||||||
size_t cur, i, j;
|
|
||||||
|
|
||||||
t->pathlist_joliet[0] = t->joliet_root;
|
|
||||||
t->path_table_size_joliet = 10; /* root directory record */
|
|
||||||
cur = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < t->dirlist_len; i++) {
|
|
||||||
struct joliet_tree_node *dir = t->pathlist_joliet[i];
|
|
||||||
for (j = 0; j < dir->nchildren; j++) {
|
|
||||||
struct joliet_tree_node *ch = dir->children[j];
|
|
||||||
if (ISO_ISDIR(ch->iso_self)) {
|
|
||||||
size_t len = 8 + ucslen(ch->name)*2;
|
|
||||||
t->pathlist_joliet[cur++] = ch;
|
|
||||||
t->path_table_size_joliet += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the size of each directory.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
joliet_calc_dir_size(struct ecma119_write_target *t,
|
|
||||||
struct joliet_tree_node *root)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
struct joliet_tree_node *ch;
|
|
||||||
|
|
||||||
assert(root && ISO_ISDIR(root->iso_self));
|
|
||||||
|
|
||||||
root->len = 68; /* for "." and ".." entries */
|
|
||||||
for (i = 0; i < root->nchildren; i++) {
|
|
||||||
ch = root->children[i];
|
|
||||||
root->len += ch->dirent_len;
|
|
||||||
if (ISO_ISDIR(ch->iso_self))
|
|
||||||
joliet_calc_dir_size(t, ch);
|
|
||||||
}
|
|
||||||
t->total_dir_size_joliet += round_up (root->len, t->block_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the position of each directory. Also fill out t->dirlist_joliet.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
joliet_calc_dir_pos(struct ecma119_write_target *t,
|
|
||||||
struct joliet_tree_node *root)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
struct joliet_tree_node *ch;
|
|
||||||
|
|
||||||
assert(root && ISO_ISDIR(root->iso_self));
|
|
||||||
|
|
||||||
root->block = t->curblock;
|
|
||||||
t->curblock += div_up(root->len, t->block_size);
|
|
||||||
|
|
||||||
t->dirlist_joliet[t->curfile++] = root;
|
|
||||||
for (i = 0; i < root->nchildren; i++) {
|
|
||||||
ch = root->children[i];
|
|
||||||
if (ISO_ISDIR(ch->iso_self))
|
|
||||||
joliet_calc_dir_pos(t, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset curfile when we're finished */
|
|
||||||
if (!root->parent)
|
|
||||||
t->curfile = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_update_file_pos(struct ecma119_write_target *t,
|
|
||||||
struct joliet_tree_node *dir)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
assert(dir && ISO_ISDIR(dir->iso_self));
|
|
||||||
for (i = 0; i < dir->nchildren; i++) {
|
|
||||||
struct joliet_tree_node *ch;
|
|
||||||
ch = dir->children[i];
|
|
||||||
|
|
||||||
if (!ISO_ISDIR (ch->iso_self)) {
|
|
||||||
struct iso_tree_node *iso = ch->iso_self;
|
|
||||||
ch->block = iso->block;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
joliet_update_file_pos(t, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset curfile when we're finished */
|
|
||||||
if (!dir->parent)
|
|
||||||
t->curfile = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct joliet_tree_node*
|
|
||||||
joliet_tree_create(struct ecma119_write_target *t,
|
|
||||||
struct iso_tree_node *iso_root)
|
|
||||||
{
|
|
||||||
struct joliet_tree_node *root = create_tree(t, NULL, iso_root);
|
|
||||||
|
|
||||||
sort_tree(root);
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ugh. this is mostly C&P */
|
|
||||||
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 joliet_tree_node *dir;
|
|
||||||
int parent = 0;
|
|
||||||
|
|
||||||
assert (t->joliet);
|
|
||||||
|
|
||||||
for (i = 0; i < t->dirlist_len; i++) {
|
|
||||||
dir = t->pathlist_joliet[i];
|
|
||||||
while ((i) && t->pathlist_joliet[parent] != dir->parent)
|
|
||||||
parent++;
|
|
||||||
assert(parent < i || i == 0);
|
|
||||||
|
|
||||||
rec = (struct ecma119_path_table_record*) buf;
|
|
||||||
rec->len_di[0] = dir->parent ?
|
|
||||||
(uint8_t) ucslen(dir->name) * 2 : 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 joliet_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 : ucslen(node->name) * 2;
|
|
||||||
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
|
|
||||||
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
|
|
||||||
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
|
||||||
|
|
||||||
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, node->len, 4);
|
|
||||||
iso_datetime_7(rec->recording_time, t->now);
|
|
||||||
rec->flags[0] = ISO_ISDIR(node->iso_self) ? 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_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|
||||||
{
|
|
||||||
struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf;
|
|
||||||
struct iso_volume *volume = t->volset->volume[t->volnum];
|
|
||||||
uint16_t *vol_id = str2ucs(volume->volume_id);
|
|
||||||
uint16_t *pub_id = str2ucs(volume->publisher_id);
|
|
||||||
uint16_t *data_id = str2ucs(volume->data_preparer_id);
|
|
||||||
uint16_t *volset_id = str2ucs(t->volset->volset_id);
|
|
||||||
int vol_id_len = MIN(32, ucslen(vol_id) * 2);
|
|
||||||
int pub_id_len = MIN(128, ucslen(pub_id) * 2);
|
|
||||||
int data_id_len = MIN(128, ucslen(data_id) * 2);
|
|
||||||
int volset_id_len = MIN(128, ucslen(volset_id) * 2);
|
|
||||||
|
|
||||||
vol->vol_desc_type[0] = 2;
|
|
||||||
memcpy(vol->std_identifier, "CD001", 5);
|
|
||||||
vol->vol_desc_version[0] = 1;
|
|
||||||
memcpy(vol->system_id, "SYSID", 5);
|
|
||||||
if (vol_id)
|
|
||||||
memcpy(vol->volume_id, vol_id, vol_id_len);
|
|
||||||
memcpy(vol->esc_sequences, "%/E", 3);
|
|
||||||
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_joliet, 4);
|
|
||||||
iso_lsb(vol->l_path_table_pos, t->l_path_table_pos_joliet, 4);
|
|
||||||
iso_msb(vol->m_path_table_pos, t->m_path_table_pos_joliet, 4);
|
|
||||||
|
|
||||||
write_one_dir_record(t, t->joliet_root, 3, vol->root_dir_record);
|
|
||||||
|
|
||||||
memcpy(vol->vol_set_id, volset_id, volset_id_len);
|
|
||||||
memcpy(vol->publisher_id, pub_id, pub_id_len);
|
|
||||||
memcpy(vol->data_prep_id, data_id, data_id_len);
|
|
||||||
/*memcpy(vol->application_id, "APPID", app_id_len);*/
|
|
||||||
|
|
||||||
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_one_dir(struct ecma119_write_target *t,
|
|
||||||
struct joliet_tree_node *dir,
|
|
||||||
uint8_t *buf)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
uint8_t *orig_buf = buf;
|
|
||||||
|
|
||||||
assert(ISO_ISDIR (dir->iso_self));
|
|
||||||
/* 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->nchildren; i++) {
|
|
||||||
write_one_dir_record(t, dir->children[i], -1, buf);
|
|
||||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (buf - orig_buf == dir->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
write_dirs(struct ecma119_write_target *t, uint8_t *buf)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
struct joliet_tree_node *dir;
|
|
||||||
|
|
||||||
assert (t->curblock == t->dirlist_joliet[0]->block);
|
|
||||||
for (i = 0; i < t->dirlist_len; i++) {
|
|
||||||
dir = t->dirlist_joliet[i];
|
|
||||||
write_one_dir(t, dir, buf);
|
|
||||||
buf += round_up(dir->len, t->block_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_sup_vol_desc(struct ecma119_write_target *t,
|
|
||||||
uint8_t *buf)
|
|
||||||
{
|
|
||||||
ecma119_start_chunking(t,
|
|
||||||
write_sup_vol_desc,
|
|
||||||
2048,
|
|
||||||
buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_l_path_table(struct ecma119_write_target *t,
|
|
||||||
uint8_t *buf)
|
|
||||||
{
|
|
||||||
ecma119_start_chunking(t,
|
|
||||||
write_l_path_table,
|
|
||||||
t->path_table_size_joliet,
|
|
||||||
buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_m_path_table(struct ecma119_write_target *t,
|
|
||||||
uint8_t *buf)
|
|
||||||
{
|
|
||||||
ecma119_start_chunking(t,
|
|
||||||
write_m_path_table,
|
|
||||||
t->path_table_size_joliet,
|
|
||||||
buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_dir_records(struct ecma119_write_target *t,
|
|
||||||
uint8_t *buf)
|
|
||||||
{
|
|
||||||
ecma119_start_chunking(t,
|
|
||||||
write_dirs,
|
|
||||||
t->total_dir_size_joliet,
|
|
||||||
buf);
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file joliet.h
|
|
||||||
*
|
|
||||||
* Declare the filesystems trees that are Joliet-compatible and the public
|
|
||||||
* functions for tying them into an ecma119 volume.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBISO_JOLIET_H
|
|
||||||
#define LIBISO_JOLIET_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
struct ecma119_write_target;
|
|
||||||
struct iso_tree_node;
|
|
||||||
|
|
||||||
struct joliet_tree_node
|
|
||||||
{
|
|
||||||
uint16_t *name; /**< In UCS-2BE. */
|
|
||||||
size_t dirent_len;
|
|
||||||
size_t len;
|
|
||||||
size_t block;
|
|
||||||
|
|
||||||
struct joliet_tree_node *parent;
|
|
||||||
struct iso_tree_node *iso_self;
|
|
||||||
struct ecma119_write_target *target;
|
|
||||||
|
|
||||||
struct joliet_tree_node **children;
|
|
||||||
size_t nchildren;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new joliet_tree that corresponds to the tree represented by
|
|
||||||
* \p iso_root.
|
|
||||||
*/
|
|
||||||
struct joliet_tree_node*
|
|
||||||
joliet_tree_create(struct ecma119_write_target *target,
|
|
||||||
struct iso_tree_node *iso_root);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the size of each directory in the joliet heirarchy.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the position of each directory in the joliet heirarchy.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the position of each file in the joliet hierarchy (to be called
|
|
||||||
* AFTER the file positions in the iso tree have been set).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
joliet_update_file_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the size of the joliet path table and fill in the list of
|
|
||||||
* directories.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
joliet_prepare_path_tables(struct ecma119_write_target *t);
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_tree_free(struct joliet_tree_node *root);
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
|
|
||||||
|
|
||||||
void
|
|
||||||
joliet_wr_dir_records(struct ecma119_write_target *t, uint8_t *buf);
|
|
||||||
|
|
||||||
#endif /* LIBISO_JOLIET_H */
|
|
@ -1,225 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ISO-9660 data volume with Rock Ridge and Joliet extensions.
|
|
||||||
* Usage is easy:
|
|
||||||
* - Create a new volume.
|
|
||||||
* - Add files and directories.
|
|
||||||
* - Write the volume to a file or create a burn source for use with Libburn.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBISO_LIBISOFS_H
|
|
||||||
#define LIBISO_LIBISOFS_H
|
|
||||||
|
|
||||||
/* #include <libburn.h> */
|
|
||||||
struct burn_source;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data volume.
|
|
||||||
* @see volume.h for details.
|
|
||||||
*/
|
|
||||||
struct iso_volume;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of data volumes.
|
|
||||||
* @see volume.h for details.
|
|
||||||
*/
|
|
||||||
struct iso_volset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A node in the filesystem tree.
|
|
||||||
* \see tree.h
|
|
||||||
*/
|
|
||||||
struct iso_tree_node;
|
|
||||||
|
|
||||||
enum ecma119_extension_flag {
|
|
||||||
ECMA119_ROCKRIDGE = (1<<0),
|
|
||||||
ECMA119_JOLIET = (1<<1)
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new volume.
|
|
||||||
* The parameters can be set to NULL if you wish to set them later.
|
|
||||||
*/
|
|
||||||
struct iso_volume *iso_volume_new(const char *volume_id,
|
|
||||||
const char *publisher_id,
|
|
||||||
const char *data_preparer_id);
|
|
||||||
|
|
||||||
struct iso_volume *iso_volume_new_with_root(const char *volume_id,
|
|
||||||
const char *publisher_id,
|
|
||||||
const char *data_preparer_id,
|
|
||||||
struct iso_tree_node *root);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free a volume.
|
|
||||||
*/
|
|
||||||
void iso_volume_free(struct iso_volume *volume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free a set of data volumes.
|
|
||||||
*/
|
|
||||||
void iso_volset_free(struct iso_volset *volume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the root directory for a volume.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fill in the volume identifier for a volume.
|
|
||||||
*/
|
|
||||||
void iso_volume_set_volume_id(struct iso_volume *volume,
|
|
||||||
const char *volume_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fill in the publisher for a volume.
|
|
||||||
*/
|
|
||||||
void iso_volume_set_publisher_id(struct iso_volume *volume,
|
|
||||||
const char *publisher_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fill in the data preparer for a volume.
|
|
||||||
*/
|
|
||||||
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
|
|
||||||
const char *data_preparer_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locate a node by its path on disc.
|
|
||||||
*
|
|
||||||
* \param volume The volume to search in.
|
|
||||||
* \param path The path, in the image, of the file.
|
|
||||||
*
|
|
||||||
* \return The node found or NULL.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a file or a directory (recursively) to a volume by specifying its path on the volume.
|
|
||||||
*
|
|
||||||
* \param volume The volume to add the file to.
|
|
||||||
* \param disc_path The path on the disc at which to add the disc.
|
|
||||||
* \param path The path, on the local filesystem, of the file.
|
|
||||||
*
|
|
||||||
* \return The node for the file or NULL if the parent doesn't exists on the disc.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_volume_add_path(struct iso_volume *volume,
|
|
||||||
const char *disc_path,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new, empty directory on the volume.
|
|
||||||
*
|
|
||||||
* \param volume The volume to add the directory to.
|
|
||||||
* \param disc_path The path on the volume at which to add the directory.
|
|
||||||
*
|
|
||||||
* \return A pointer to the newly created directory.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_volume_add_new_dir(struct iso_volume *volume,
|
|
||||||
const char *disc_path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new Volume Set consisting of only one volume.
|
|
||||||
* @param volume The first and only volume for the volset to contain.
|
|
||||||
* @param volset_id The Volume Set ID.
|
|
||||||
* @return A new iso_volset.
|
|
||||||
*/
|
|
||||||
struct iso_volset *iso_volset_new(struct iso_volume *volume,
|
|
||||||
const char *volset_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a file to a directory.
|
|
||||||
*
|
|
||||||
* \param path The path, on the local filesystem, of the file.
|
|
||||||
*
|
|
||||||
* \pre \p parent is NULL or is a directory.
|
|
||||||
* \pre \p path is non-NULL and is a valid path to a non-directory on the local
|
|
||||||
* filesystem.
|
|
||||||
* \return An iso_tree_node whose path is \p path and whose parent is \p parent.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively add an existing directory to the tree.
|
|
||||||
* Warning: when using this, you'll lose pointers to files or subdirectories.
|
|
||||||
* If you want to have pointers to all files and directories,
|
|
||||||
* use iso_tree_add_file and iso_tree_add_dir.
|
|
||||||
*
|
|
||||||
* \param path The path, on the local filesystem, of the directory to add.
|
|
||||||
*
|
|
||||||
* \pre \p parent is NULL or is a directory.
|
|
||||||
* \pre \p path is non-NULL and is a valid path to a directory on the local
|
|
||||||
* filesystem.
|
|
||||||
* \return a pointer to the newly created directory.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the path of a file or directory to ignore when adding a directory recursively.
|
|
||||||
*
|
|
||||||
* \param path The path, on the local filesystem, of the file.
|
|
||||||
*/
|
|
||||||
void iso_exclude_add_path(const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a path that was set to be ignored when adding a directory recusively.
|
|
||||||
*
|
|
||||||
* \param path The path, on the local filesystem, of the file.
|
|
||||||
*/
|
|
||||||
void iso_exclude_remove_path(const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all paths that were set to be ignored when adding a directory recusively.
|
|
||||||
*/
|
|
||||||
void iso_exclude_empty(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new, empty directory on the volume.
|
|
||||||
*
|
|
||||||
* \pre \p parent is NULL or is a directory.
|
|
||||||
* \pre \p name is unique among the children and files belonging to \p parent.
|
|
||||||
* Also, it doesn't contain '/' characters.
|
|
||||||
*
|
|
||||||
* \post \p parent contains a child directory whose name is \p name and whose
|
|
||||||
* POSIX attributes are the same as \p parent's.
|
|
||||||
* \return a pointer to the newly created directory.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent,
|
|
||||||
const char *name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of a file (using the current locale).
|
|
||||||
*/
|
|
||||||
void iso_tree_node_set_name(struct iso_tree_node *file, const char *name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively print a directory to stdout.
|
|
||||||
* \param spaces The initial number of spaces on the left. Set to 0 if you
|
|
||||||
* supply a root directory.
|
|
||||||
*/
|
|
||||||
void iso_tree_print(const struct iso_tree_node *root, int spaces);
|
|
||||||
|
|
||||||
/** Create a burn_source which can be used as a data source for a track
|
|
||||||
*
|
|
||||||
* The volume set used to create the libburn_source can _not_ be modified
|
|
||||||
* until the libburn_source is freed.
|
|
||||||
*
|
|
||||||
* \param volumeset The volume set from which you want to write
|
|
||||||
* \param volnum The volume in the set which you want to write (usually 0)
|
|
||||||
* \param level ISO level to write at.
|
|
||||||
* \param flags Which extensions to support.
|
|
||||||
*
|
|
||||||
* \pre \p volumeset is non-NULL
|
|
||||||
* \pre \p volnum is less than \p volset->volset_size.
|
|
||||||
* \return A burn_source to be used for the data source for a track
|
|
||||||
*/
|
|
||||||
struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset,
|
|
||||||
int volnum,
|
|
||||||
int level,
|
|
||||||
int flags);
|
|
||||||
|
|
||||||
#endif /* LIBISO_LIBISOFS_H */
|
|
@ -1,300 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
#include "rockridge.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "ecma119.h"
|
|
||||||
#include "ecma119_tree.h"
|
|
||||||
#include "tree.h"
|
|
||||||
#include "susp.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
/* create a PX field from the permissions on the current node. */
|
|
||||||
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
|
|
||||||
struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
uint8_t *PX = malloc(44);
|
|
||||||
|
|
||||||
PX[0] = 'P';
|
|
||||||
PX[1] = 'X';
|
|
||||||
PX[2] = 44;
|
|
||||||
PX[3] = 1;
|
|
||||||
iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4);
|
|
||||||
iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4);
|
|
||||||
iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4);
|
|
||||||
iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4);
|
|
||||||
iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4);
|
|
||||||
return PX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** See IEEE 1282 4.1.1 */
|
|
||||||
void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
susp_append(t, &node->susp, rrip_make_PX(t, node));
|
|
||||||
if (node->type == ECMA119_DIR) {
|
|
||||||
susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node));
|
|
||||||
susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
uint8_t *PN = malloc(20);
|
|
||||||
|
|
||||||
PN[0] = 'P';
|
|
||||||
PN[1] = 'N';
|
|
||||||
PN[2] = 20;
|
|
||||||
PN[3] = 1;
|
|
||||||
iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4);
|
|
||||||
iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4);
|
|
||||||
susp_append(t, &node->susp, PN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rrip_SL_append_comp(int *n, uint8_t ***comps,
|
|
||||||
char *s, int size, char fl)
|
|
||||||
{
|
|
||||||
uint8_t *comp = malloc(size + 2);
|
|
||||||
|
|
||||||
(*n)++;
|
|
||||||
comp[0] = fl;
|
|
||||||
comp[1] = size;
|
|
||||||
*comps = realloc(*comps, (*n) * sizeof(void*));
|
|
||||||
(*comps)[(*n) - 1] = comp;
|
|
||||||
|
|
||||||
if (size) {
|
|
||||||
memcpy(&comp[2], s, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
|
|
||||||
uint8_t ***comps)
|
|
||||||
{
|
|
||||||
int size = cur - prev;
|
|
||||||
|
|
||||||
if (size == 0) {
|
|
||||||
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 1 && prev[0] == '.') {
|
|
||||||
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (size == 2 && !strncmp(prev, "..", 2)) {
|
|
||||||
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we can't make a component any bigger than 250 (is this really a
|
|
||||||
problem)? because then it won't fit inside the SL field */
|
|
||||||
while (size > 248) {
|
|
||||||
size -= 248;
|
|
||||||
rrip_SL_append_comp(n_comp, comps, prev, 248, 1 << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
rrip_SL_append_comp(n_comp, comps, prev, size, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
int ret, pathsize = 0;
|
|
||||||
char *path = NULL, *cur, *prev;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
uint8_t **comp = NULL;
|
|
||||||
int n_comp = 0;
|
|
||||||
int total_comp_len = 0;
|
|
||||||
int written = 0, pos;
|
|
||||||
|
|
||||||
uint8_t *SL;
|
|
||||||
|
|
||||||
do {
|
|
||||||
pathsize += 128;
|
|
||||||
path = realloc(path, pathsize);
|
|
||||||
/* FIXME: what if the file is not on the local fs? */
|
|
||||||
ret = readlink(node->iso_self->loc.path, path, pathsize);
|
|
||||||
} while (ret == pathsize);
|
|
||||||
if (ret == -1) {
|
|
||||||
fprintf(stderr, "Error: couldn't read symlink: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
path[ret] = '\0';
|
|
||||||
|
|
||||||
prev = path;
|
|
||||||
for (cur = strchr(path, '/'); cur && *cur; cur = strchr(cur, '/')) {
|
|
||||||
rrip_SL_add_component(prev, cur, &n_comp, &comp);
|
|
||||||
cur++;
|
|
||||||
prev = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if there was no trailing '/', we need to add the last component. */
|
|
||||||
if (prev == path || prev != &path[ret - 1]) {
|
|
||||||
rrip_SL_add_component(prev, &path[ret], &n_comp, &comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < n_comp; i++) {
|
|
||||||
total_comp_len += comp[i][1] + 2;
|
|
||||||
if (total_comp_len > 250) {
|
|
||||||
total_comp_len -= comp[i][1] + 2;
|
|
||||||
SL = malloc(total_comp_len + 5);
|
|
||||||
SL[0] = 'S';
|
|
||||||
SL[1] = 'L';
|
|
||||||
SL[2] = total_comp_len + 5;
|
|
||||||
SL[3] = 1;
|
|
||||||
SL[4] = 1; /* CONTINUE */
|
|
||||||
pos = 5;
|
|
||||||
for (j = written; j < i; j++) {
|
|
||||||
memcpy(&SL[pos], comp[j], comp[j][2]);
|
|
||||||
pos += comp[j][2];
|
|
||||||
}
|
|
||||||
susp_append(t, &node->susp, SL);
|
|
||||||
written = i - 1;
|
|
||||||
total_comp_len = comp[i][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SL = malloc(total_comp_len + 5);
|
|
||||||
SL[0] = 'S';
|
|
||||||
SL[1] = 'L';
|
|
||||||
SL[2] = total_comp_len + 5;
|
|
||||||
SL[3] = 1;
|
|
||||||
SL[4] = 0;
|
|
||||||
pos = 5;
|
|
||||||
|
|
||||||
for (j = written; j < n_comp; j++) {
|
|
||||||
memcpy(&SL[pos], comp[j], comp[j][1] + 2);
|
|
||||||
pos += comp[j][1] + 2;
|
|
||||||
}
|
|
||||||
susp_append(t, &node->susp, SL);
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
/* free the components */
|
|
||||||
for (i = 0; i < n_comp; i++) {
|
|
||||||
free(comp[i]);
|
|
||||||
}
|
|
||||||
free(comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rrip_add_NM_single(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
char *name, int size, int flags)
|
|
||||||
{
|
|
||||||
uint8_t *NM = malloc(size + 5);
|
|
||||||
|
|
||||||
NM[0] = 'N';
|
|
||||||
NM[1] = 'M';
|
|
||||||
NM[2] = size + 5;
|
|
||||||
NM[3] = 1;
|
|
||||||
NM[4] = flags;
|
|
||||||
if (size) {
|
|
||||||
memcpy(&NM[5], name, size);
|
|
||||||
}
|
|
||||||
susp_append(t, susp, NM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
char *name = iso_p_fileid(node->iso_self->name);
|
|
||||||
int len = name ? strlen(name) : 0;
|
|
||||||
char *pos = name;
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (node->type == ECMA119_DIR) {
|
|
||||||
rrip_add_NM_single(t, &node->dir.self_susp, pos, 0, 1 << 1);
|
|
||||||
rrip_add_NM_single(t, &node->dir.parent_susp, pos, 0, 1 << 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (len > 250) {
|
|
||||||
rrip_add_NM_single(t, &node->susp, pos, 250, 1);
|
|
||||||
len -= 250;
|
|
||||||
pos += 250;
|
|
||||||
}
|
|
||||||
rrip_add_NM_single(t, &node->susp, pos, len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrip_add_CL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
uint8_t *CL = calloc(1, 12);
|
|
||||||
|
|
||||||
CL[0] = 'C';
|
|
||||||
CL[1] = 'L';
|
|
||||||
CL[2] = 12;
|
|
||||||
CL[3] = 1;
|
|
||||||
susp_append(t, &node->susp, CL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
uint8_t *PL = calloc(1, 12);
|
|
||||||
|
|
||||||
PL[0] = 'P';
|
|
||||||
PL[1] = 'L';
|
|
||||||
PL[2] = 12;
|
|
||||||
PL[3] = 1;
|
|
||||||
susp_append(t, &node->dir.parent_susp, PL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rrip_add_RE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
uint8_t *RE = malloc(4);
|
|
||||||
|
|
||||||
RE[0] = 'R';
|
|
||||||
RE[1] = 'E';
|
|
||||||
RE[2] = 4;
|
|
||||||
RE[3] = 1;
|
|
||||||
susp_append(t, &node->susp, RE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
uint8_t *TF = malloc(5 + 3 * 7);
|
|
||||||
|
|
||||||
TF[0] = 'T';
|
|
||||||
TF[1] = 'F';
|
|
||||||
TF[2] = 5 + 3 * 7;
|
|
||||||
TF[3] = 1;
|
|
||||||
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
|
|
||||||
iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime);
|
|
||||||
iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime);
|
|
||||||
iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime);
|
|
||||||
susp_append(t, &node->susp, TF);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
assert(dir->type == ECMA119_DIR);
|
|
||||||
|
|
||||||
if (dir->parent != dir->dir.real_parent) {
|
|
||||||
uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL");
|
|
||||||
|
|
||||||
assert(PL);
|
|
||||||
iso_bb(&PL[4], dir->dir.real_parent->block, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
|
||||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
|
||||||
|
|
||||||
if (ch->type == ECMA119_FILE && ch->file.real_me) {
|
|
||||||
uint8_t *CL = susp_find(&ch->susp, "CL");
|
|
||||||
|
|
||||||
assert(CL);
|
|
||||||
iso_bb(&CL[4], ch->file.real_me->block, 4);
|
|
||||||
} else if (ch->type == ECMA119_DIR) {
|
|
||||||
rrip_finalize(t, ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/** Functions and structures used for Rock Ridge support. */
|
|
||||||
|
|
||||||
#ifndef ISO_ROCKRIDGE_H
|
|
||||||
#define ISO_ROCKRIDGE_H
|
|
||||||
|
|
||||||
struct ecma119_write_target;
|
|
||||||
struct ecma119_tree_node;
|
|
||||||
|
|
||||||
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
|
|
||||||
/* This is special because it doesn't modify the susp fields of the directory
|
|
||||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
|
||||||
* that directory. */
|
|
||||||
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
|
|
||||||
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
|
|
||||||
#endif /* ISO_ROCKRIDGE_H */
|
|
@ -1,280 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
#include "susp.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "ecma119.h"
|
|
||||||
#include "ecma119_tree.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
void susp_insert(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
uint8_t *data,
|
|
||||||
int pos)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (pos < 0) {
|
|
||||||
pos = susp->n_susp_fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(pos <= susp->n_susp_fields);
|
|
||||||
susp->n_susp_fields++;
|
|
||||||
susp->susp_fields = realloc(susp->susp_fields,
|
|
||||||
sizeof(void*) * susp->n_susp_fields);
|
|
||||||
|
|
||||||
for (i = susp->n_susp_fields-1; i > pos; i--) {
|
|
||||||
susp->susp_fields[i] = susp->susp_fields[i - 1];
|
|
||||||
}
|
|
||||||
susp->susp_fields[pos] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_append(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
uint8_t *data)
|
|
||||||
{
|
|
||||||
susp_insert(t, susp, data, susp->n_susp_fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *susp_find(struct susp_info *susp, const char *name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < susp->n_susp_fields; i++) {
|
|
||||||
if (!strncmp((char *)susp->susp_fields[i], name, 2)) {
|
|
||||||
return susp->susp_fields[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Utility function for susp_add_CE because susp_add_CE needs to act 3 times
|
|
||||||
* on directories (for the "." and ".." entries.
|
|
||||||
*
|
|
||||||
* \param len The amount of space available for the System Use area.
|
|
||||||
*/
|
|
||||||
#define CE_LEN 28
|
|
||||||
static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
int len)
|
|
||||||
{
|
|
||||||
int susp_length = 0, tmp_len;
|
|
||||||
int i;
|
|
||||||
unsigned char *CE;
|
|
||||||
|
|
||||||
for (i = 0; i < susp->n_susp_fields; i++) {
|
|
||||||
susp_length += susp->susp_fields[i][2];
|
|
||||||
}
|
|
||||||
if (susp_length <= len) {
|
|
||||||
/* no need for a CE field */
|
|
||||||
susp->non_CE_len = susp_length;
|
|
||||||
susp->n_fields_fit = susp->n_susp_fields;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_len = susp_length;
|
|
||||||
for (i = susp->n_susp_fields - 1; i >= 0; i--) {
|
|
||||||
tmp_len -= susp->susp_fields[i][2];
|
|
||||||
if (tmp_len + CE_LEN <= len) {
|
|
||||||
susp->non_CE_len = tmp_len + CE_LEN;
|
|
||||||
susp->CE_len = susp_length - tmp_len;
|
|
||||||
|
|
||||||
/* i+1 because we have to count the CE field */
|
|
||||||
susp->n_fields_fit = i + 1;
|
|
||||||
|
|
||||||
CE = calloc(1, CE_LEN);
|
|
||||||
/* we don't fill in the BLOCK LOCATION or OFFSET
|
|
||||||
fields yet. */
|
|
||||||
CE[0] = 'C';
|
|
||||||
CE[1] = 'E';
|
|
||||||
CE[2] = (char)CE_LEN;
|
|
||||||
CE[3] = (char)1;
|
|
||||||
iso_bb(&CE[20], susp_length - tmp_len, 4);
|
|
||||||
|
|
||||||
return CE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
try_add_CE(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
size_t dirent_len)
|
|
||||||
{
|
|
||||||
uint8_t *CE = susp_add_single_CE(t, susp, 255 - dirent_len);
|
|
||||||
if (CE)
|
|
||||||
susp_insert(t, susp, CE, susp->n_fields_fit - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the
|
|
||||||
* length of the other SUSP fields, it should always be calculated last. */
|
|
||||||
void
|
|
||||||
susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|
||||||
{
|
|
||||||
try_add_CE(t, &node->susp, node->dirent_len);
|
|
||||||
if (node->type == ECMA119_DIR) {
|
|
||||||
try_add_CE(t, &node->dir.self_susp, 34);
|
|
||||||
try_add_CE(t, &node->dir.parent_susp, 34);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.3 */
|
|
||||||
void
|
|
||||||
susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|
||||||
{
|
|
||||||
unsigned char *SP = malloc(7);
|
|
||||||
|
|
||||||
assert(dir->type == ECMA119_DIR);
|
|
||||||
|
|
||||||
SP[0] = 'S';
|
|
||||||
SP[1] = 'P';
|
|
||||||
SP[2] = (char)7;
|
|
||||||
SP[3] = (char)1;
|
|
||||||
SP[4] = 0xbe;
|
|
||||||
SP[5] = 0xef;
|
|
||||||
SP[6] = 0;
|
|
||||||
susp_append(t, &dir->dir.self_susp, SP);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.4 */
|
|
||||||
static void susp_add_ST(struct ecma119_write_target *t,
|
|
||||||
struct iso_tree_node *node)
|
|
||||||
{
|
|
||||||
unsigned char *ST = malloc(4);
|
|
||||||
|
|
||||||
ST[0] = 'S';
|
|
||||||
ST[1] = 'T';
|
|
||||||
ST[2] = (char)4;
|
|
||||||
ST[3] = (char)1;
|
|
||||||
susp_append(t, node, ST);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
|
|
||||||
void
|
|
||||||
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|
||||||
{
|
|
||||||
unsigned char *ER = malloc(182);
|
|
||||||
|
|
||||||
assert(dir->type == ECMA119_DIR);
|
|
||||||
|
|
||||||
ER[0] = 'E';
|
|
||||||
ER[1] = 'R';
|
|
||||||
ER[2] = 182;
|
|
||||||
ER[3] = 1;
|
|
||||||
ER[4] = 9;
|
|
||||||
ER[5] = 72;
|
|
||||||
ER[6] = 93;
|
|
||||||
ER[7] = 1;
|
|
||||||
memcpy(&ER[8], "IEEE_1282", 9);
|
|
||||||
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
|
|
||||||
"FILE SYSTEM SEMANTICS.", 72);
|
|
||||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
|
||||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
|
||||||
susp_append(t, &dir->dir.self_susp, ER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate the location of the CE areas. Since CE areas don't need to be
|
|
||||||
* aligned to a block boundary, we contatenate all CE areas from a single
|
|
||||||
* directory and dump them immediately after all the directory records.
|
|
||||||
*
|
|
||||||
* Requires that the following be known:
|
|
||||||
* - position of the current directory (dir->block)
|
|
||||||
* - length of the current directory (dir->dir.len)
|
|
||||||
* - sum of the children's CE lengths (dir->dir.CE_len)
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
susp_fin_1_CE(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
size_t block,
|
|
||||||
size_t *offset)
|
|
||||||
{
|
|
||||||
uint8_t *CE = susp->susp_fields[susp->n_fields_fit - 1];
|
|
||||||
|
|
||||||
if (!susp->CE_len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
iso_bb(&CE[4], block + (*offset) / t->block_size, 4);
|
|
||||||
iso_bb(&CE[12], (*offset) % t->block_size, 4);
|
|
||||||
*offset += susp->CE_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void susp_fin_CE(struct ecma119_write_target *t,
|
|
||||||
struct ecma119_tree_node *dir)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
size_t CE_offset = dir->dir.len;
|
|
||||||
|
|
||||||
assert(dir->type == ECMA119_DIR);
|
|
||||||
|
|
||||||
susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset);
|
|
||||||
susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset);
|
|
||||||
|
|
||||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
|
||||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
|
||||||
susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset);
|
|
||||||
}
|
|
||||||
assert(CE_offset == dir->dir.len + dir->dir.CE_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
assert(dir->type = ECMA119_DIR);
|
|
||||||
|
|
||||||
if (dir->dir.depth != 1) {
|
|
||||||
susp_fin_CE(t, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
|
||||||
if (dir->dir.children[i]->type == ECMA119_DIR)
|
|
||||||
susp_finalize(t, dir->dir.children[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_write(struct ecma119_write_target *t,
|
|
||||||
struct susp_info *susp,
|
|
||||||
unsigned char *buf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < susp->n_fields_fit; i++) {
|
|
||||||
memcpy(&buf[pos], susp->susp_fields[i],
|
|
||||||
susp->susp_fields[i][2]);
|
|
||||||
pos += susp->susp_fields[i][2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_write_CE(struct ecma119_write_target *t, struct susp_info *susp,
|
|
||||||
unsigned char *buf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
for (i = susp->n_fields_fit; i < susp->n_susp_fields; i++) {
|
|
||||||
memcpy(&buf[pos], susp->susp_fields[i],
|
|
||||||
susp->susp_fields[i][2]);
|
|
||||||
pos += susp->susp_fields[i][2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_free_fields(struct susp_info *susp)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<susp->n_susp_fields; i++) {
|
|
||||||
free(susp->susp_fields[i]);
|
|
||||||
}
|
|
||||||
if (susp->susp_fields) {
|
|
||||||
free(susp->susp_fields);
|
|
||||||
}
|
|
||||||
memset(susp, 0, sizeof(struct susp_info));
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/** Functions and structures used for SUSP (IEEE 1281).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ISO_SUSP
|
|
||||||
#define __ISO_SUSP
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* SUSP is only present in standard ecma119 */
|
|
||||||
struct ecma119_write_target;
|
|
||||||
struct ecma119_tree_node;
|
|
||||||
|
|
||||||
/** This contains the information that needs to go in the SUSP area of a file.
|
|
||||||
*/
|
|
||||||
struct susp_info
|
|
||||||
{
|
|
||||||
int n_susp_fields; /**< Number of SUSP fields */
|
|
||||||
uint8_t **susp_fields; /**< Data for each SUSP field */
|
|
||||||
|
|
||||||
/* the next 3 relate to CE and are filled out by susp_add_CE. */
|
|
||||||
int n_fields_fit; /**< How many of the above SUSP fields fit
|
|
||||||
* within this node's dirent. */
|
|
||||||
int non_CE_len; /**< Length of the part of the SUSP area that
|
|
||||||
* fits in the dirent. */
|
|
||||||
int CE_len; /**< Length of the part of the SUSP area that
|
|
||||||
* will go in a CE area. */
|
|
||||||
};
|
|
||||||
|
|
||||||
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
|
|
||||||
/* these next 2 are special because they don't modify the susp fields of the
|
|
||||||
* directory; they modify the susp fields of the
|
|
||||||
* "." entry in the directory. */
|
|
||||||
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
|
|
||||||
/** Once all the directories and files are laid out, recurse through the tree
|
|
||||||
* and finalize all SUSP CE entries. */
|
|
||||||
void susp_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
|
||||||
|
|
||||||
void susp_append(struct ecma119_write_target *,
|
|
||||||
struct susp_info *,
|
|
||||||
uint8_t *);
|
|
||||||
void susp_insert(struct ecma119_write_target *,
|
|
||||||
struct susp_info *,
|
|
||||||
uint8_t *,
|
|
||||||
int pos);
|
|
||||||
uint8_t *susp_find(struct susp_info *,
|
|
||||||
const char *);
|
|
||||||
|
|
||||||
void susp_write(struct ecma119_write_target *,
|
|
||||||
struct susp_info *,
|
|
||||||
uint8_t *);
|
|
||||||
void susp_write_CE(struct ecma119_write_target *,
|
|
||||||
struct susp_info *,
|
|
||||||
uint8_t *);
|
|
||||||
|
|
||||||
void susp_free_fields(struct susp_info *);
|
|
||||||
|
|
||||||
#endif /* __ISO_SUSP */
|
|
@ -1,223 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file tree.c
|
|
||||||
*
|
|
||||||
* Implement filesystem trees.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "tree.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "volume.h"
|
|
||||||
#include "exclude.h"
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_default_stat(struct stat *s)
|
|
||||||
{
|
|
||||||
time_t now = time(NULL);
|
|
||||||
|
|
||||||
memset(s, 0, sizeof(struct stat));
|
|
||||||
s->st_mode = 0777 | S_IFREG;
|
|
||||||
s->st_atime = s->st_mtime = s->st_ctime = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct stat
|
|
||||||
get_attrib(const struct iso_tree_node *node)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (node) {
|
|
||||||
return node->attrib;
|
|
||||||
}
|
|
||||||
set_default_stat(&st);
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
append_node(struct iso_tree_node *parent,
|
|
||||||
struct iso_tree_node *child)
|
|
||||||
{
|
|
||||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
|
|
||||||
if (!parent)
|
|
||||||
return;
|
|
||||||
|
|
||||||
parent->nchildren++;
|
|
||||||
parent->children =
|
|
||||||
realloc(parent->children, parent->nchildren * sizeof(void*));
|
|
||||||
parent->children[parent->nchildren-1] = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node*
|
|
||||||
iso_tree_new_root(struct iso_volume *vol)
|
|
||||||
{
|
|
||||||
assert(vol);
|
|
||||||
|
|
||||||
if (vol->root) {
|
|
||||||
iso_tree_free(vol->root);
|
|
||||||
}
|
|
||||||
|
|
||||||
vol->root = calloc(1, sizeof(struct iso_tree_node));
|
|
||||||
vol->root->volume = vol;
|
|
||||||
set_default_stat(&vol->root->attrib);
|
|
||||||
vol->root->attrib.st_mode = S_IFDIR | 0777;
|
|
||||||
vol->root->loc.type = LIBISO_NONE;
|
|
||||||
return vol->root;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node*
|
|
||||||
iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
|
|
||||||
{
|
|
||||||
struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node));
|
|
||||||
|
|
||||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
|
|
||||||
|
|
||||||
f->volume = parent ? parent->volume : NULL;
|
|
||||||
f->parent = parent;
|
|
||||||
f->name = parent ? strdup(name) : NULL;
|
|
||||||
f->attrib = get_attrib(parent);
|
|
||||||
f->attrib.st_mode = 0777 | S_IFREG;
|
|
||||||
f->loc.type = LIBISO_NONE;
|
|
||||||
append_node(parent, f);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node*
|
|
||||||
iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name)
|
|
||||||
{
|
|
||||||
struct iso_tree_node *d = iso_tree_add_new_file(parent, name);
|
|
||||||
|
|
||||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
|
|
||||||
|
|
||||||
d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node*
|
|
||||||
iso_tree_add_node(struct iso_tree_node *parent, const char *path)
|
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
struct stat st;
|
|
||||||
struct iso_tree_node *ret;
|
|
||||||
|
|
||||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
|
|
||||||
|
|
||||||
if (lstat(path, &st) == -1)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
p = strdup(path); /* because basename() might modify its arg */
|
|
||||||
|
|
||||||
/* it doesn't matter if we add a file or directory since we modify
|
|
||||||
* attrib anyway. */
|
|
||||||
ret = iso_tree_add_new_file(parent, basename(p));
|
|
||||||
ret->attrib = st;
|
|
||||||
ret->loc.type = LIBISO_FILESYS;
|
|
||||||
ret->loc.path = strdup(path);
|
|
||||||
free(p);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node*
|
|
||||||
iso_tree_radd_dir (struct iso_tree_node *parent, const char *path)
|
|
||||||
{
|
|
||||||
struct iso_tree_node *new;
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *ent;
|
|
||||||
|
|
||||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
|
|
||||||
|
|
||||||
new = iso_tree_add_node(parent, path);
|
|
||||||
if (!new || !S_ISDIR(new->attrib.st_mode)) {
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir = opendir(path);
|
|
||||||
if (!dir) {
|
|
||||||
warn("couldn't open directory %s: %s\n", path, strerror(errno));
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ent = readdir(dir))) {
|
|
||||||
char child[strlen(ent->d_name) + strlen(path) + 2];
|
|
||||||
|
|
||||||
if (strcmp(ent->d_name, ".") == 0 ||
|
|
||||||
strcmp(ent->d_name, "..") == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
sprintf(child, "%s/%s", path, ent->d_name);
|
|
||||||
|
|
||||||
/* see if this child is excluded. */
|
|
||||||
if (iso_exclude_lookup(child))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
iso_tree_radd_dir(new, child);
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_tree_free(struct iso_tree_node *root)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i=0; i < root->nchildren; i++) {
|
|
||||||
iso_tree_free(root->children[i]);
|
|
||||||
}
|
|
||||||
free(root->name);
|
|
||||||
free(root->children);
|
|
||||||
free(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_tree_print(const struct iso_tree_node *root, int spaces)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
char sp[spaces+1];
|
|
||||||
|
|
||||||
memset(sp, ' ', spaces);
|
|
||||||
sp[spaces] = '\0';
|
|
||||||
|
|
||||||
printf("%s%sn", sp, root->name);
|
|
||||||
for (i=0; i < root->nchildren; i++) {
|
|
||||||
iso_tree_print(root->children[i], spaces+2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_tree_print_verbose(const struct iso_tree_node *root,
|
|
||||||
print_dir_callback dir,
|
|
||||||
print_file_callback file,
|
|
||||||
void *callback_data,
|
|
||||||
int spaces)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
(S_ISDIR(root->attrib.st_mode) ? dir : file)
|
|
||||||
(root, callback_data, spaces);
|
|
||||||
for (i=0; i < root->nchildren; i++) {
|
|
||||||
iso_tree_print_verbose(root->children[i], dir,
|
|
||||||
file, callback_data, spaces+2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
|
|
||||||
{
|
|
||||||
free(file->name);
|
|
||||||
file->name = strdup(name);
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file tree.h
|
|
||||||
*
|
|
||||||
* Declare the structure of a libisofs filesystem tree. The files in this
|
|
||||||
* tree can come from either the local filesystem or from another .iso image
|
|
||||||
* (for multisession).
|
|
||||||
*
|
|
||||||
* This tree preserves as much information as it can about the files; names
|
|
||||||
* are stored in wchar_t and we preserve POSIX attributes. This tree does
|
|
||||||
* *not* include information that is necessary for writing out, for example,
|
|
||||||
* an ISO level 1 tree. That information will go in a different tree because
|
|
||||||
* the structure is sufficiently different.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBISO_TREE_H
|
|
||||||
#define LIBISO_TREE_H
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
|
|
||||||
#include "libisofs.h"
|
|
||||||
|
|
||||||
enum file_location {
|
|
||||||
LIBISO_FILESYS,
|
|
||||||
LIBISO_PREVSESSION,
|
|
||||||
LIBISO_NONE /**< for files/dirs that were added with
|
|
||||||
* iso_tree_add_new_XXX. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This tells us where to read the data from a file. Either we read from the
|
|
||||||
* local filesystem or we just point to the block on a previous session.
|
|
||||||
*/
|
|
||||||
struct iso_file_location
|
|
||||||
{
|
|
||||||
enum file_location type;
|
|
||||||
/* union {*/
|
|
||||||
char *path; /* in the current locale */
|
|
||||||
uint32_t block;
|
|
||||||
/* };*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A node in the filesystem tree.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node
|
|
||||||
{
|
|
||||||
struct iso_volume *volume;
|
|
||||||
struct iso_tree_node *parent;
|
|
||||||
char *name;
|
|
||||||
struct stat attrib; /**< The POSIX attributes of this node as
|
|
||||||
* documented in "man 2 stat". */
|
|
||||||
struct iso_file_location loc;
|
|
||||||
/**< Only used for regular files and symbolic
|
|
||||||
* links (ie. files for which we might have to
|
|
||||||
* copy data). */
|
|
||||||
|
|
||||||
size_t nchildren; /**< The number of children of this
|
|
||||||
* directory (if this is a directory). */
|
|
||||||
struct iso_tree_node **children;
|
|
||||||
|
|
||||||
size_t block; /**< The block at which this file will
|
|
||||||
* reside on disk. We store this here as
|
|
||||||
* well as in the various mangled trees
|
|
||||||
* because many different trees might point
|
|
||||||
* to the same file and they need to share the
|
|
||||||
* block location. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new root directory for a volume.
|
|
||||||
*
|
|
||||||
* \param vol The volume for which to create a new root directory.
|
|
||||||
*
|
|
||||||
* \pre \p vol is non-NULL.
|
|
||||||
* \post \p vol has a non-NULL, empty root directory with permissions 777.
|
|
||||||
* \return \p vol's new non-NULL, empty root directory.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new, empty, file.
|
|
||||||
*
|
|
||||||
* \param parent The parent directory of the new file. If this is null, create
|
|
||||||
* and return a new file node without adding it to any tree.
|
|
||||||
* \param name The name of the new file, encoded in the current locale.
|
|
||||||
* \pre \p name is non-NULL and it does not match any other file or directory
|
|
||||||
* name in \p parent.
|
|
||||||
* \post \p parent (if non-NULL) contains a file with the following properties:
|
|
||||||
* - the file's name is \p name (converted to wchar_t)
|
|
||||||
* - the file's POSIX permissions are the same as \p parent's
|
|
||||||
* - the file is a regular file
|
|
||||||
* - the file is empty
|
|
||||||
*
|
|
||||||
* \return \p parent's newly created file.
|
|
||||||
*/
|
|
||||||
struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent,
|
|
||||||
const char *name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively free a directory.
|
|
||||||
*
|
|
||||||
* \param root The root of the directory heirarchy to free.
|
|
||||||
*
|
|
||||||
* \pre \p root is non-NULL.
|
|
||||||
*/
|
|
||||||
void iso_tree_free(struct iso_tree_node *root);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function that prints verbose information about a directory.
|
|
||||||
*
|
|
||||||
* \param dir The directory about which to print information.
|
|
||||||
* \param data Unspecified function-dependent data.
|
|
||||||
* \param spaces The number of spaces to prepend to the output.
|
|
||||||
*
|
|
||||||
* \see iso_tree_print_verbose
|
|
||||||
*/
|
|
||||||
typedef void (*print_dir_callback) (const struct iso_tree_node *dir,
|
|
||||||
void *data,
|
|
||||||
int spaces);
|
|
||||||
/**
|
|
||||||
* A function that prints verbose information about a file.
|
|
||||||
*
|
|
||||||
* \param dir The file about which to print information.
|
|
||||||
* \param data Unspecified function-dependent data.
|
|
||||||
* \param spaces The number of spaces to prepend to the output.
|
|
||||||
*
|
|
||||||
* \see iso_tree_print_verbose
|
|
||||||
*/
|
|
||||||
typedef void (*print_file_callback) (const struct iso_tree_node *file,
|
|
||||||
void *data,
|
|
||||||
int spaces);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively print a directory heirarchy. For each node in the directory
|
|
||||||
* heirarchy, call a callback function to print information more verbosely.
|
|
||||||
*
|
|
||||||
* \param root The root of the directory heirarchy to print.
|
|
||||||
* \param dir The callback function to call for each directory in the tree.
|
|
||||||
* \param file The callback function to call for each file in the tree.
|
|
||||||
* \param callback_data The data to pass to the callback functions.
|
|
||||||
* \param spaces The number of spaces to prepend to the output.
|
|
||||||
*
|
|
||||||
* \pre \p root is not NULL.
|
|
||||||
* \pre Neither of the callback functions modifies the directory heirarchy.
|
|
||||||
*/
|
|
||||||
void iso_tree_print_verbose(const struct iso_tree_node *root,
|
|
||||||
print_dir_callback dir,
|
|
||||||
print_file_callback file,
|
|
||||||
void *callback_data,
|
|
||||||
int spaces);
|
|
||||||
|
|
||||||
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
|
|
||||||
|
|
||||||
#endif /* LIBISO_TREE_H */
|
|
@ -1,584 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility functions for the Libisofs library.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <iconv.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <locale.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
/* avoids warning and names in iso, joliet and rockridge can't be > 255 bytes
|
|
||||||
* anyway. There are at most 31 characters in iso level 1, 255 for rockridge,
|
|
||||||
* 64 characters (* 2 since UCS) for joliet. */
|
|
||||||
#define NAME_BUFFER_SIZE 255
|
|
||||||
|
|
||||||
int div_up(int n, int div)
|
|
||||||
{
|
|
||||||
return (n + div - 1) / div;
|
|
||||||
}
|
|
||||||
|
|
||||||
int round_up(int n, int mul)
|
|
||||||
{
|
|
||||||
return div_up(n, mul) * mul;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this function must always return a name
|
|
||||||
* since the caller never checks if a NULL
|
|
||||||
* is returned. It also avoids some warnings. */
|
|
||||||
char *str2ascii(const char *src_arg)
|
|
||||||
{
|
|
||||||
wchar_t wsrc_[NAME_BUFFER_SIZE];
|
|
||||||
char *src = (char*)wsrc_;
|
|
||||||
char *ret_;
|
|
||||||
char *ret;
|
|
||||||
mbstate_t state;
|
|
||||||
iconv_t conv;
|
|
||||||
size_t numchars;
|
|
||||||
size_t outbytes;
|
|
||||||
size_t inbytes;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (!src_arg)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* convert the string to a wide character string. Note: outbytes
|
|
||||||
* is in fact the number of characters in the string and doesn't
|
|
||||||
* include the last NULL character. */
|
|
||||||
memset(&state, 0, sizeof(state));
|
|
||||||
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
|
|
||||||
if (numchars < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
inbytes = numchars * sizeof(wchar_t);
|
|
||||||
|
|
||||||
ret_ = malloc(numchars+1);
|
|
||||||
outbytes = numchars;
|
|
||||||
ret = ret_;
|
|
||||||
|
|
||||||
/* initialize iconv */
|
|
||||||
conv = iconv_open("ASCII", "WCHAR_T");
|
|
||||||
if (conv == (iconv_t)-1)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
|
||||||
while(n == -1) {
|
|
||||||
/* The destination buffer is too small. Stops here. */
|
|
||||||
if(errno == E2BIG)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* An incomplete multi bytes sequence was found. We
|
|
||||||
* can't do anything here. That's quite unlikely. */
|
|
||||||
if(errno == EINVAL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* The last possible error is an invalid multi bytes
|
|
||||||
* sequence. Just replace the character with a "_".
|
|
||||||
* Probably the character doesn't exist in ascii like
|
|
||||||
* "é, è, à, ç, ..." in French. */
|
|
||||||
*ret++ = '_';
|
|
||||||
outbytes--;
|
|
||||||
|
|
||||||
if(!outbytes)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* There was an error with one character but some other remain
|
|
||||||
* to be converted. That's probably a multibyte character.
|
|
||||||
* See above comment. */
|
|
||||||
src += sizeof(wchar_t);
|
|
||||||
inbytes -= sizeof(wchar_t);
|
|
||||||
|
|
||||||
if(!inbytes)
|
|
||||||
break;
|
|
||||||
|
|
||||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
iconv_close(conv);
|
|
||||||
|
|
||||||
*ret='\0';
|
|
||||||
return ret_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: C&P */
|
|
||||||
uint16_t *str2ucs(const char *src_arg)
|
|
||||||
{
|
|
||||||
wchar_t wsrc_[NAME_BUFFER_SIZE];
|
|
||||||
char *src = (char*)wsrc_;
|
|
||||||
char *ret_;
|
|
||||||
char *ret;
|
|
||||||
mbstate_t state;
|
|
||||||
iconv_t conv;
|
|
||||||
size_t outbytes;
|
|
||||||
size_t numchars;
|
|
||||||
size_t inbytes;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (!src_arg)
|
|
||||||
return calloc(2, 1); /* empty UCS string */
|
|
||||||
|
|
||||||
/* convert the string to a wide character string. Note: outbytes
|
|
||||||
* is in fact the number of characters in the string and doesn't
|
|
||||||
* include the last NULL character. */
|
|
||||||
memset(&state, 0, sizeof(state));
|
|
||||||
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
|
|
||||||
if (numchars < 0)
|
|
||||||
return calloc(2, 1); /* empty UCS string */
|
|
||||||
|
|
||||||
inbytes = numchars * sizeof(wchar_t);
|
|
||||||
|
|
||||||
outbytes = numchars * sizeof(uint16_t);
|
|
||||||
ret_ = malloc ((numchars+1) * sizeof(uint16_t));
|
|
||||||
ret = ret_;
|
|
||||||
|
|
||||||
/* initialize iconv */
|
|
||||||
conv = iconv_open("UCS-2BE", "WCHAR_T");
|
|
||||||
if (conv == (iconv_t)-1)
|
|
||||||
return calloc(2, 1); /* empty UCS string */
|
|
||||||
|
|
||||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
|
||||||
while(n == -1) {
|
|
||||||
/* The destination buffer is too small. Stops here. */
|
|
||||||
if(errno == E2BIG)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* An incomplete multi bytes sequence was found. We
|
|
||||||
* can't do anything here. That's quite unlikely. */
|
|
||||||
if(errno == EINVAL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* The last possible error is an invalid multi bytes
|
|
||||||
* sequence. Just replace the character with a "_".
|
|
||||||
* Probably the character doesn't exist in ascii like
|
|
||||||
* "é, è, à, ç, ..." in French. */
|
|
||||||
*((uint16_t*) ret) = '_';
|
|
||||||
ret += sizeof(uint16_t);
|
|
||||||
outbytes -= sizeof(uint16_t);
|
|
||||||
|
|
||||||
if(!outbytes)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* There was an error with one character but some other remain
|
|
||||||
* to be converted. That's probably a multibyte character.
|
|
||||||
* See above comment. */
|
|
||||||
src += sizeof(wchar_t);
|
|
||||||
inbytes -= sizeof(wchar_t);
|
|
||||||
|
|
||||||
if(!inbytes)
|
|
||||||
break;
|
|
||||||
|
|
||||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
iconv_close(conv);
|
|
||||||
|
|
||||||
/* close the ucs string */
|
|
||||||
*((uint16_t*) ret) = 0;
|
|
||||||
|
|
||||||
return (uint16_t*)ret_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int valid_d_char(char c)
|
|
||||||
{
|
|
||||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int valid_a_char(char c)
|
|
||||||
{
|
|
||||||
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?')
|
|
||||||
|| (c >= 'A' && c <= 'Z')
|
|
||||||
|| (c == '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int valid_j_char(uint16_t c)
|
|
||||||
{
|
|
||||||
return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/'
|
|
||||||
|| c == (uint16_t)':' || c == (uint16_t)';'
|
|
||||||
|| c == (uint16_t)'?' || c == (uint16_t)'\\');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: where are these documented? */
|
|
||||||
static int valid_p_char(char c)
|
|
||||||
{
|
|
||||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
|
|
||||||
|| (c >= 'a' && c <= 'z')
|
|
||||||
|| (c == '.') || (c == '_') || (c == '-');
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *iso_dirid(const char *src, int size)
|
|
||||||
{
|
|
||||||
char *ret = str2ascii(src);
|
|
||||||
size_t len, i;
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
len = strlen(ret);
|
|
||||||
if (len > size) {
|
|
||||||
ret[size] = '\0';
|
|
||||||
len = size;
|
|
||||||
}
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
char c = toupper(ret[i]);
|
|
||||||
ret[i] = valid_d_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_1_dirid(const char *src)
|
|
||||||
{
|
|
||||||
return iso_dirid(src, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_2_dirid(const char *src)
|
|
||||||
{
|
|
||||||
return iso_dirid(src, 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_1_fileid(const char *src_arg)
|
|
||||||
{
|
|
||||||
char *src = str2ascii(src_arg);
|
|
||||||
char *dest;
|
|
||||||
char *dot; /* Position of the last dot in the
|
|
||||||
filename, will be used to calculate
|
|
||||||
lname and lext. */
|
|
||||||
int lname, lext, pos, i;
|
|
||||||
|
|
||||||
if (!src)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2
|
|
||||||
(;1) + 1 (\0) */
|
|
||||||
dot = strrchr(src, '.');
|
|
||||||
|
|
||||||
lext = dot ? strlen(dot + 1) : 0;
|
|
||||||
lname = strlen(src) - lext - (dot ? 1 : 0);
|
|
||||||
|
|
||||||
/* If we can't build a filename, return NULL. */
|
|
||||||
if (lname == 0 && lext == 0) {
|
|
||||||
free(src);
|
|
||||||
free(dest);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
/* Convert up to 8 characters of the filename. */
|
|
||||||
for (i = 0; i < lname && i < 8; i++) {
|
|
||||||
char c = toupper(src[i]);
|
|
||||||
|
|
||||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
/* This dot is mandatory, even if there is no extension. */
|
|
||||||
dest[pos++] = '.';
|
|
||||||
/* Convert up to 3 characters of the extension, if any. */
|
|
||||||
for (i = 0; i < lext && i < 3; i++) {
|
|
||||||
char c = toupper(src[lname + 1 + i]);
|
|
||||||
|
|
||||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
/* File versions are mandatory, even if they aren't used. */
|
|
||||||
dest[pos++] = ';';
|
|
||||||
dest[pos++] = '1';
|
|
||||||
dest[pos] = '\0';
|
|
||||||
dest = (char *)realloc(dest, pos + 1);
|
|
||||||
|
|
||||||
free(src);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_2_fileid(const char *src_arg)
|
|
||||||
{
|
|
||||||
char *src = str2ascii(src_arg);
|
|
||||||
char *dest;
|
|
||||||
char *dot;
|
|
||||||
int lname, lext, lnname, lnext, pos, i;
|
|
||||||
|
|
||||||
if (!src)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2
|
|
||||||
(;1) + 1 (\0) */
|
|
||||||
dot = strrchr(src, '.');
|
|
||||||
|
|
||||||
/* Since the maximum length can be divided freely over the name and
|
|
||||||
extension, we need to calculate their new lengths (lnname and
|
|
||||||
lnext). If the original filename is too long, we start by trimming
|
|
||||||
the extension, but keep a minimum extension length of 3. */
|
|
||||||
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
|
|
||||||
lname = strlen(src);
|
|
||||||
lnname = (lname > 30) ? 30 : lname;
|
|
||||||
lext = lnext = 0;
|
|
||||||
} else {
|
|
||||||
lext = strlen(dot + 1);
|
|
||||||
lname = strlen(src) - lext - 1;
|
|
||||||
lnext = (strlen(src) > 31 && lext > 3)
|
|
||||||
? (lname < 27 ? 30 - lname : 3) : lext;
|
|
||||||
lnname = (strlen(src) > 31) ? 30 - lnext : lname;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lnname == 0 && lnext == 0) {
|
|
||||||
free(src);
|
|
||||||
free(dest);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
/* Convert up to lnname characters of the filename. */
|
|
||||||
for (i = 0; i < lnname; i++) {
|
|
||||||
char c = toupper(src[i]);
|
|
||||||
|
|
||||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
dest[pos++] = '.';
|
|
||||||
/* Convert up to lnext characters of the extension, if any. */
|
|
||||||
for (i = 0; i < lnext; i++) {
|
|
||||||
char c = toupper(src[lname + 1 + i]);
|
|
||||||
|
|
||||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
dest[pos++] = ';';
|
|
||||||
dest[pos++] = '1';
|
|
||||||
dest[pos] = '\0';
|
|
||||||
dest = (char *)realloc(dest, pos + 1);
|
|
||||||
|
|
||||||
free(src);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
iso_p_fileid(const char *src)
|
|
||||||
{
|
|
||||||
char *ret = str2ascii(src);
|
|
||||||
size_t i, len;
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
return NULL;
|
|
||||||
len = strlen(ret);
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if (!valid_p_char(ret[i])) {
|
|
||||||
ret[i] = (uint16_t)'_';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t *
|
|
||||||
iso_j_id(const char *src_arg)
|
|
||||||
{
|
|
||||||
uint16_t *j_str = str2ucs(src_arg);
|
|
||||||
size_t len = ucslen(j_str);
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (len > 128) {
|
|
||||||
j_str[128] = '\0';
|
|
||||||
len = 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = 0; n < len; n++)
|
|
||||||
if (!valid_j_char(j_str[n]))
|
|
||||||
j_str[n] = '_';
|
|
||||||
return j_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
assert(bytes <= 4);
|
|
||||||
|
|
||||||
for (i = 0; i < bytes; ++i)
|
|
||||||
buf[i] = (num >> (8 * i)) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_msb(uint8_t *buf, uint32_t num, int bytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
assert(bytes <= 4);
|
|
||||||
|
|
||||||
for (i = 0; i < bytes; ++i)
|
|
||||||
buf[bytes - 1 - i] = (num >> (8 * i)) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_bb(uint8_t *buf, uint32_t num, int bytes)
|
|
||||||
{
|
|
||||||
iso_lsb(buf, num, bytes);
|
|
||||||
iso_msb(buf+bytes, num, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void iso_datetime_7(unsigned char *buf, time_t t)
|
|
||||||
{
|
|
||||||
static int tzsetup = 0;
|
|
||||||
int tzoffset;
|
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
if (!tzsetup) {
|
|
||||||
tzset();
|
|
||||||
tzsetup = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
localtime_r(&t, &tm);
|
|
||||||
|
|
||||||
buf[0] = tm.tm_year;
|
|
||||||
buf[1] = tm.tm_mon + 1;
|
|
||||||
buf[2] = tm.tm_mday;
|
|
||||||
buf[3] = tm.tm_hour;
|
|
||||||
buf[4] = tm.tm_min;
|
|
||||||
buf[5] = tm.tm_sec;
|
|
||||||
#ifdef HAVE_TM_GMTOFF
|
|
||||||
tzoffset = -tm.tm_gmtoff / 60 / 15;
|
|
||||||
#else
|
|
||||||
tzoffset = -timezone / 60 / 15;
|
|
||||||
#endif
|
|
||||||
if (tzoffset < -48)
|
|
||||||
tzoffset += 101;
|
|
||||||
buf[6] = tzoffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t iso_datetime_read_7(const uint8_t *buf)
|
|
||||||
{
|
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
tm.tm_year = buf[0];
|
|
||||||
tm.tm_mon = buf[1] + 1;
|
|
||||||
tm.tm_mday = buf[2];
|
|
||||||
tm.tm_hour = buf[3];
|
|
||||||
tm.tm_min = buf[4];
|
|
||||||
tm.tm_sec = buf[5];
|
|
||||||
|
|
||||||
return mktime(&tm) - buf[6] * 60 * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_datetime_17(unsigned char *buf, time_t t)
|
|
||||||
{
|
|
||||||
static int tzsetup = 0;
|
|
||||||
static int tzoffset;
|
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
if (t == (time_t) - 1) {
|
|
||||||
/* unspecified time */
|
|
||||||
memset(buf, '0', 16);
|
|
||||||
buf[16] = 0;
|
|
||||||
} else {
|
|
||||||
if (!tzsetup) {
|
|
||||||
tzset();
|
|
||||||
tzsetup = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
localtime_r(&t, &tm);
|
|
||||||
|
|
||||||
sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
|
|
||||||
sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
|
|
||||||
sprintf((char*)&buf[6], "%02d", tm.tm_mday);
|
|
||||||
sprintf((char*)&buf[8], "%02d", tm.tm_hour);
|
|
||||||
sprintf((char*)&buf[10], "%02d", tm.tm_min);
|
|
||||||
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
|
|
||||||
memcpy(&buf[14], "00", 2);
|
|
||||||
#ifdef HAVE_TM_GMTOFF
|
|
||||||
tzoffset = -tm.tm_gmtoff / 60 / 15;
|
|
||||||
#else
|
|
||||||
tzoffset = -timezone / 60 / 15;
|
|
||||||
#endif
|
|
||||||
if (tzoffset < -48)
|
|
||||||
tzoffset += 101;
|
|
||||||
buf[16] = tzoffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t iso_datetime_read_17(const uint8_t *buf)
|
|
||||||
{
|
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
sscanf((char*)&buf[0], "%4d", &tm.tm_year);
|
|
||||||
sscanf((char*)&buf[4], "%2d", &tm.tm_mon);
|
|
||||||
sscanf((char*)&buf[6], "%2d", &tm.tm_mday);
|
|
||||||
sscanf((char*)&buf[8], "%2d", &tm.tm_hour);
|
|
||||||
sscanf((char*)&buf[10], "%2d", &tm.tm_min);
|
|
||||||
sscanf((char*)&buf[12], "%2d", &tm.tm_sec);
|
|
||||||
tm.tm_year -= 1900;
|
|
||||||
tm.tm_mon -= 1;
|
|
||||||
|
|
||||||
return mktime(&tm) - buf[16] * 60 * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ucslen(const uint16_t *str)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; str[i]; i++)
|
|
||||||
;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Although each character is 2 bytes, we actually compare byte-by-byte
|
|
||||||
* (thats what the spec says).
|
|
||||||
*/
|
|
||||||
int ucscmp(const uint16_t *s1, const uint16_t *s2)
|
|
||||||
{
|
|
||||||
const char *s = (const char*)s1;
|
|
||||||
const char *t = (const char*)s2;
|
|
||||||
size_t len1 = ucslen(s1);
|
|
||||||
size_t len2 = ucslen(s2);
|
|
||||||
size_t i, len = MIN(len1, len2) * 2;
|
|
||||||
|
|
||||||
for (i=0; i < len; i++) {
|
|
||||||
if (s[i] < t[i]) {
|
|
||||||
return -1;
|
|
||||||
} else if (s[i] > t[i]) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len1 < len2)
|
|
||||||
return -1;
|
|
||||||
else if (len1 > len2)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint32_t ret = 0;
|
|
||||||
|
|
||||||
for (i=0; i<bytes; i++) {
|
|
||||||
ret += ((uint32_t) buf[i]) << (i*8);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t iso_read_msb(const uint8_t *buf, int bytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint32_t ret = 0;
|
|
||||||
|
|
||||||
for (i=0; i<bytes; i++) {
|
|
||||||
ret += ((uint32_t) buf[bytes-i-1]) << (i*8);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t iso_read_bb(const uint8_t *buf, int bytes)
|
|
||||||
{
|
|
||||||
uint32_t v1 = iso_read_lsb(buf, bytes);
|
|
||||||
uint32_t v2 = iso_read_msb(buf+bytes, bytes);
|
|
||||||
|
|
||||||
assert(v1 == v2);
|
|
||||||
return v1;
|
|
||||||
}
|
|
@ -1,121 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility functions for the Libisofs library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBISO_UTIL_H
|
|
||||||
#define LIBISO_UTIL_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
|
|
||||||
#ifndef MAX
|
|
||||||
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern inline int div_up(int n, int div)
|
|
||||||
{
|
|
||||||
return (n + div - 1) / div;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern inline int round_up(int n, int mul)
|
|
||||||
{
|
|
||||||
return div_up(n, mul) * mul;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t *towcs(const char *);
|
|
||||||
char *str2ascii(const char*);
|
|
||||||
uint16_t *str2ucs(const char*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a level 1 directory identifier.
|
|
||||||
*/
|
|
||||||
char *iso_1_dirid(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a level 2 directory identifier.
|
|
||||||
*/
|
|
||||||
char *iso_2_dirid(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a level 1 file identifier that consists of a name, extension and
|
|
||||||
* version number. The resulting string will have a file name of maximum
|
|
||||||
* length 8, followed by a separator (.), an optional extension of maximum
|
|
||||||
* length 3, followed by a separator (;) and a version number (digit 1).
|
|
||||||
* @return NULL if the original name and extension both are of length 0.
|
|
||||||
*/
|
|
||||||
char *iso_1_fileid(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a level 2 file identifier that consists of a name, extension and
|
|
||||||
* version number. The combined file name and extension length will not exceed
|
|
||||||
* 30, the name and extension will be separated (.), and the extension will be
|
|
||||||
* followed by a separator (;) and a version number (digit 1).
|
|
||||||
* @return NULL if the original name and extension both are of length 0.
|
|
||||||
*/
|
|
||||||
char *iso_2_fileid(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Joliet file or directory identifier that consists of a name,
|
|
||||||
* extension and version number. The combined name and extension length will
|
|
||||||
* not exceed 128 bytes, the name and extension will be separated (.),
|
|
||||||
* and the extension will be followed by a separator (;) and a version number
|
|
||||||
* (digit 1). All characters consist of 2 bytes and the resulting string is
|
|
||||||
* NULL-terminated by a 2-byte NULL. Requires the locale to be set correctly.
|
|
||||||
*
|
|
||||||
* @param size will be set to the size (in bytes) of the identifier.
|
|
||||||
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
|
|
||||||
*/
|
|
||||||
uint16_t *iso_j_id(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FIXME: what are the requirements for these next two? Is this for RR?
|
|
||||||
*
|
|
||||||
* Create a POSIX portable file name that consists of a name and extension.
|
|
||||||
* The resulting file name will not exceed 250 characters.
|
|
||||||
* @return NULL if the original name and extension both are of length 0.
|
|
||||||
*/
|
|
||||||
char *iso_p_fileid(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a POSIX portable directory name.
|
|
||||||
* The resulting directory name will not exceed 250 characters.
|
|
||||||
* @return NULL if the original name is of length 0.
|
|
||||||
*/
|
|
||||||
char *iso_p_dirid(const char *src);
|
|
||||||
|
|
||||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
|
|
||||||
void iso_msb(uint8_t *buf, uint32_t num, int bytes);
|
|
||||||
void iso_bb(uint8_t *buf, uint32_t num, int bytes);
|
|
||||||
|
|
||||||
uint32_t iso_read_lsb(const uint8_t *buf, int bytes);
|
|
||||||
uint32_t iso_read_msb(const uint8_t *buf, int bytes);
|
|
||||||
uint32_t iso_read_bb(const uint8_t *buf, int bytes);
|
|
||||||
|
|
||||||
/** Records the date/time into a 7 byte buffer (9.1.5) */
|
|
||||||
void iso_datetime_7(uint8_t *buf, time_t t);
|
|
||||||
|
|
||||||
/** Records the date/time into a 17 byte buffer (8.4.26.1) */
|
|
||||||
void iso_datetime_17(uint8_t *buf, time_t t);
|
|
||||||
|
|
||||||
time_t iso_datetime_read_7(const uint8_t *buf);
|
|
||||||
time_t iso_datetime_read_17(const uint8_t *buf);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Like strlen, but for Joliet strings.
|
|
||||||
*/
|
|
||||||
size_t ucslen(const uint16_t *str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Like strcmp, but for Joliet strings.
|
|
||||||
*/
|
|
||||||
int ucscmp(const uint16_t *s1, const uint16_t *s2);
|
|
||||||
|
|
||||||
#endif /* LIBISO_UTIL_H */
|
|
@ -1,189 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set ts=8 sts=8 sw=8 noet : */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include "libisofs.h"
|
|
||||||
#include "tree.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "volume.h"
|
|
||||||
|
|
||||||
struct iso_volset*
|
|
||||||
iso_volset_new(struct iso_volume *vol, const char *id)
|
|
||||||
{
|
|
||||||
struct iso_volset *volset = calloc(1, sizeof(struct iso_volset));
|
|
||||||
|
|
||||||
volset->volset_size = 1;
|
|
||||||
volset->refcount = 1;
|
|
||||||
volset->volume = malloc(sizeof(void *));
|
|
||||||
volset->volume[0] = vol;
|
|
||||||
volset->volset_id = strdup(id);
|
|
||||||
|
|
||||||
vol->refcount++;
|
|
||||||
return volset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_volset_free(struct iso_volset *volset)
|
|
||||||
{
|
|
||||||
if (--volset->refcount < 1) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < volset->volset_size; i++) {
|
|
||||||
iso_volume_free(volset->volume[i]);
|
|
||||||
}
|
|
||||||
free(volset->volume);
|
|
||||||
free(volset->volset_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_volume*
|
|
||||||
iso_volume_new(const char *volume_id,
|
|
||||||
const char *publisher_id,
|
|
||||||
const char *data_preparer_id)
|
|
||||||
{
|
|
||||||
return iso_volume_new_with_root(volume_id,
|
|
||||||
publisher_id,
|
|
||||||
data_preparer_id,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_volume*
|
|
||||||
iso_volume_new_with_root(const char *volume_id,
|
|
||||||
const char *publisher_id,
|
|
||||||
const char *data_preparer_id,
|
|
||||||
struct iso_tree_node *root)
|
|
||||||
{
|
|
||||||
struct iso_volume *volume;
|
|
||||||
|
|
||||||
volume = calloc(1, sizeof(struct iso_volume));
|
|
||||||
volume->refcount = 1;
|
|
||||||
|
|
||||||
volume->root = root ? root : iso_tree_new_root(volume);
|
|
||||||
|
|
||||||
if (volume_id != NULL)
|
|
||||||
volume->volume_id = strdup(volume_id);
|
|
||||||
if (publisher_id != NULL)
|
|
||||||
volume->publisher_id = strdup(publisher_id);
|
|
||||||
if (data_preparer_id != NULL)
|
|
||||||
volume->data_preparer_id = strdup(data_preparer_id);
|
|
||||||
return volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iso_volume_free(struct iso_volume *volume)
|
|
||||||
{
|
|
||||||
/* Only free if no references are in use. */
|
|
||||||
if (--volume->refcount < 1) {
|
|
||||||
iso_tree_free(volume->root);
|
|
||||||
|
|
||||||
free(volume->volume_id);
|
|
||||||
free(volume->publisher_id);
|
|
||||||
free(volume->data_preparer_id);
|
|
||||||
|
|
||||||
free(volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node *
|
|
||||||
iso_volume_get_root(const struct iso_volume *volume)
|
|
||||||
{
|
|
||||||
return volume->root;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node *
|
|
||||||
iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
|
|
||||||
{
|
|
||||||
struct iso_tree_node *node;
|
|
||||||
char *ptr, *brk_info, *component;
|
|
||||||
|
|
||||||
/* get the first child at the root of the volume
|
|
||||||
* that is "/" */
|
|
||||||
node=iso_volume_get_root(volume);
|
|
||||||
if (!strcmp (path, "/"))
|
|
||||||
return node;
|
|
||||||
|
|
||||||
if (!node->nchildren)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* the name of the nodes is in wide characters so first convert path
|
|
||||||
* into wide characters. */
|
|
||||||
ptr = strdup(path);
|
|
||||||
|
|
||||||
/* get the first component of the path */
|
|
||||||
component=strtok_r(ptr, "/", &brk_info);
|
|
||||||
while (component) {
|
|
||||||
size_t max;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* search among all the children of this directory if this path component exists */
|
|
||||||
max=node->nchildren;
|
|
||||||
for (i=0; i < max; i++) {
|
|
||||||
if (!strcmp(component, node->children[i]->name)) {
|
|
||||||
node=node->children[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see if a node could be found */
|
|
||||||
if (i==max) {
|
|
||||||
node=NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
component=strtok_r(NULL, "/", &brk_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ptr);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node *
|
|
||||||
iso_tree_volume_add_path(struct iso_volume *volume,
|
|
||||||
const char *disc_path,
|
|
||||||
const char *path)
|
|
||||||
{
|
|
||||||
char *tmp;
|
|
||||||
struct iso_tree_node *node;
|
|
||||||
struct iso_tree_node *parent_node;
|
|
||||||
|
|
||||||
tmp=strdup(disc_path);
|
|
||||||
parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
if (!parent_node)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
node = iso_tree_radd_dir(parent_node, path);
|
|
||||||
if (!node)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
tmp=strdup(disc_path);
|
|
||||||
iso_tree_node_set_name(node, basename(tmp));
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_node *
|
|
||||||
iso_tree_volume_add_new_dir(struct iso_volume *volume,
|
|
||||||
const char *disc_path)
|
|
||||||
{
|
|
||||||
char *tmp;
|
|
||||||
struct iso_tree_node *node;
|
|
||||||
struct iso_tree_node *parent_node;
|
|
||||||
|
|
||||||
tmp=strdup(disc_path);
|
|
||||||
parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
if (!parent_node)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
tmp=strdup(disc_path);
|
|
||||||
node = iso_tree_add_new_dir(parent_node, basename(tmp));
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set noet sts=8 ts=8 sw=8 : */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra declarations for use with the iso_volume structure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBISO_VOLUME_H
|
|
||||||
#define LIBISO_VOLUME_H
|
|
||||||
|
|
||||||
#include "libisofs.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data volume.
|
|
||||||
*/
|
|
||||||
struct iso_volume
|
|
||||||
{
|
|
||||||
int refcount; /**< Number of used references to this
|
|
||||||
volume. */
|
|
||||||
|
|
||||||
struct iso_tree_node *root; /**< Root of the directory tree for the
|
|
||||||
volume. */
|
|
||||||
|
|
||||||
char *volume_id; /**< Volume identifier. */
|
|
||||||
char *publisher_id; /**< Volume publisher. */
|
|
||||||
char *data_preparer_id; /**< Volume data preparer. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of data volumes.
|
|
||||||
*/
|
|
||||||
struct iso_volset
|
|
||||||
{
|
|
||||||
int refcount;
|
|
||||||
|
|
||||||
struct iso_volume **volume; /**< The volumes belonging to this
|
|
||||||
volume set. */
|
|
||||||
int volset_size; /**< The number of volumes in this
|
|
||||||
volume set. */
|
|
||||||
|
|
||||||
char *volset_id; /**< The id of this volume set, encoded
|
|
||||||
in the current locale. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __ISO_VOLUME */
|
|
@ -1,107 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
/* vim: set ts=8 sts=8 sw=8 noet : */
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
|
|
||||||
#include "libisofs.h"
|
|
||||||
#include "libburn/libburn.h"
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <err.h>
|
|
||||||
|
|
||||||
#define SECSIZE 2048
|
|
||||||
|
|
||||||
const char * const optstring = "JRL:h";
|
|
||||||
extern char *optarg;
|
|
||||||
extern int optind;
|
|
||||||
|
|
||||||
void usage()
|
|
||||||
{
|
|
||||||
printf("test [OPTIONS] DIRECTORY OUTPUT\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void help()
|
|
||||||
{
|
|
||||||
printf(
|
|
||||||
"Options:\n"
|
|
||||||
" -J Add Joliet support\n"
|
|
||||||
" -R Add Rock Ridge support\n"
|
|
||||||
" -L <num> Set the ISO level (1 or 2)\n"
|
|
||||||
" -h Print this message\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
struct iso_volset *volset;
|
|
||||||
struct iso_volume *volume;
|
|
||||||
struct iso_tree_node *root;
|
|
||||||
struct burn_source *src;
|
|
||||||
unsigned char buf[2048];
|
|
||||||
FILE *fd;
|
|
||||||
int c;
|
|
||||||
int level=1, flags=0;
|
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, optstring)) != -1) {
|
|
||||||
switch(c) {
|
|
||||||
case 'h':
|
|
||||||
usage();
|
|
||||||
help();
|
|
||||||
exit(0);
|
|
||||||
break;
|
|
||||||
case 'J':
|
|
||||||
flags |= ECMA119_JOLIET;
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
flags |= ECMA119_ROCKRIDGE;
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
level = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
usage();
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
printf ("must pass directory to build iso from\n");
|
|
||||||
usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (argc < 3) {
|
|
||||||
printf ("must supply output file\n");
|
|
||||||
usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
fd = fopen(argv[optind+1], "w");
|
|
||||||
if (!fd) {
|
|
||||||
err(1, "error opening output file");
|
|
||||||
}
|
|
||||||
|
|
||||||
root = iso_tree_radd_dir(NULL, argv[optind]);
|
|
||||||
if (!root) {
|
|
||||||
err(1, "error opening input directory");
|
|
||||||
}
|
|
||||||
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
|
|
||||||
volset = iso_volset_new( volume, "VOLSETID" );
|
|
||||||
|
|
||||||
src = iso_source_new_ecma119(volset, 0, level, flags);
|
|
||||||
|
|
||||||
while (src->read(src, buf, 2048) == 2048) {
|
|
||||||
fwrite(buf, 1, 2048, fd);
|
|
||||||
}
|
|
||||||
fclose(fd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,297 +0,0 @@
|
|||||||
|
|
||||||
import struct
|
|
||||||
import tree
|
|
||||||
import sys
|
|
||||||
|
|
||||||
voldesc_fmt = "B" "5s" "B" "2041x"
|
|
||||||
|
|
||||||
# all these fields are common between the pri and sec voldescs
|
|
||||||
privoldesc_fmt = "B" "5s" "B" "x" "32s" "32s" "8x" "8s" "32x" "4s" "4s" "4s" "8s" "4s4s" "4s4s" "34s" "128s" \
|
|
||||||
"128s" "128s" "128s" "37s" "37s" "37s" "17s" "17s" "17s" "17s" "B" "x" "512s" "653x"
|
|
||||||
|
|
||||||
# the fields unique to the sec_vol_desc
|
|
||||||
secvoldesc_fmt = "x" "5x" "x" "B" "32x" "32x" "8x" "8x" "32s" "4x" "4x" "4x" "8x" "4x4x" "4x4x" "34x" "128x" \
|
|
||||||
"128x" "128x" "128x" "37x" "37x" "37x" "17x" "17x" "17x" "17x" "x" "x" "512x" "653x"
|
|
||||||
|
|
||||||
dirrecord_fmt = "B" "B" "8s" "8s" "7s" "B" "B" "B" "4s" "B" # + file identifier, padding field and SU area
|
|
||||||
|
|
||||||
pathrecord_fmt = "B" "B" "4s" "2s" # + directory identifier and padding field
|
|
||||||
|
|
||||||
def read_bb(str, le, be):
|
|
||||||
val1, = struct.unpack(le, str)
|
|
||||||
val2, = struct.unpack(be, str)
|
|
||||||
if val1 != val2:
|
|
||||||
print "val1=%d, val2=%d" % (val1, val2)
|
|
||||||
raise AssertionError, "values are not equal in dual byte-order field"
|
|
||||||
return val1
|
|
||||||
|
|
||||||
def read_bb4(str):
|
|
||||||
return read_bb(str, "<I4x", ">4xI")
|
|
||||||
|
|
||||||
def read_bb2(str):
|
|
||||||
return read_bb(str, "<H2x", ">2xH")
|
|
||||||
|
|
||||||
def read_lsb4(str):
|
|
||||||
return struct.unpack("<I", str)[0]
|
|
||||||
|
|
||||||
def read_lsb2(str):
|
|
||||||
return struct.unpack("<H", str)[0]
|
|
||||||
|
|
||||||
def read_msb4(str):
|
|
||||||
return struct.unpack(">I", str)[0]
|
|
||||||
|
|
||||||
def read_msb2(str):
|
|
||||||
return struct.unpack(">H", str)[0]
|
|
||||||
|
|
||||||
class VolDesc(object):
|
|
||||||
def __init__(self, data):
|
|
||||||
print "fmt len=%d, data len=%d" % ( struct.calcsize(voldesc_fmt), len(data) )
|
|
||||||
self.vol_desc_type, self.standard_id, self.vol_desc_version = struct.unpack(voldesc_fmt, data)
|
|
||||||
|
|
||||||
class PriVolDesc(VolDesc):
|
|
||||||
def __init__(self, data):
|
|
||||||
self.vol_desc_type, \
|
|
||||||
self.standard_id, \
|
|
||||||
self.vol_desc_version, \
|
|
||||||
self.system_id, \
|
|
||||||
self.volume_id, \
|
|
||||||
self.vol_space_size, \
|
|
||||||
self.vol_set_size, \
|
|
||||||
self.vol_seq_num, \
|
|
||||||
self.block_size, \
|
|
||||||
self.path_table_size, \
|
|
||||||
self.l_table_pos, \
|
|
||||||
self.l_table2_pos, \
|
|
||||||
self.m_table_pos, \
|
|
||||||
self.m_table2_pos, \
|
|
||||||
self.root_record, \
|
|
||||||
self.volset_id, \
|
|
||||||
self.publisher_id, \
|
|
||||||
self.preparer_id, \
|
|
||||||
self.application_id, \
|
|
||||||
self.copyright_file, \
|
|
||||||
self.abstract_file, \
|
|
||||||
self.bibliographic_file, \
|
|
||||||
self.creation_timestamp, \
|
|
||||||
self.modification_timestamp, \
|
|
||||||
self.expiration_timestamp, \
|
|
||||||
self.effective_timestamp, \
|
|
||||||
self.file_struct_version, \
|
|
||||||
self.application_use = struct.unpack(privoldesc_fmt, data)
|
|
||||||
|
|
||||||
# take care of reading the integer types
|
|
||||||
self.vol_space_size = read_bb4(self.vol_space_size)
|
|
||||||
self.vol_set_size = read_bb2(self.vol_set_size)
|
|
||||||
self.vol_seq_num = read_bb2(self.vol_seq_num)
|
|
||||||
self.block_size = read_bb2(self.block_size)
|
|
||||||
self.path_table_size = read_bb4(self.path_table_size)
|
|
||||||
self.l_table_pos = read_lsb4(self.l_table_pos)
|
|
||||||
self.l_table2_pos = read_lsb4(self.l_table2_pos)
|
|
||||||
self.m_table_pos = read_msb4(self.m_table_pos)
|
|
||||||
self.m_table2_pos = read_msb4(self.m_table2_pos)
|
|
||||||
|
|
||||||
# parse the root directory record
|
|
||||||
self.root_record = DirRecord(self.root_record)
|
|
||||||
|
|
||||||
def readPathTables(self, file):
|
|
||||||
file.seek( self.block_size * self.l_table_pos )
|
|
||||||
self.l_table = PathTable( file.read(self.path_table_size), 0 )
|
|
||||||
file.seek( self.block_size * self.m_table_pos )
|
|
||||||
self.m_table = PathTable( file.read(self.path_table_size), 1 )
|
|
||||||
|
|
||||||
if self.l_table2_pos:
|
|
||||||
file.seek( self.block_size * self.l_table2_pos )
|
|
||||||
self.l_table2 = PathTable( file.read(self.path_table_size), 0 )
|
|
||||||
else:
|
|
||||||
self.l_table2 = None
|
|
||||||
|
|
||||||
if self.m_table2_pos:
|
|
||||||
file.seek( self.block_size * self.m_table2_pos )
|
|
||||||
self.m_table2 = PathTable( file.read(self.path_table_size), 1 )
|
|
||||||
else:
|
|
||||||
self.m_table2 = None
|
|
||||||
|
|
||||||
def toTree(self, isofile):
|
|
||||||
ret = tree.Tree(isofile=isofile.name)
|
|
||||||
ret.root = self.root_record.toTreeNode(parent=None, isofile=isofile)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
class SecVolDesc(PriVolDesc):
|
|
||||||
def __init__(self, data):
|
|
||||||
super(SecVolDesc,self).__init__(data)
|
|
||||||
self.flags, self.escape_sequences = struct.unpack(secvoldesc_fmt, data)
|
|
||||||
|
|
||||||
# return a single volume descriptor of the appropriate type
|
|
||||||
def readVolDesc(data):
|
|
||||||
desc = VolDesc(data)
|
|
||||||
if desc.standard_id != "CD001":
|
|
||||||
print "Unexpected standard_id " +desc.standard_id
|
|
||||||
return None
|
|
||||||
if desc.vol_desc_type == 1:
|
|
||||||
return PriVolDesc(data)
|
|
||||||
elif desc.vol_desc_type == 2:
|
|
||||||
return SecVolDesc(data)
|
|
||||||
elif desc.vol_desc_type == 3:
|
|
||||||
print "I don't know about partitions yet!"
|
|
||||||
return None
|
|
||||||
elif desc.vol_desc_type == 255:
|
|
||||||
return desc
|
|
||||||
else:
|
|
||||||
print "Unknown volume descriptor type %d" % (desc.vol_desc_type,)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def readVolDescSet(file):
|
|
||||||
ret = [ readVolDesc(file.read(2048)) ]
|
|
||||||
while ret[-1].vol_desc_type != 255:
|
|
||||||
ret.append( readVolDesc(file.read(2048)) )
|
|
||||||
|
|
||||||
for vol in ret:
|
|
||||||
if vol.vol_desc_type == 1 or vol.vol_desc_type == 2:
|
|
||||||
vol.readPathTables(file)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
class DirRecord:
|
|
||||||
def __init__(self, data):
|
|
||||||
self.len_dr, \
|
|
||||||
self.len_xa, \
|
|
||||||
self.block, \
|
|
||||||
self.len_data, \
|
|
||||||
self.timestamp, \
|
|
||||||
self.flags, \
|
|
||||||
self.unit_size, \
|
|
||||||
self.gap_size, \
|
|
||||||
self.vol_seq_number, \
|
|
||||||
self.len_fi = struct.unpack(dirrecord_fmt, data[:33])
|
|
||||||
self.children = []
|
|
||||||
|
|
||||||
if self.len_dr > len(data):
|
|
||||||
raise AssertionError, "Error: not enough data to read in DirRecord()"
|
|
||||||
elif self.len_dr < 34:
|
|
||||||
raise AssertionError, "Error: directory record too short"
|
|
||||||
|
|
||||||
fmt = str(self.len_fi) + "s"
|
|
||||||
if self.len_fi % 2 == 0:
|
|
||||||
fmt += "1x"
|
|
||||||
len_su = self.len_dr - (33 + self.len_fi + 1 - (self.len_fi % 2))
|
|
||||||
fmt += str(len_su) + "s"
|
|
||||||
|
|
||||||
if len(data) >= self.len_dr:
|
|
||||||
self.file_id, self.su = struct.unpack(fmt, data[33 : self.len_dr])
|
|
||||||
else:
|
|
||||||
print "Error: couldn't read file_id: not enough data"
|
|
||||||
self.file_id = "BLANK"
|
|
||||||
self.su = ""
|
|
||||||
|
|
||||||
# convert to integers
|
|
||||||
self.block = read_bb4(self.block)
|
|
||||||
self.len_data = read_bb4(self.len_data)
|
|
||||||
self.vol_seq_number = read_bb2(self.vol_seq_number)
|
|
||||||
|
|
||||||
def toTreeNode(self, parent, isofile, path=""):
|
|
||||||
ret = tree.TreeNode(parent=parent, isofile=isofile.name)
|
|
||||||
if len(path) > 0:
|
|
||||||
path += "/"
|
|
||||||
path += self.file_id
|
|
||||||
ret.path = path
|
|
||||||
|
|
||||||
if self.flags & 2: # we are a directory, recurse
|
|
||||||
isofile.seek( 2048 * self.block )
|
|
||||||
data = isofile.read( self.len_data )
|
|
||||||
pos = 0
|
|
||||||
while pos < self.len_data:
|
|
||||||
try:
|
|
||||||
child = DirRecord( data[pos:] )
|
|
||||||
pos += child.len_dr
|
|
||||||
if child.len_fi == 1 and (child.file_id == "\x00" or child.file_id == "\x01"):
|
|
||||||
continue
|
|
||||||
print "read child named " +child.file_id
|
|
||||||
self.children.append( child )
|
|
||||||
ret.children.append( child.toTreeNode(ret, isofile, path) )
|
|
||||||
except AssertionError:
|
|
||||||
print "Couldn't read child of directory %s, position is %d, len is %d" % \
|
|
||||||
(path, pos, self.len_data)
|
|
||||||
raise
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
class PathTableRecord:
|
|
||||||
def __init__(self, data, readint2, readint4):
|
|
||||||
self.len_di, self.len_xa, self.block, self.parent_number = struct.unpack(pathrecord_fmt, data[:8])
|
|
||||||
|
|
||||||
if len(data) < self.len_di + 8:
|
|
||||||
raise AssertionError, "Error: not enough data to read path table record"
|
|
||||||
|
|
||||||
fmt = str(self.len_di) + "s"
|
|
||||||
self.dir_id, = struct.unpack(fmt, data[8:8+self.len_di])
|
|
||||||
|
|
||||||
self.block = readint4(self.block)
|
|
||||||
self.parent_number = readint2(self.parent_number)
|
|
||||||
|
|
||||||
class PathTable:
|
|
||||||
def __init__(self, data, m_type):
|
|
||||||
if m_type:
|
|
||||||
readint2 = read_msb2
|
|
||||||
readint4 = read_msb4
|
|
||||||
else:
|
|
||||||
readint2 = read_lsb2
|
|
||||||
readint4 = read_lsb4
|
|
||||||
pos = 0
|
|
||||||
self.records = []
|
|
||||||
while pos < len(data):
|
|
||||||
try:
|
|
||||||
self.records.append( PathTableRecord(data[pos:], readint2, readint4) )
|
|
||||||
print "Read path record %d: dir_id %s, block %d, parent_number %d" %\
|
|
||||||
(len(self.records), self.records[-1].dir_id, self.records[-1].block, self.records[-1].parent_number)
|
|
||||||
pos += self.records[-1].len_di + 8
|
|
||||||
pos += pos % 2
|
|
||||||
except AssertionError:
|
|
||||||
print "Last successfully read path table record had dir_id %s, block %d, parent_number %d" % \
|
|
||||||
(self.records[-1].dir_id, self.records[-1].block, self.records[-1].parent_number)
|
|
||||||
print "Error was near offset %x" % (pos,)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def findRecord(self, dir_id, block, parent_number):
|
|
||||||
number=1
|
|
||||||
for record in self.records:
|
|
||||||
if record.dir_id == dir_id and record.block == block and record.parent_number == parent_number:
|
|
||||||
return number, record
|
|
||||||
number += 1
|
|
||||||
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
# check this path table for consistency against the actual directory heirarchy
|
|
||||||
def crossCheckDirRecords(self, root, parent_number=1):
|
|
||||||
number, rec = self.findRecord(root.file_id, root.block, parent_number)
|
|
||||||
|
|
||||||
if not rec:
|
|
||||||
print "Error: directory record parent_number %d, dir_id %s, block %d doesn't match a path table record" % \
|
|
||||||
(parent_number, root.file_id, root.block)
|
|
||||||
parent = self.records[parent_number]
|
|
||||||
print "Parent has parent_number %d, dir_id %s, block %d" % (parent.parent_number, parent.dir_id, parent.block)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
for child in root.children:
|
|
||||||
if child.flags & 2:
|
|
||||||
self.crossCheckDirRecords(child, number)
|
|
||||||
|
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print "Please enter the name of the .iso file to open"
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
f = file(sys.argv[1])
|
|
||||||
f.seek(2048 * 16) # system area
|
|
||||||
volumes = readVolDescSet(f)
|
|
||||||
vol = volumes[0]
|
|
||||||
t = vol.toTree(f)
|
|
||||||
vol.l_table.crossCheckDirRecords(vol.root_record)
|
|
||||||
vol.m_table.crossCheckDirRecords(vol.root_record)
|
|
||||||
|
|
||||||
vol = volumes[1]
|
|
||||||
try:
|
|
||||||
t = vol.toTree(f)
|
|
||||||
vol.l_table.crossCheckDirRecords(vol.root_record)
|
|
||||||
vol.m_table.crossCheckDirRecords(vol.root_record)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
Loading…
Reference in New Issue
Block a user