Compare commits

..

1 Commits

Author SHA1 Message Date
4108ddd995 Tagged 0.2.4 release 2007-01-03 20:37:40 +00:00
38 changed files with 819 additions and 4563 deletions

View File

@ -1,4 +1,2 @@
Joe Neeman
Philippe Rouquier
Suriyan Laohaprapanon
Vreixo Formoso Lopes

View File

@ -29,11 +29,7 @@ libisofs_libisofs_la_SOURCES = \
libisofs/exclude.c \
libisofs/exclude.h \
libisofs/hash.h \
libisofs/hash.c \
libisofs/file.h \
libisofs/file.c \
libisofs/eltorito.h \
libisofs/eltorito.c
libisofs/hash.c
libinclude_HEADERS = \
libisofs/libisofs.h
@ -48,23 +44,6 @@ test_iso_CPPFLAGS = -Ilibisofs
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_iso_SOURCES = test/iso.c
## Build unit test
check_PROGRAMS = \
test/test
test_test_CPPFLAGS = -Ilibisofs
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
test_test_LDFLAGS = -L.. -lm
test_test_SOURCES = \
test/test_exclude.c \
test/test_tree.c \
test/test_ecma119_tree.c \
test/test_file_hashtable.c \
test/test_util.c \
test/test_volume.c \
test/test.c
## ========================================================================= ##

53
README
View File

@ -6,7 +6,7 @@ This all is under GPL.
------------------------------------------------------------------------------
libburnia.pykix.org
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2006-2007 Mario Danic, Thomas Schmitt
Copyright (C) 2006 Mario Danic, Thomas Schmitt
Still containing parts of
Libburn. By Derek Foreman <derek@signalmarketing.com> and
@ -19,7 +19,7 @@ commitment as written at the end of this text.
The rights and merits of the Libburn-copyright holders Derek Foreman and
Ben Jansens will be duely respected.
This libburnia.pykix.org toplevel README (C) 2006-2007 Thomas Schmitt
This libburnia.pykix.org toplevel README (C) 2006 Thomas Schmitt
------------------------------------------------------------------------------
Build and Installation
@ -54,8 +54,7 @@ See README file there.
Overview of libburnia.pykix.org
libburnia.pykix.org is an open-source software project for reading, mastering
and writing optical discs.
For now this means only CD media and all single layer DVD media except DVD+R.
and writing optical discs. For now this means only CD-R and CD-RW.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
@ -67,10 +66,10 @@ we would need : login on a development machine resp. a live OS on CD or DVD,
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
volunteers for testing of realistic use cases.
We have a workable code base for burning CD and most single layer DVD.
The burn API is quite comprehensively documented and can be used to build a
presentable application.
We have a functional binary which emulates parts of cdrecord in order to
We do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
application.
We do have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburnia's scope
by help of existing cdrecord frontends.
@ -79,25 +78,20 @@ The project components (list subject to growth, hopefully):
- libburn is the library by which preformatted data get onto optical media.
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
/dev/hdX (e.g. on kernel 2.6).
libburn is the foundation of our cdrecord emulation. Its code is
independent of cdrecord. Its DVD capabilities are learned from
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
libburn is the foundation of our cdrecord emulation.
- libisofs is the library to pack up hard disk files and directories into a
ISO 9660 disk image. This may then be brought to media via libburn.
ISO 9660 disk image. This may then be brought to CD via libburn.
libisofs is to be the foundation of our upcoming mkisofs emulation.
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
Cdrecord is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for
the services traditionally provided by cdrecord. Additionally it
provides libburn's DVD capabilities, where only -sao is compatible
with cdrecord.
the services traditionally provided by cdrecord.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though.
See cdrskin/README and man cdrskin/cdrskin.1 for more.
See cdrskin/README for more.
- test is a collection of application gestures and examples given by the
authors of the library features. The main API example for libburn
@ -127,7 +121,7 @@ Project history as far as known to me:
It has meanwhile moved to use vanilla libburn.pykix.org , though.
Version 0.1.4 constitutes the first release of this kind.
- In July 2006 our team mate Mario Danic announced a revival of libburn
- In Juli 2006 our team mate Mario Danic announced a revival of libburn
which by about nearly everybody else was perceived as unfriendly fork.
Derek Foreman four days later posted a message which expressed his
discontent.
@ -184,32 +178,13 @@ Project history as far as known to me:
libburn, is now called libburnia. For the origin of this name, see
http://en.wikipedia.org/wiki/Liburnians .
- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
is widened to a first class of DVD media: overwriteable single layer types
DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
by dvd+rw-tools' "poor man" writing facility for this class of media.
Taking a bow towards Andy Polyakov.
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
multi-session and with DAO.
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
yet.
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
people that one should not use /dev/sg on kernel 2.6.
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
We look back on improved stability, a substantially extended list of media
and write modes, and better protection against typical user mishaps.
------------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation. To be exact: version 2 of that License.
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of

29
TODO
View File

@ -1,29 +0,0 @@
FEATURES
========
El-Torito
Support for multiple images
HFS/HFS+
CD reading
Multisession
UDF
ISO relaxed contraints
ISO 9660:1998
Support for special files (only dirs, reg. files and symlinks are supported).
TESTS
=====
For all
IMPLEMENTATION
==============
a way to return NULL sources meaning a failure!!
Error message queue
Public API for all things already implemented
Better charset support
default input charset to locale one, no always UTF-8

View File

@ -1,4 +1,4 @@
AC_INIT([libisofs], [0.2.8], [http://libburnia-project.org])
AC_INIT([libisofs], [0.2.4], [http://libburnia.pykix.org])
AC_PREREQ([2.50])
dnl AC_CONFIG_HEADER([config.h])
@ -25,7 +25,7 @@ dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
dnl
BURN_MAJOR_VERSION=0
BURN_MINOR_VERSION=2
BURN_MICRO_VERSION=8
BURN_MICRO_VERSION=4
BURN_INTERFACE_AGE=0
BURN_BINARY_AGE=0
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
@ -39,7 +39,7 @@ AC_SUBST(BURN_VERSION)
dnl Libtool versioning
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION
LT_CURRENT=5
LT_CURRENT=`expr $BURN_MICRO_VERSION - $BURN_INTERFACE_AGE`
LT_REVISION=$BURN_INTERFACE_AGE
LT_AGE=`expr $BURN_BINARY_AGE - $BURN_INTERFACE_AGE`
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`

View File

@ -16,10 +16,8 @@
#include "volume.h"
#include "tree.h"
#include "util.h"
#include "file.h"
#include "libisofs.h"
#include "libburn/libburn.h"
#include "eltorito.h"
/* burn-source compatible stuff */
static int
@ -79,7 +77,6 @@ static const write_fn writers[] =
NULL,
wr_system_area,
wr_pri_vol_desc,
el_torito_wr_boot_vol_desc,
joliet_wr_sup_vol_desc,
wr_vol_desc_term,
wr_l_path_table,
@ -88,7 +85,6 @@ static const write_fn writers[] =
joliet_wr_m_path_table,
wr_dir_records,
joliet_wr_dir_records,
el_torito_wr_catalog,
wr_files
};
@ -105,35 +101,30 @@ add_susp_fields_rec(struct ecma119_write_target *t,
{
size_t i;
if (!node->iso_self)
return;
rrip_add_PX(t, node);
rrip_add_NM(t, node);
rrip_add_TF(t, node);
switch (node->type) {
case ECMA119_FILE:
break;
case ECMA119_SYMLINK:
rrip_add_SL(t, node);
break;
case ECMA119_DIR:
if (node->info.dir.real_parent != node->parent) {
rrip_add_RE(t, node);
rrip_add_PL(t, node);
}
for (i = 0; i < node->info.dir.nchildren; i++) {
add_susp_fields_rec(t, node->info.dir.children[i]);
}
break;
case ECMA119_PLACEHOLDER:
rrip_add_CL(t, node);
break;
default:
// FIXME support for device blocks by uncommenting this
//if (node->iso_self->attrib.st_rdev)
// rrip_add_PN(t, node);
break;
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
@ -155,40 +146,33 @@ calc_dir_size(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
size_t newlen;
assert(dir->type == ECMA119_DIR);
t->dirlist_len++;
dir->info.dir.len = 34 + dir->info.dir.self_susp.non_CE_len
+ 34 + dir->info.dir.parent_susp.non_CE_len;
dir->info.dir.CE_len = dir->info.dir.self_susp.CE_len
+ dir->info.dir.parent_susp.CE_len;
for (i = 0; i < dir->info.dir.nchildren; ++i) {
struct ecma119_tree_node *ch = dir->info.dir.children[i];
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];
newlen = dir->info.dir.len + ch->dirent_len + ch->susp.non_CE_len;
if ((newlen % 2048) < (dir->info.dir.len % 2048)) {
dir->info.dir.len = newlen + (2048 - (dir->info.dir.len % 2048));
} else {
dir->info.dir.len += ch->dirent_len + ch->susp.non_CE_len;
}
dir->info.dir.CE_len += ch->susp.CE_len;
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->info.dir.len + dir->info.dir.CE_len,
t->total_dir_size += round_up(dir->dir.len + dir->dir.CE_len,
t->block_size);
for (i = 0; i < dir->info.dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->info.dir.children[i];
//struct iso_tree_node *iso = ch->iso_self;
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++;
// }
} else if (iso && iso->attrib.st_size
&& iso->loc.type == LIBISO_FILESYS
&& iso->loc.path) {
t->filelist_len++;
}
}
}
@ -204,27 +188,26 @@ calc_dir_pos(struct ecma119_write_target *t,
assert(dir->type == ECMA119_DIR);
dir->info.dir.block = t->curblock;
t->curblock += div_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size);
/* 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->info.dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->info.dir.children[i];
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);
}
}
static int
cmp_file(const void *f1, const void *f2)
{
struct iso_file *f = *((struct iso_file**)f1);
struct iso_file *g = *((struct iso_file**)f2);
/* higher weighted first */
return g->sort_weight - f->sort_weight;
/* reset curfile when we're finished */
if (!dir->parent) {
t->curfile = 0;
}
}
/**
* Fill out the block field for each file and fill out t->filelist.
* 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,
@ -233,112 +216,69 @@ calc_file_pos(struct ecma119_write_target *t,
size_t i;
assert(dir->type == ECMA119_DIR);
t->filelist = calloc(1, sizeof(struct iso_file *) * t->file_table->count);
for (i = 0; i < FILE_HASH_NODES; ++i) {
struct iso_file_hash_node *node;
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;
node = t->file_table->table[i];
if (!node)
continue;
do {
struct iso_file *file = node->file;
if (file->size)
t->filelist[t->curfile++] = file;
node = node->next;
} while (node);
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;
}
}
t->filelist_len = t->curfile;
/* sort */
if ( t->sort_files )
qsort(t->filelist, t->filelist_len, sizeof(void*), cmp_file);
/* fill block value */
for ( i = 0; i < t->filelist_len; ++i) {
struct iso_file *file = t->filelist[i];
file->block = t->curblock;
t->curblock += div_up(file->size, t->block_size);
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 */
t->curfile = 0;
if (!dir->parent) {
t->curfile = 0;
}
}
/**
* 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.
*/
static struct ecma119_write_target*
struct ecma119_write_target*
ecma119_target_new(struct iso_volset *volset,
const struct ecma119_source_opts *opts)
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 =
(struct iso_tree_node*) volset->volume[opts->volnum]->root;
struct iso_tree_node *iso_root = volset->volume[volnum]->root;
t->cache_inodes = opts->no_cache_inodes ? 0 : 1;
t->replace_mode = opts->default_mode ? 0 : 1;
if ( opts->replace_dir_mode )
t->replace_mode |= 0x02;
if ( opts->replace_file_mode )
t->replace_mode |= 0x04;
if ( opts->replace_gid )
t->replace_mode |= 0x08;
if ( opts->replace_uid )
t->replace_mode |= 0x10;
t->dir_mode = opts->dir_mode;
t->file_mode = opts->file_mode;
t->gid = opts->gid;
t->uid = opts->uid;
//TODO get defailt values for current locale, no UTF-8
t->input_charset = opts->input_charset ? opts->input_charset : "UTF-8";
t->ouput_charset = opts->ouput_charset ? opts->ouput_charset : "UTF-8";
t->sort_files = opts->sort_files;
t->file_table = iso_file_table_new(t->cache_inodes);
volset->refcount++;
t->iso_level = opts->level;
t->block_size = 2048;
t->relaxed_constraints = opts->relaxed_constraints;
t->rockridge = (opts->flags & ECMA119_ROCKRIDGE) ? 1 : 0;
t->joliet = (opts->flags & ECMA119_JOLIET) ? 1 : 0;
t->catalog = volset->volume[opts->volnum]->bootcat;
t->eltorito = t->catalog ? 1 : 0;
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 = opts->volnum;
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_joliet);
t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet);
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;
@ -346,10 +286,10 @@ ecma119_target_new(struct iso_volset *volset,
cur = 1;
for (i = 0; i < t->dirlist_len; i++) {
struct ecma119_tree_node *dir = t->pathlist[i];
for (j = 0; j < dir->info.dir.nchildren; j++) {
struct ecma119_tree_node *ch = dir->info.dir.children[j];
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->iso_name);
size_t len = 8 + strlen(ch->name);
t->pathlist[cur++] = ch;
t->path_table_size += len + len % 2;
}
@ -360,8 +300,6 @@ ecma119_target_new(struct iso_volset *volset,
+ 1 /* volume desc */
+ 1; /* volume desc terminator */
if (t->eltorito)
t->curblock += 1; /* boot record volume descriptor */
if (t->joliet) /* supplementary vol desc */
t->curblock += div_up (2048, t->block_size);
@ -378,30 +316,11 @@ ecma119_target_new(struct iso_volset *volset,
}
calc_dir_pos(t, t->root);
/* reset curfile when we're finished */
t->curfile = 0;
if (t->joliet) {
if (t->joliet)
joliet_calc_dir_pos(t, t->joliet_root);
/* reset curfile when we're finished */
t->curfile = 0;
}
/* el-torito? */
if (t->eltorito) {
/* add catalog block */
t->catalog->file->block = t->curblock;
t->curblock += div_up(2048, t->block_size);
el_torito_get_image_files(t);
}
calc_file_pos(t, t->root);
if (t->eltorito)
el_torito_patch_image_files(t);
if (t->joliet)
joliet_update_file_pos (t, t->joliet_root);
if (t->rockridge) {
susp_finalize(t, t->root);
@ -427,19 +346,11 @@ is_joliet_state(enum ecma119_write_state state)
|| state == ECMA119_WRITE_DIR_RECORDS_JOLIET;
}
static int
is_eltorito_state(enum ecma119_write_state state)
{
return state == ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC
|| state == ECMA119_WRITE_ELTORITO_CATALOG;
}
static void
next_state(struct ecma119_write_target *t)
{
t->state++;
while ( (!t->joliet && is_joliet_state(t->state))
||(!t->eltorito && is_eltorito_state(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);
@ -488,13 +399,11 @@ wr_files(struct ecma119_write_target *t, uint8_t *buf)
{
struct state_files *f_st = &t->state_files;
size_t nread;
struct iso_file *f = t->filelist[f_st->file];
const char *path = f->path;
struct ecma119_tree_node *f = t->filelist[f_st->file];
const char *path = f->iso_self->loc.path;
if (!f_st->fd) {
printf("Writing file %s\n", path);
f_st->data_len = f->size;
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);
@ -522,25 +431,15 @@ 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 = str2d_char(volume->volume_id, t->input_charset);
char *pub_id = str2a_char(volume->publisher_id, t->input_charset);
char *data_id = str2a_char(volume->data_preparer_id, t->input_charset);
char *volset_id = str2d_char(t->volset->volset_id, t->input_charset);
char *system_id = str2a_char(volume->system_id, t->input_charset);
char *application_id = str2a_char(volume->application_id, t->input_charset);
char *copyright_file_id = str2d_char(volume->copyright_file_id, t->input_charset);
char *abstract_file_id = str2d_char(volume->abstract_file_id, t->input_charset);
char *biblio_file_id = str2d_char(volume->biblio_file_id, t->input_charset);
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;
if (system_id)
strncpy((char*)vol->system_id, system_id, 32);
else
/* put linux by default? */
memcpy(vol->system_id, "LINUX", 5);
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);
@ -553,19 +452,10 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
write_one_dir_record(t, t->root, 3, vol->root_dir_record);
/* mmm, why not check for null? */
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);
if (application_id)
strncpy((char*)vol->application_id, application_id, 128);
if (copyright_file_id)
strncpy((char*)vol->copyright_file_id, copyright_file_id, 37);
if (abstract_file_id)
strncpy((char*)vol->abstract_file_id, abstract_file_id, 37);
if (biblio_file_id)
strncpy((char*)vol->bibliographic_file_id, biblio_file_id, 37);
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);
@ -576,11 +466,6 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
free(volset_id);
free(pub_id);
free(data_id);
free(system_id);
free(application_id);
free(copyright_file_id);
free(abstract_file_id);
free(biblio_file_id);
}
static void
@ -606,18 +491,17 @@ write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf)
for (i = 0; i < t->dirlist_len; i++) {
dir = t->pathlist[i];
assert(dir->type == ECMA119_DIR);
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->iso_name) : 1;
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
rec->len_xa[0] = 0;
write_int(rec->block, dir->info.dir.block, 4);
write_int(rec->block, dir->block, 4);
write_int(rec->parent, parent + 1, 2);
if (dir->parent)
memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]);
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
}
}
@ -643,36 +527,22 @@ write_one_dir_record(struct ecma119_write_target *t,
int file_id,
uint8_t *buf)
{
uint32_t len;
uint32_t block;
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->iso_name);
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->iso_name;
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;
if (node->type == ECMA119_DIR) {
len = node->info.dir.len;
block = node->info.dir.block;
} else if (node->type == ECMA119_FILE) {
len = node->info.file->size;
block = node->info.file->block;
} else {
/* for nodes other than files and dirs, we set both len and block to 0 */
len = 0;
block = 0;
}
/* we don't write out susp fields for the root node */
if (t->rockridge) {
if (file_id == 0) {
assert(node->type == ECMA119_DIR);
susp_write(t, &node->info.dir.self_susp, &buf[len_dr]);
len_dr += node->info.dir.self_susp.non_CE_len;
susp_write(t, &node->dir.self_susp, &buf[len_dr]);
len_dr += node->dir.self_susp.non_CE_len;
} else if (file_id == 1) {
assert(node->type == ECMA119_DIR);
susp_write(t, &node->info.dir.parent_susp, &buf[len_dr]);
len_dr += node->info.dir.parent_susp.non_CE_len;
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;
@ -682,7 +552,7 @@ write_one_dir_record(struct ecma119_write_target *t,
node = node->parent;
rec->len_dr[0] = len_dr;
iso_bb(rec->block, block, 4);
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;
@ -697,10 +567,7 @@ write_one_dir(struct ecma119_write_target *t,
uint8_t *buf)
{
size_t i;
int j;
size_t len;
uint8_t *orig_buf = buf;
uint8_t *prior_buf = buf;
assert(dir->type == ECMA119_DIR);
/* write the "." and ".." entries first */
@ -710,34 +577,23 @@ write_one_dir(struct ecma119_write_target *t,
write_one_dir_record(t, dir, 1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
for (i = 0; i < dir->info.dir.nchildren; i++) {
write_one_dir_record(t, dir->info.dir.children[i], -1, buf);
len = ((struct ecma119_dir_record*) buf)->len_dr[0];
if ((buf + len - prior_buf) >= 2048) {
for (j = len - 1; j >= 0; j--) {
prior_buf[2048 + j] = buf[j];
buf[j] = 0;
}
prior_buf += 2048;
buf = prior_buf + len;
}
else {
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->info.dir.self_susp, buf);
buf += dir->info.dir.self_susp.CE_len;
susp_write_CE(t, &dir->info.dir.parent_susp, buf);
buf += dir->info.dir.parent_susp.CE_len;
for (i = 0; i < dir->info.dir.nchildren; i++) {
susp_write_CE(t, &dir->info.dir.children[i]->susp, buf);
buf += dir->info.dir.children[i]->susp.CE_len;
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->info.dir.len + dir->info.dir.CE_len);
assert (buf - orig_buf == dir->dir.len + dir->dir.CE_len);
}
static void
@ -748,7 +604,7 @@ write_dirs(struct ecma119_write_target *t, uint8_t *buf)
for (i = 0; i < t->dirlist_len; i++) {
dir = t->dirlist[i];
write_one_dir(t, dir, buf);
buf += round_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size);
buf += round_up(dir->dir.len + dir->dir.CE_len, t->block_size);
}
}
@ -813,28 +669,26 @@ bs_free_data(struct burn_source *bs)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
ecma119_tree_free(t->root);
iso_file_table_clear(t->file_table);
free(t->dirlist);
free(t->pathlist);
free(t->dirlist_joliet);
free(t->pathlist_joliet);
free(t->filelist);
free(t->state_data);
if (t->joliet)
joliet_tree_free(t->joliet_root);
if (t->state_files.fd)
fclose(t->state_files.fd);
}
struct burn_source *iso_source_new_ecma119(struct iso_volset *volset,
struct ecma119_source_opts *opts)
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, opts);
ret->data = ecma119_target_new(volset, volnum, level, flags);
return ret;
}

View File

@ -29,7 +29,6 @@ enum ecma119_write_state
ECMA119_WRITE_SYSTEM_AREA,
ECMA119_WRITE_PRI_VOL_DESC,
ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC,
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
ECMA119_WRITE_VOL_DESC_TERMINATOR,
ECMA119_WRITE_L_PATH_TABLE,
@ -38,7 +37,6 @@ enum ecma119_write_state
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
ECMA119_WRITE_DIR_RECORDS,
ECMA119_WRITE_DIR_RECORDS_JOLIET,
ECMA119_WRITE_ELTORITO_CATALOG,
ECMA119_WRITE_FILES,
ECMA119_WRITE_DONE
@ -63,40 +61,6 @@ struct ecma119_write_target
unsigned int rockridge:1;
unsigned int joliet:1;
unsigned int iso_level:2;
unsigned int eltorito:1;
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
struct el_torito_boot_catalog *catalog;
int replace_mode; /**< Replace ownership and modes of files
*
* 0. filesystem values
* 1. useful values
* bits 1-4 bitmask:
* 2 - replace dir
* 3 - replace file
* 4 - replace gid
* 5 - replace uid
*/
mode_t dir_mode;
mode_t file_mode;
gid_t gid;
uid_t uid;
char *input_charset;
char *ouput_charset;
int cache_inodes;
int sort_files; /**< if sort files or not. Sorting is based of
* the weight of each file */
/**
* In the CD, each file must have an unique inode number. So each
* time we add a new file, this is incremented.
*/
ino_t ino;
int curblock;
uint16_t block_size;
@ -122,13 +86,10 @@ struct ecma119_write_target
size_t dirlist_len; /**< The length of the previous 2 lists.
*/
struct iso_file_table *file_table;
/**<
* A hash table with info about all files
struct ecma119_tree_node **filelist;
/**< A pre-order list of files with
* non-NULL paths and non-zero sizes.
*/
struct iso_file **filelist; /**< A pre-order list of files.*/
size_t filelist_len; /* Length of the previous list. */
int curfile; /**< Used as a helper field for writing
@ -140,8 +101,6 @@ struct ecma119_write_target
*/
struct joliet_tree_node **dirlist_joliet;
struct joliet_tree_node **pathlist_joliet;
size_t dirlist_len_joliet;
enum ecma119_write_state state; /* The current state of the writer. */
@ -170,6 +129,19 @@ struct ecma119_write_target
} 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
@ -246,17 +218,6 @@ struct ecma119_sup_vol_desc
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_boot_rec_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 boot_sys_id BP(8, 39);
uint8_t boot_id BP(40, 71);
uint8_t boot_catalog BP(72, 75);
uint8_t unused BP(76, 2048);
};
struct ecma119_vol_desc_terminator
{
uint8_t vol_desc_type BP(1, 1);

View File

@ -9,343 +9,74 @@
#include "ecma119_tree.h"
#include "tree.h"
#include "util.h"
#include "eltorito.h"
static size_t calc_dirent_len(struct ecma119_tree_node *n)
{
int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
int ret = n->name ? strlen(n->name) + 33 : 34;
if (ret % 2) ret++;
return ret;
}
/**
* Replace the file permissions and user/group id of an ECMA-119 node.
* This is used when a replace mode is selected, i.e., when we want to
* create a disc where the mode of each file or directory will be
* different than the mode in the original source.
*/
static void
replace_node_mode(struct ecma119_write_target *t, struct stat *st)
{
if ( S_ISDIR(st->st_mode) ) {
if ( t->replace_mode & 0x02 ) {
/* replace dir mode with specific */
st->st_mode &= S_IFMT;
st->st_mode |= t->dir_mode;
} else if (t->replace_mode & 0x01) {
/* replace dir mode with default */
/* read perm */
mode_t new_mode = (st->st_mode & S_IFMT) | 0444;
/* search bit if any */
if ( st->st_mode & 0111)
new_mode |= 0111;
st->st_mode = new_mode;
}
} else {
if ( t->replace_mode & 0x04 ) {
/* replace file mode with specific */
st->st_mode &= S_IFMT;
st->st_mode |= t->file_mode;
} else if (t->replace_mode & 0x01) {
/* replace file mode with default */
/* read perm */
mode_t new_mode = (st->st_mode & S_IFMT) | 0444;
/* execute bit if any */
if ( st->st_mode & 0111)
new_mode |= 0111;
st->st_mode = new_mode;
}
}
if ( t->replace_mode & 0x08 ) {
/* replace gid mode with specific */
st->st_gid = t->gid;
} else if (t->replace_mode & 0x01) {
st->st_gid = 0;
}
if ( t->replace_mode & 0x10 ) {
/* replace gid mode with specific */
st->st_uid = t->uid;
} else if (t->replace_mode & 0x01) {
st->st_uid = 0;
}
}
/**
* Creates a new ECMA-119 node from the given iso tree node, and initializes
* the fields that are common to all kind of nodes (dir, reg file, symlink...).
*
* @param t
* The options for the ECMA-119 tree that is being created
* @param parent
* The parent of the node, or NULL if it's the root.
* @param iso
* The node from which this function creates a ECMA-119 node
* @return
* The created node.
*/
static struct ecma119_tree_node*
create_ecma119_node(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
char *(*iso_name)(const char *, const char *) = ISO_ISDIR(iso) ?
((t->iso_level == 1) ? iso_1_dirid : iso_2_dirid)
: ((t->iso_level == 1) ? iso_1_fileid : iso_2_fileid);
char *(*iso_r_name)(const char *, const char *, int) =
ISO_ISDIR(iso) ? iso_r_dirid : iso_r_fileid;
assert(t && (!parent || parent->type == ECMA119_DIR) && iso );
ret = calloc(1, sizeof(struct ecma119_tree_node));
/*
* If selected one ISO relaxed constraints other than NO_DIR_REALOCATION,
* we use the function that computes the relaxed name, otherwise normal
* function for specified level is used.
*/
ret->iso_name = iso->name ?
( t->relaxed_constraints & ~ECMA119_NO_DIR_REALOCATION ?
iso_r_name(iso->name, t->input_charset, t->relaxed_constraints) :
iso_name(iso->name, t->input_charset)
) : NULL;
ret->dirent_len = calc_dirent_len(ret);
/* iso node keeps the same file attribs as the original file. */
ret->attrib = iso->attrib;
/*
* When using RR extension and replace mode, we will replace the
* permissions and uid/gid of each file with those previously selected
* by the user.
*/
if ( t->rockridge && t->replace_mode )
replace_node_mode(t, &ret->attrib);
if (!iso->name)
ret->full_name = NULL;
else if ( strcmp(t->input_charset,t->ouput_charset) )
/* convert the file name charset */
ret->full_name = convert_str(iso->name, t->input_charset,
t->ouput_charset);
else
ret->full_name = strdup(iso->name);
ret->target = t;
ret->parent = parent;
return ret;
}
/**
* Create a new ECMA-119 node representing a directory from a iso directory
* node.
*/
static struct ecma119_tree_node*
create_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node_dir *iso)
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
assert(t && (!parent || parent->type == ECMA119_DIR)
&& iso && S_ISDIR(iso->node.attrib.st_mode));
&& iso && S_ISDIR(iso->attrib.st_mode));
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
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->info.dir.real_parent = parent;
ret->info.dir.depth = parent ? parent->info.dir.depth + 1 : 1;
ret->info.dir.nchildren = 0;
ret->info.dir.children = calloc(1, sizeof(void*) * iso->nchildren);
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;
}
/**
* Create a new ECMA-119 node representing a regular file from a iso file
* node.
*/
static struct ecma119_tree_node*
create_file(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node_file *iso)
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
struct iso_file *file;
assert(t && iso && parent && parent->type == ECMA119_DIR);
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->type = ECMA119_FILE;
/* get iso_file struct */
file = iso_file_table_lookup(t->file_table, iso);
if ( file == NULL ) {
/*
* If the file is not already added to the disc, we add it now
* to the file table, and get a new inode number for it.
*/
file = iso_file_new(iso);
iso_file_table_add_file(t->file_table, file);
file->ino = ++t->ino;
} else {
/* increment number of hard-links */
file->nlink++;
}
ret->attrib.st_nlink = file->nlink;
ret->attrib.st_ino = file->ino;
ret->info.file = file;
return ret;
}
/**
* Create a new ECMA-119 node representing a placeholder for a relocated
* dir.
*
* See IEEE P1282, section 4.1.5 for details
*/
static struct ecma119_tree_node*
create_placeholder(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct ecma119_tree_node *real)
{
struct ecma119_tree_node *ret;
assert(t && real && real->type == ECMA119_DIR
&& parent && parent->type == ECMA119_DIR);
ret = calloc(1, sizeof(struct ecma119_tree_node));
ret->iso_name = real->iso_name; /* TODO strdup? */
/* FIXME
* if we strdup above, if name changes in mangle_all,
* this probably keeps as original.
* if not, both change, but we need to update dirent_len.
* I think that attributes of a placeholder must be taken from
* real_me, not keept here.
* FIXME
* Another question is that real is a dir, while placeholder is
* a file, and ISO name restricctions are different, what to do?
*/
ret->dirent_len = real->dirent_len;
ret->attrib = real->attrib;
ret->full_name = strdup(real->full_name);
ret->target = t;
ret->parent = parent;
ret->type = ECMA119_PLACEHOLDER;
ret->info.real_me = real;
ret->attrib.st_nlink = 1;
ret->attrib.st_ino = ++t->ino;
return ret;
}
/**
* Create a new ECMA-119 node representing a symbolic link from a iso symlink
* node.
*/
static struct ecma119_tree_node*
create_symlink(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node_symlink *iso)
{
struct ecma119_tree_node *ret;
assert(t && iso && parent && parent->type == ECMA119_DIR);
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->iso_name = iso->node.name ? ((t->iso_level == 1) ?
iso_1_fileid(iso->node.name, t->input_charset)
: iso_2_fileid(iso->node.name, t->input_charset))
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_fileid(iso->name)
: iso_2_fileid(iso->name))
: NULL;
ret->type = ECMA119_SYMLINK;
ret->info.dest = iso->dest; /* TODO strdup? */
ret->attrib.st_nlink = 1;
ret->attrib.st_ino = ++t->ino;
return ret;
}
/**
* Create a new ECMA-119 node representing a boot catalog. This is like a
* regular file, but its contents are taken from a El-Torito boot catalog,
* and not from a file in the local filesystem.
*
* See "El Torito" Bootable CD-ROM Format Specification Version 1.0 for
* more details.
*/
static struct ecma119_tree_node*
create_boot_catalog(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node_boot_catalog *iso)
{
struct ecma119_tree_node *ret;
struct iso_file *file;
assert(t && iso && parent && parent->type == ECMA119_DIR);
/*
* This will simply create a ECMA119 file, with the only difference
* that the iso_file is not taken from table, but from boot catalog
*/
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->dirent_len = calc_dirent_len(ret);
ret->parent = parent;
ret->iso_self = iso;
ret->target = t;
ret->type = ECMA119_FILE;
file = iso->catalog->file;
file->ino = ++t->ino;
ret->attrib.st_nlink = file->nlink;
ret->attrib.st_ino = file->ino;
ret->info.file = file;
return ret;
}
/**
* Create a new ECMA-119 node that corresponds to the given iso tree node.
* If that node is a dir, this function recurses over all their children,
* thus creating a ECMA-119 tree whose root is the given iso dir.
*/
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 = NULL;
struct ecma119_tree_node *ret;
size_t i;
assert(t && iso);
if ( iso->hide_flags & LIBISO_HIDE_ON_RR )
return NULL;
switch ( iso->type ) {
case LIBISO_NODE_FILE:
ret = create_file(t, parent, (struct iso_tree_node_file*)iso);
break;
case LIBISO_NODE_SYMLINK:
if ( !t->rockridge )
printf("Can't add symlinks to a non ISO tree. Skipping %s \n",
iso->name);
else
ret = create_symlink(t, parent, (struct iso_tree_node_symlink*)iso);
break;
case LIBISO_NODE_DIR:
{
size_t i;
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir*)iso;
ret = create_dir(t, parent, dir);
for (i = 0; i < dir->nchildren; i++) {
struct ecma119_tree_node *child;
child = create_tree(t, ret, dir->children[i]);
if (child)
ret->info.dir.children[ret->info.dir.nchildren++] = child;
}
}
break;
case LIBISO_NODE_BOOTCATALOG:
ret = create_boot_catalog(t, parent,
(struct iso_tree_node_boot_catalog*)iso);
break;
default:
/* should never happen */
assert( 0 );
break;
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;
}
@ -356,13 +87,12 @@ ecma119_tree_free(struct ecma119_tree_node *root)
size_t i;
if (root->type == ECMA119_DIR) {
for (i=0; i < root->info.dir.nchildren; i++) {
ecma119_tree_free(root->info.dir.children[i]);
for (i=0; i < root->dir.nchildren; i++) {
ecma119_tree_free(root->dir.children[i]);
}
free(root->info.dir.children);
free(root->dir.children);
}
free(root->iso_name);
free(root->full_name);
free(root->name);
free(root);
}
@ -372,19 +102,13 @@ max_child_name_len(struct ecma119_tree_node *root)
size_t ret = 0, i;
assert(root->type == ECMA119_DIR);
for (i=0; i < root->info.dir.nchildren; i++) {
size_t len = strlen(root->info.dir.children[i]->iso_name);
for (i=0; i < root->dir.nchildren; i++) {
size_t len = strlen(root->dir.children[i]->name);
ret = MAX(ret, len);
}
return ret;
}
/**
* Relocates a directory, as specified in Rock Ridge Specification
* (see IEEE P1282, section 4.1.5). This is needed when the number of levels
* on a directory hierarchy exceeds 8, or the length of a path is higher
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
*/
static void
reparent(struct ecma119_tree_node *child,
struct ecma119_tree_node *parent)
@ -396,11 +120,13 @@ reparent(struct ecma119_tree_node *child,
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->info.dir.nchildren; i++) {
if (child->parent->info.dir.children[i] == child) {
placeholder = create_placeholder(child->target,
child->parent, child);
child->parent->info.dir.children[i] = 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;
}
@ -409,83 +135,52 @@ reparent(struct ecma119_tree_node *child,
/* add the child to its new parent */
child->parent = parent;
parent->info.dir.nchildren++;
parent->info.dir.children = realloc( parent->info.dir.children,
sizeof(void*) * parent->info.dir.nchildren );
parent->info.dir.children[parent->info.dir.nchildren-1] = child;
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
* This restriction is imposed by ECMA-119 specification (see ECMA-119,
* 6.8.2.1).
*/
static void
reorder_tree(struct ecma119_write_target *t,
struct ecma119_tree_node *root,
reorder_tree(struct ecma119_tree_node *root,
struct ecma119_tree_node *cur)
{
size_t max_path;
assert(root && cur && cur->type == ECMA119_DIR);
cur->info.dir.depth = cur->parent ? cur->parent->info.dir.depth + 1 : 1;
cur->info.dir.path_len = cur->parent ? cur->parent->info.dir.path_len
+ strlen(cur->iso_name) : 0;
max_path = cur->info.dir.path_len + cur->info.dir.depth
+ max_child_name_len(cur);
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->info.dir.depth > 8 || max_path > 255) {
if (t->rockridge) {
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 {
/* we need to delete cur */
size_t i,j;
struct ecma119_tree_node *parent = cur->parent;
printf("Can't dirs deeper than 8 without RR. Skipping %s\n",
cur->full_name);
for (i=0; i < parent->info.dir.nchildren; ++i) {
if (parent->info.dir.children[i] == cur) {
break;
}
}
assert ( i < parent->info.dir.nchildren);
for ( j = i; j < parent->info.dir.nchildren - 1; ++j)
parent->info.dir.children[j] = parent->info.dir.children[j+1];
parent->info.dir.nchildren--;
ecma119_tree_free(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->info.dir.nchildren; i++) {
if (cur->info.dir.children[i]->type == ECMA119_DIR)
reorder_tree(t, root, cur->info.dir.children[i]);
for (i=0; i < cur->dir.nchildren; i++) {
if (cur->dir.children[i]->type == ECMA119_DIR)
reorder_tree(root, cur->dir.children[i]);
}
}
}
/**
* Compare the iso name of two ECMA-119 nodes
*/
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->iso_name, g->iso_name);
return strcmp(f->name, g->name);
}
/**
* Sorts a the children of each directory in the ECMA-119 tree represented
* by \p root, acording to the order specified in ECMA-119, section 9.3.
*/
static void
sort_tree(struct ecma119_tree_node *root)
{
@ -493,11 +188,10 @@ sort_tree(struct ecma119_tree_node *root)
assert(root && root->type == ECMA119_DIR);
qsort(root->info.dir.children, root->info.dir.nchildren,
sizeof(void*), cmp_node);
for (i=0; i < root->info.dir.nchildren; i++) {
if (root->info.dir.children[i]->type == ECMA119_DIR)
sort_tree(root->info.dir.children[i]);
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]);
}
}
@ -548,15 +242,11 @@ mangle_name(char **name, int num_change, int level, int seq_num)
sprintf(*name, fmt, base, seq_num, ext);
}
/**
* Ensures that the ISO name of each children of the given dir is unique,
* changing some of them if needed.
*/
static void
mangle_all(struct ecma119_tree_node *dir)
{
size_t i, j, k;
struct ecma119_dir_info d = dir->info.dir;
struct ecma119_dir_info d = dir->dir;
size_t n_change;
int changed;
@ -567,8 +257,8 @@ mangle_all(struct ecma119_tree_node *dir)
/* find the number of consecutive equal names */
j = 1;
while ( i+j < d.nchildren &&
!strcmp(d.children[i]->iso_name,
d.children[i+j]->iso_name) )
!strcmp(d.children[i]->name,
d.children[i+j]->name) )
j++;
if (j == 1) continue;
@ -576,7 +266,7 @@ mangle_all(struct ecma119_tree_node *dir)
changed = 1;
n_change = j / 10 + 1;
for (k=0; k < j; k++) {
mangle_name(&(d.children[i+k]->iso_name),
mangle_name(&(d.children[i+k]->name),
n_change,
dir->target->iso_level,
k);
@ -600,8 +290,7 @@ ecma119_tree_create(struct ecma119_write_target *t,
struct iso_tree_node *iso_root)
{
t->root = create_tree(t, NULL, iso_root);
if ( !(t->relaxed_constraints & ECMA119_NO_DIR_REALOCATION) )
reorder_tree(t, t->root, t->root);
reorder_tree(t->root, t->root);
sort_tree(t->root);
mangle_all(t->root);
return t->root;
@ -616,8 +305,8 @@ ecma119_tree_print(struct ecma119_tree_node *root, int spaces)
memset(sp, ' ', spaces);
sp[spaces] = '\0';
printf("%s%s\n", sp, root->iso_name);
printf("%s%s\n", sp, root->name);
if (root->type == ECMA119_DIR)
for (i=0; i < root->info.dir.nchildren; i++)
ecma119_tree_print(root->info.dir.children[i], spaces+2);
for (i=0; i < root->dir.nchildren; i++)
ecma119_tree_print(root->dir.children[i], spaces+2);
}

View File

@ -10,18 +10,11 @@
#ifndef LIBISO_ECMA119_TREE_H
#define LIBISO_ECMA119_TREE_H
#include <sys/stat.h>
#include "file.h"
struct ecma119_write_target;
struct iso_tree_node;
enum ecma119_node_type {
enum {
ECMA119_FILE,
ECMA119_SYMLINK,
ECMA119_DIR,
ECMA119_PLACEHOLDER /**< placeholder for a relocated dir. */
ECMA119_DIR
};
struct ecma119_dir_info {
@ -32,7 +25,6 @@ struct ecma119_dir_info {
* Directory Records (including SU) */
size_t CE_len; /**< sum of the lengths of children's
* SUSP CE areas */
size_t block;
int depth;
size_t path_len; /**< The length of a path up to, and
@ -45,34 +37,39 @@ struct ecma119_dir_info {
/**< 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 *iso_name; /**< in ASCII, conforming to the
* current ISO level. */
char *full_name; /**< full name, in current locale (TODO put this in UTF-8?) */
char *name; /**< in ASCII, conforming to the
* current ISO level. */
size_t dirent_len; /**< Length of the directory record,
* not including SU. */
* not including SU. */
size_t block;
struct ecma119_tree_node *parent;
struct iso_tree_node *iso_self;
struct ecma119_write_target *target;
struct stat attrib;
struct susp_info susp;
enum ecma119_node_type type; /**< file, symlink, directory or placeholder */
union {
struct iso_file *file;
char *dest;
int type; /**< file or directory */
/* union {*/
struct ecma119_dir_info dir;
struct ecma119_tree_node *real_me; /**< this field points to
* the relocated directory.
*/
} info;
struct ecma119_file_info file;
/* };*/
};
/**

View File

@ -1,454 +0,0 @@
#include "libisofs.h"
#include "eltorito.h"
#include "volume.h"
#include "util.h"
#include <assert.h>
#include <malloc.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
struct el_torito_validation_entry {
uint8_t header_id BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32);
};
struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32);
};
struct el_torito_section_header_entry {
uint8_t header_indicator BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
};
struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32);
};
/**
* This table should be written with accuracy values at offset
* 8 of boot image, when used ISOLINUX boot loader
*/
struct boot_info_table {
uint8_t bi_pvd BP(1, 4); /* LBA of primary volume descriptor */
uint8_t bi_file BP(5, 8); /* LBA of boot file */
uint8_t bi_length BP(9, 12); /* Length of boot file */
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
uint8_t bi_reserved BP(17, 56); /* Reserved */
};
struct partition_desc {
uint8_t boot_ind;
uint8_t begin_chs[3];
uint8_t type;
uint8_t end_chs[3];
uint8_t start[4];
uint8_t size[4];
};
struct hard_disc_mbr {
uint8_t code_area[440];
uint8_t opt_disk_sg[4];
uint8_t pad[2];
struct partition_desc partition[4];
uint8_t sign1;
uint8_t sign2;
};
static struct el_torito_boot_image *
create_image(struct iso_tree_node *image,
enum eltorito_boot_media_type type)
{
struct el_torito_boot_image *boot;
int boot_media_type = 0;
int load_sectors = 0; /* number of sector to load */
unsigned char partition_type = 0;
switch (type) {
case ELTORITO_FLOPPY_EMUL:
switch (image->attrib.st_size) {
case 1200 * 1024:
boot_media_type = 1; /* 1.2 meg diskette */
break;
case 1440 * 1024:
boot_media_type = 2; /* 1.44 meg diskette */
break;
case 2880 * 1024:
boot_media_type = 3; /* 2.88 meg diskette */
break;
default:
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", (int) image->attrib.st_size / 1024);
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE;
return NULL;
break;
}
/* it seems that for floppy emulation we need to load
* a single sector (512b) */
load_sectors = 1;
break;
case ELTORITO_HARD_DISC_EMUL:
{
size_t i;
int fd;
struct hard_disc_mbr mbr;
int used_partition;
/* read the MBR on disc and get the type of the partition */
fd = open(((struct iso_tree_node_file*)image)->path, O_RDONLY);
if ( fd == -1 ) {
fprintf(stderr, "Can't open image file\n");
return NULL;
}
if ( read(fd, &mbr, sizeof(mbr)) ) {
fprintf(stderr, "Can't read MBR from image file\n");
close(fd);
return NULL;
}
close(fd);
/* check valid MBR signature */
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
fprintf(stderr, "Invalid MBR. Wrong signature.\n");
return NULL;
}
/* ensure single partition */
used_partition = -1;
for (i = 0; i < 4; ++i) {
if (mbr.partition[i].type != 0) {
/* it's an used partition */
if (used_partition != -1) {
fprintf(stderr, "Invalid MBR. At least 2 paritions: %d and "
"%d, are being used\n", used_partition, i);
return NULL;
} else
used_partition = i;
}
}
partition_type = mbr.partition[used_partition].type;
}
boot_media_type = 4;
/* only load the MBR */
load_sectors = 1;
break;
case ELTORITO_NO_EMUL:
boot_media_type = 0;
break;
}
boot = calloc(1, sizeof(struct el_torito_boot_image));
boot->bootable = 1;
boot->image = (struct iso_tree_node_file *) image;
boot->type = boot_media_type;
boot->load_size = load_sectors;
boot->partition_type = partition_type;
return boot;
}
static struct iso_tree_node_boot_catalog*
create_boot_catalog_node(struct iso_tree_node_dir *parent,
const char *name)
{
struct iso_tree_node_boot_catalog *boot;
assert( parent && name );
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog));
boot->node.attrib.st_mode = S_IFREG | 0444;
boot->node.attrib.st_atime =
boot->node.attrib.st_mtime =
boot->node.attrib.st_ctime = time(NULL);
boot->node.type = LIBISO_NODE_BOOTCATALOG;
boot->node.name = strdup(name);
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
return boot;
}
struct el_torito_boot_image *
iso_volume_create_boot_catalog(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name)
{
struct el_torito_boot_image *boot_image;
struct iso_tree_node_boot_catalog *boot_node;
struct el_torito_boot_catalog *catalog;
assert( volume && !volume->bootcat);
assert( image && ISO_ISREG(image) && dir && name);
boot_image = create_image(image, type);
if ( !boot_image )
return NULL;
/* creates the catalog with the given default image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
catalog->nentries = 1;
catalog->entries = malloc(sizeof(struct el_torito_boot_image *));
catalog->entries[0] = boot_image;
catalog->file = malloc(sizeof(struct iso_file));
catalog->file->size = 2048;
/* add catalog file */
boot_node = create_boot_catalog_node(dir, name);
boot_node->catalog = catalog;
volume->bootcat = catalog;
return boot_image;
}
void
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment)
{
if (bootimg->type != ELTORITO_NO_EMUL)
return;
bootimg->load_seg = segment;
}
void
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors)
{
if (bootimg->type != ELTORITO_NO_EMUL)
return;
bootimg->load_size = sectors;
}
void
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
{
bootimg->bootable = 0;
}
void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg)
{
bootimg->patch_isolinux = 1;
}
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
{
size_t i;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
free(cat->entries[i]);
}
free(cat->entries);
free(cat->file);
free(cat);
}
void el_torito_get_image_files(struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
struct iso_tree_node_file *image = cat->entries[i]->image;
struct iso_file *file = iso_file_table_lookup(t->file_table, image);
if ( file == NULL ) {
file = iso_file_new(image);
iso_file_table_add_file(t->file_table, file);
}
cat->entries[i]->file = file;
}
}
/**
* Write the Boot Record Volume Descriptor
*/
static void
write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct el_torito_boot_catalog *cat = t->catalog;
struct ecma119_boot_rec_vol_desc *vol =
(struct ecma119_boot_rec_vol_desc*)buf;
assert(cat);
vol->vol_desc_type[0] = 0;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
iso_lsb(vol->boot_catalog, cat->file->block, 4);
}
static void
write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
{
size_t i;
int checksum;
struct el_torito_validation_entry *ve =
(struct el_torito_validation_entry*)buf;
ve->header_id[0] = 1;
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
ve->key_byte1[0] = 0x55;
ve->key_byte2[0] = 0xAA;
/* calculate the checksum, to ensure sum of all words is 0 */
checksum = 0;
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
checksum -= buf[i];
checksum -= (buf[i] << 8);
}
iso_lsb(ve->checksum, checksum, 2);
}
static void
patch_boot_file(struct el_torito_boot_image *img)
{
struct boot_info_table info;
int fd;
uint32_t checksum;
ssize_t len;
uint8_t buf[4];
memset(&info, 0, sizeof(info));
/* open image */
fd = open(img->image->path, O_RDWR);
if ( fd == -1 ) {
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
close(fd);
return;
}
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
lseek(fd, (off_t) 64, SEEK_SET);
//TODO this can (must) be optimizied by reading to a longer buffer
while ( (len = read(fd, buf, 4) ) == 4 ) {
checksum += iso_read_lsb(buf, 4);
}
if ( len != 0 ) {
/* error reading file, or file length not multiple of 4 */
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
close(fd);
return;
}
/* fill boot info table */
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms
iso_lsb(info.bi_file, img->file->block, 4);
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4);
iso_lsb(info.bi_csum, checksum, 4);
/* patch file */
lseek(fd, (off_t) 8, SEEK_SET);
write(fd, &info, sizeof(info));
close(fd);
}
void
el_torito_patch_image_files(struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
for (i = 0; i < cat->nentries; ++i) {
struct el_torito_boot_image *img = cat->entries[i];
if ( img->patch_isolinux )
patch_boot_file(img);
}
}
/**
* Write one section entry.
* Currently this is used for both default and other entries since we
* put selection criteria no 0 (no sel. criteria)
*/
static void
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img)
{
struct el_torito_section_entry *se =
(struct el_torito_section_entry*)buf;
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
se->boot_media_type[0] = img->type;
iso_lsb(se->load_seg, img->load_seg, 2);
se->system_type[0] = 0; //TODO need to get the partition type
iso_lsb(se->sec_count, img->load_size, 2);
iso_lsb(se->block, img->file->block, 4);
}
/**
* Write El-Torito Boot Catalog
*/
static void
write_catalog(struct ecma119_write_target *t, uint8_t *buf)
{
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
assert(cat->nentries >= 1 && cat->nentries < 63);
write_validation_entry(t, buf);
/* write default entry */
write_section_entry(buf + 32, cat->entries[0]);
//TODO write all images
}
void
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
assert(t->catalog);
ecma119_start_chunking(t,
write_boot_vol_desc,
2048,
buf);
}
void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf)
{
assert(t->catalog);
ecma119_start_chunking(t,
write_catalog,
2048,
buf);
}

View File

@ -1,60 +0,0 @@
#ifndef ELTORITO_H_
#define ELTORITO_H_
#include "tree.h"
#include "file.h"
#include "ecma119.h"
/**
* Location of the boot catalog
*/
struct iso_tree_node_boot_catalog
{
struct iso_tree_node node;
struct el_torito_boot_catalog *catalog;
};
struct el_torito_boot_catalog {
int nentries;
struct el_torito_boot_image **entries;
struct iso_file *file; /**< The catalog file */
};
struct el_torito_boot_image {
unsigned char bootable; /**< If the entry is bootable. */
unsigned char patch_isolinux; /**< If the image will be patched */
unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */
short load_size; /**< Number of sector to load. */
struct iso_tree_node_file *image;
struct iso_file *file;
};
/*struct el_torito_boot_entry *
el_torito_add_boot_entry(struct el_torito_boot_catalog *cat,
struct iso_tree_node_file *image);
*/
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
/**
* For each boot image file, this gets the related iso_file object.
* In most cases, the file is already in the hash table. However, if the
* boot record is hidden in both ISO/RR and joliet trees, this ensures
* that boot images will be written to image.
*/
void el_torito_get_image_files(struct ecma119_write_target *t);
/**
* Patch image files if selected. This is needed for isolinux boot images
*/
void el_torito_patch_image_files(struct ecma119_write_target *t);
void
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf);
#endif /*ELTORITO_H_*/

View File

@ -1,38 +1,42 @@
#include "hash.h"
#include "exclude.h"
static struct iso_hash_node *table[HASH_NODES]={0,};
static int num=0;
void
iso_exclude_add_path(struct iso_hash_table *table, const char *path)
iso_exclude_add_path(const char *path)
{
if (!path)
return;
table->num += iso_hash_insert(table->table, path);
num += iso_hash_insert(table, path);
}
/*void
iso_exclude_remove_path(struct iso_hash_table *table, const char *path)
void
iso_exclude_remove_path(const char *path)
{
if (!table->num || !path)
if (!num || !path)
return;
table->num -= iso_hash_remove(table->table, path);
}*/
num -= iso_hash_remove(table, path);
}
void
iso_exclude_empty(struct iso_hash_table *table)
iso_exclude_empty(void)
{
if (!table->num)
if (!num)
return;
iso_hash_empty(table->table);
table->num=0;
iso_hash_empty(table);
num=0;
}
int
iso_exclude_lookup(struct iso_hash_table *table, const char *path)
iso_exclude_lookup(const char *path)
{
if (!table->num || !path)
if (!num || !path)
return 0;
return iso_hash_lookup(table->table, path);
return iso_hash_lookup(table, path);
}

View File

@ -1,37 +1,12 @@
#ifndef ISO_EXCLUDE_H
#define ISO_EXCLUDE_H
#include "hash.h"
struct iso_hash_table {
struct iso_hash_node *table[HASH_NODES];
int num;
};
/**
* 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(struct iso_hash_table *table, 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(struct iso_hash_table *table, 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(struct iso_hash_table *table, const char *path);
/**
* Remove all paths that were set to be ignored when adding a directory recusively.
*/
void iso_exclude_empty(struct iso_hash_table *table);
int
iso_exclude_lookup(const char *path);
#endif /* ISO_EXCLUDE */

View File

@ -1,188 +0,0 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "file.h"
#include "tree.h"
//TODO: refactor both hash and this hash table into a single one!!
struct iso_file *
iso_file_new(struct iso_tree_node_file *f)
{
struct iso_file *file = calloc(1, sizeof(struct iso_file));
file->path = f->path; /*TODO strdup? it needs to be free on clear then */
file->size = f->node.attrib.st_size;
file->nlink = 1;
file->real_dev = f->node.attrib.st_dev;
file->real_ino = f->node.attrib.st_ino;
file->sort_weight = f->sort_weight;
return file;
}
static unsigned int
iso_file_table_hash(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 % FILE_HASH_NODES;
}
static inline unsigned int
iso_file_table_hash_inode(dev_t dev, ino_t ino)
{
return (dev ^ ino) % FILE_HASH_NODES;
}
struct iso_file_table*
iso_file_table_new(int cache_inodes)
{
struct iso_file_table *table = calloc(1, sizeof(struct iso_file_table));
table->cache_inodes = cache_inodes;
return table;
}
static struct iso_file_hash_node *
iso_file_table_node_new(struct iso_file *file)
{
struct iso_file_hash_node *node;
node = calloc(1, sizeof(struct iso_file_hash_node) );
node->file = file;
return node;
}
static void
iso_file_table_node_free(struct iso_file_hash_node *node)
{
free(node->file);
free(node);
}
void
iso_file_table_clear(struct iso_file_table *ft)
{
int i;
for (i=0; i < FILE_HASH_NODES; i++) {
struct iso_file_hash_node *node;
node=ft->table[i];
if (!node)
continue;
ft->table[i] = NULL;
do {
struct iso_file_hash_node *next;
next = node->next;
iso_file_table_node_free(node);
node = next;
} while (node);
}
ft->count = 0;
}
/**
* return 0 if equal, != 0 if not
*/
static int
iso_table_compare_files(struct iso_file_table *ft,
struct iso_file *f1, struct iso_file *f2)
{
if (ft->cache_inodes) {
return (f1->real_dev != f2->real_dev) || (f1->real_ino != f2->real_ino);
} else {
return strcmp(f1->path, f2->path);
}
}
int
iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
{
struct iso_file_hash_node *node;
unsigned int hash_num;
/* find the hash number */
if (ft->cache_inodes)
hash_num = iso_file_table_hash_inode(f->real_dev, f->real_ino);
else
hash_num = iso_file_table_hash(f->path);
/* insert it */
node = ft->table[hash_num];
/* unfortunately, we can't safely consider that a file
* won't be twice in the hash table so make sure it
* doesn't already exists */
if (!node) {
ft->table[hash_num]=iso_file_table_node_new(f);
ft->count++;
return 1;
}
/* if it's already in, we don't do anything */
if (!iso_table_compare_files(ft, f, node->file))
return 0;
while (node->next) {
node = node->next;
/* if it's already in, we don't do anything */
if (!iso_table_compare_files(ft, f, node->file))
return 0;
}
node->next = iso_file_table_node_new(f);
ft->count++;
return 1;
}
struct iso_file *
iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
{
struct iso_file_hash_node *node;
unsigned int hash_num;
int equal;
/* find the hash number */
if ( ft->cache_inodes )
hash_num = iso_file_table_hash_inode(f->node.attrib.st_dev,
f->node.attrib.st_ino);
else
hash_num = iso_file_table_hash(f->path);
node = ft->table[hash_num];
if (!node)
return NULL;
equal = ft->cache_inodes ?
((f->node.attrib.st_dev == node->file->real_dev)
&& (f->node.attrib.st_ino == node->file->real_ino))
: !strcmp(f->path, node->file->path);
if (equal)
return node->file;
while (node->next) {
node = node->next;
equal = ft->cache_inodes ?
((f->node.attrib.st_dev == node->file->real_dev)
&& (f->node.attrib.st_ino == node->file->real_ino))
: !strcmp(f->path, node->file->path);
if (equal)
return node->file;
}
return NULL;
}

View File

@ -1,69 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file file.h
*
* Declare the structs to keep track of the files to be written into image.
* These files are stored in a hash table. Two modes of operation are supported:
* when cache inodes is enabled, the files are indexed into the table by the
* device and inode id in the local filesystem. This way, two different files
* with same inode and device id are treated as if they were a single file.
* This is usually the correct behavior, as a different file with same inode
* and device used to be a hard link.
* When cache inode is disabled, indexing is done by path on local filesystem.
*/
#ifndef FILE_H_
#define FILE_H_
#define FILE_HASH_NODES 2048
struct iso_file {
char *path; /**< Path of the file on local filesystem */
off_t size; /**< size of this file */
ino_t ino; /**< This will be the inode number on CD of the file (RR) */
nlink_t nlink; /**< Number of hard links of the file on CD (RR) */
size_t block; /**< Block where this file is to be written on image */
dev_t real_dev;
ino_t real_ino; /**< for lookup by inode caching */
int sort_weight;
};
struct iso_file_hash_node {
struct iso_file_hash_node *next;
struct iso_file *file;
};
struct iso_file_table {
struct iso_file_hash_node *table[FILE_HASH_NODES];
size_t count;
int cache_inodes; /**< 1 to index by inode number */
};
struct iso_tree_node_file;
/**
* Create a struct that represents the specified iso_tree_node_file,
* suitable to be stored into the table,
*/
struct iso_file *iso_file_new(struct iso_tree_node_file*);
struct iso_file_table *iso_file_table_new(int cache_inodes);
/**
* Clear a hash table. All iso_file structs stored will also be freed,
* but not the path of each iso_file
*/
void iso_file_table_clear(struct iso_file_table *ft);
/**
* Add a new file to the table.
* \return 1 if the file is added, 0 if the file already exist on table
*/
int iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f);
struct iso_file *iso_file_table_lookup(struct iso_file_table *ft,
struct iso_tree_node_file *f);
#endif /*FILE_H_*/

View File

@ -7,7 +7,6 @@
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "eltorito.h"
#include <assert.h>
#include <string.h>
@ -20,75 +19,33 @@ create_node(struct ecma119_write_target *t,
struct joliet_tree_node *ret =
calloc(1, sizeof(struct joliet_tree_node));
ret->name = iso_j_id(iso->name, t->input_charset);
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;
if ( ISO_ISDIR(iso) ) {
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *) iso;
ret->info.dir.children = calloc(sizeof(void*), dir->nchildren);
ret->type = JOLIET_DIR;
} else if (ISO_ISREG(iso)) {
/* it's a file */
struct iso_tree_node_file *iso_f = (struct iso_tree_node_file *) iso;
struct iso_file *file;
file = iso_file_table_lookup(t->file_table, iso_f);
if ( file == NULL ) {
file = iso_file_new(iso_f);
iso_file_table_add_file(t->file_table, file);
}
ret->info.file = file;
ret->type = JOLIET_FILE;
} else {
/* it's boot catalog info */
struct iso_tree_node_boot_catalog *iso_b =
(struct iso_tree_node_boot_catalog *) iso;
struct iso_file *file;
file = iso_b->catalog->file;
ret->info.file = file;
ret->type = JOLIET_FILE;
}
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)
{
struct joliet_tree_node *root;
assert(t && iso);
if ( iso->hide_flags & LIBISO_HIDE_ON_JOLIET )
return NULL;
switch (iso->type) {
case LIBISO_NODE_FILE:
case LIBISO_NODE_BOOTCATALOG:
root = create_node(t, parent, iso);
break;
case LIBISO_NODE_DIR:
{
size_t i;
struct joliet_tree_node *node;
struct iso_tree_node_dir *dir;
root = create_node(t, parent, iso);
dir = (struct iso_tree_node_dir*)iso;
for (i = 0; i < dir->nchildren; ++i) {
node = create_tree(t, root, dir->children[i]);
if ( node != NULL ) {
root->info.dir.children[root->info.dir.nchildren++] = node;
}
}
}
break;
default:
//TODO replace this printf
printf("Can't add this kind of node to a Joliet tree");
return NULL;
break;
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;
}
@ -106,15 +63,12 @@ sort_tree(struct joliet_tree_node *root)
{
size_t i;
assert(root && (root->type == JOLIET_DIR));
assert(root && ISO_ISDIR(root->iso_self));
qsort(root->info.dir.children, root->info.dir.nchildren,
sizeof(void*), cmp_node);
for (i = 0; i < root->info.dir.nchildren; i++) {
struct joliet_tree_node *child = root->info.dir.children[i];
if ( child->type == JOLIET_DIR )
sort_tree(child);
}
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
@ -126,11 +80,11 @@ joliet_prepare_path_tables(struct ecma119_write_target *t)
t->path_table_size_joliet = 10; /* root directory record */
cur = 1;
for (i = 0; i < t->dirlist_len_joliet; i++) {
for (i = 0; i < t->dirlist_len; i++) {
struct joliet_tree_node *dir = t->pathlist_joliet[i];
for (j = 0; j < dir->info.dir.nchildren; j++) {
struct joliet_tree_node *ch = dir->info.dir.children[j];
if (ch->type == JOLIET_DIR) {
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;
@ -147,25 +101,18 @@ joliet_calc_dir_size(struct ecma119_write_target *t,
struct joliet_tree_node *root)
{
size_t i;
size_t newlen;
struct joliet_tree_node *ch;
assert(root && (root->type == JOLIET_DIR) );
assert(root && ISO_ISDIR(root->iso_self));
t->dirlist_len_joliet++;
root->info.dir.len = 68; /* for "." and ".." entries */
for (i = 0; i < root->info.dir.nchildren; ++i) {
ch = root->info.dir.children[i];
newlen = root->info.dir.len + ch->dirent_len;
if ((newlen % 2048) < (root->info.dir.len % 2048)) {
root->info.dir.len = newlen + (2048 - (root->info.dir.len % 2048));
} else {
root->info.dir.len += ch->dirent_len;
}
if (ch->type == JOLIET_DIR)
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->info.dir.len, t->block_size);
t->total_dir_size_joliet += round_up (root->len, t->block_size);
}
/**
@ -178,17 +125,45 @@ joliet_calc_dir_pos(struct ecma119_write_target *t,
size_t i;
struct joliet_tree_node *ch;
assert(root && (root->type == JOLIET_DIR));
assert(root && ISO_ISDIR(root->iso_self));
root->info.dir.block = t->curblock;
t->curblock += div_up(root->info.dir.len, t->block_size);
root->block = t->curblock;
t->curblock += div_up(root->len, t->block_size);
t->dirlist_joliet[t->curfile++] = root;
for (i = 0; i < root->info.dir.nchildren; i++) {
ch = root->info.dir.children[i];
if (ch->type == JOLIET_DIR)
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*
@ -201,21 +176,6 @@ joliet_tree_create(struct ecma119_write_target *t,
return root;
}
void
joliet_tree_free(struct joliet_tree_node *root)
{
size_t i;
if (root->type == JOLIET_DIR) {
for (i=0; i < root->info.dir.nchildren; i++) {
joliet_tree_free(root->info.dir.children[i]);
}
free(root->info.dir.children);
}
free(root->name);
free(root);
}
/* ugh. this is mostly C&P */
static void
write_path_table(struct ecma119_write_target *t,
@ -225,7 +185,7 @@ write_path_table(struct ecma119_write_target *t,
void (*write_int)(uint8_t*, uint32_t, int) = l_type ?
iso_lsb : iso_msb;
size_t i;
size_t i;
struct ecma119_path_table_record *rec;
struct joliet_tree_node *dir;
int parent = 0;
@ -242,7 +202,7 @@ write_path_table(struct ecma119_write_target *t,
rec->len_di[0] = dir->parent ?
(uint8_t) ucslen(dir->name) * 2 : 1;
rec->len_xa[0] = 0;
write_int(rec->block, dir->info.dir.block, 4);
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]);
@ -260,31 +220,20 @@ write_one_dir_record(struct ecma119_write_target *t,
int file_id,
uint8_t *buf)
{
uint32_t len;
uint32_t block;
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 (node->type == JOLIET_DIR) {
len = node->info.dir.len;
block = node->info.dir.block;
} else {
/* file */
len = node->info.file->size;
block = node->info.file->block;
}
if (file_id == 1 && node->parent)
node = node->parent;
rec->len_dr[0] = len_dr;
iso_bb(rec->block, block, 4);
iso_bb(rec->length, len, 4);
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] = (node->type == JOLIET_DIR) ? 2 : 0;
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);
@ -307,29 +256,19 @@ 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, t->input_charset);
uint16_t *pub_id = str2ucs(volume->publisher_id, t->input_charset);
uint16_t *data_id = str2ucs(volume->data_preparer_id, t->input_charset);
uint16_t *volset_id = str2ucs(t->volset->volset_id, t->input_charset);
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);
uint16_t *system_id = str2ucs(volume->system_id, t->input_charset);
uint16_t *application_id = str2ucs(volume->application_id, t->input_charset);
uint16_t *copyright_file_id = str2ucs(volume->copyright_file_id, t->input_charset);
uint16_t *abstract_file_id = str2ucs(volume->abstract_file_id, t->input_charset);
uint16_t *biblio_file_id = str2ucs(volume->biblio_file_id, t->input_charset);
int system_id_len = MIN(32, ucslen(system_id) * 2);
int application_id_len = MIN(128, ucslen(application_id) * 2);
int copyright_file_id_len = MIN(37, ucslen(copyright_file_id) * 2);
int abstract_file_id_len = MIN(37, ucslen(abstract_file_id) * 2);
int biblio_file_id_len = MIN(37, ucslen(biblio_file_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);
@ -346,13 +285,8 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
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->system_id, system_id, system_id_len);
memcpy(vol->application_id, "APPID", application_id_len);
memcpy(vol->copyright_file_id, copyright_file_id, copyright_file_id_len);
memcpy(vol->abstract_file_id, abstract_file_id, abstract_file_id_len);
memcpy(vol->bibliographic_file_id, biblio_file_id, biblio_file_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);
@ -362,11 +296,6 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
free(volset_id);
free(pub_id);
free(data_id);
free(system_id);
free(application_id);
free(copyright_file_id);
free(abstract_file_id);
free(biblio_file_id);
}
@ -376,12 +305,9 @@ write_one_dir(struct ecma119_write_target *t,
uint8_t *buf)
{
size_t i;
int j;
size_t len;
uint8_t *orig_buf = buf;
uint8_t *prior_buf = buf;
assert(dir->type == JOLIET_DIR);
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];
@ -389,23 +315,12 @@ write_one_dir(struct ecma119_write_target *t,
write_one_dir_record(t, dir, 1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
for (i = 0; i < dir->info.dir.nchildren; i++) {
write_one_dir_record(t, dir->info.dir.children[i], -1, buf);
len = ((struct ecma119_dir_record*) buf)->len_dr[0];
if ((buf + len - prior_buf) >= 2048) {
for (j = len - 1; j >= 0; j--) {
prior_buf[2048 + j] = buf[j];
buf[j] = 0;
}
prior_buf += 2048;
buf = prior_buf + len;
}
else {
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->info.dir.len);
assert (buf - orig_buf == dir->len);
}
static void
@ -414,11 +329,11 @@ 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]->info.dir.block);
for (i = 0; i < t->dirlist_len_joliet; i++) {
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->info.dir.len, t->block_size);
buf += round_up(dir->len, t->block_size);
}
}

View File

@ -17,31 +17,19 @@
struct ecma119_write_target;
struct iso_tree_node;
enum joliet_node_type {
JOLIET_FILE,
JOLIET_DIR
};
struct joliet_dir_info {
struct joliet_tree_node **children;
size_t nchildren;
size_t len;
size_t block;
};
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;
enum joliet_node_type type;
union {
struct iso_file *file;
struct joliet_dir_info dir;
} info;
struct joliet_tree_node **children;
size_t nchildren;
};
/**
@ -64,6 +52,13 @@ joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
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.

View File

@ -12,8 +12,6 @@
#ifndef LIBISO_LIBISOFS_H
#define LIBISO_LIBISOFS_H
#include <sys/types.h>
/* #include <libburn.h> */
struct burn_source;
@ -35,156 +33,11 @@ struct iso_volset;
*/
struct iso_tree_node;
/**
* El-Torito boot image
* \see eltorito.h
*/
struct el_torito_boot_image;
/**
* A directory in the filesystem tree.
* The first member of this is an iso_tree_node.
* \see tree.h
*/
struct iso_tree_node_dir;
/**
* Extensions addition to ECMA-119 (ISO-9660) image. Usage of at least
* one of these flags is highly recommended if the disc will be used on a
* modern OS.
*/
enum ecma119_extension_flag {
/**
* Add the standard Rock Ridge extensions. This adds POSIX filesystem
* features to the ECMA-119 image. Thus, usage of this flag is highly
* recommended for images used on GNU/Linux systems. With the usage
* of RR extension, the resulting image will have long filenames (up to
* 255 characters), deeper directory structure, POSIX permissions and
* owner info on files and directories, support for symbolic links or
* special files... All that attributes can be modified/setted with the
* appropiate function.
*/
ECMA119_ROCKRIDGE = (1<<0),
/**
* Add the non-standard Joliet extension to the image. This extension is
* heavily used in Microsoft Windows systems, so if you plan to use your
* disc on such a system you should add this extension. Usage of Joliet
* supplies longer filesystem length (up to 64 unicode characters), and
* deeper directory structure.
*/
ECMA119_JOLIET = (1<<1)
};
/**
* Flag used to hide a file in the RR/ISO or Joliet tree.
*
* \see iso_tree_node_set_hidden
*/
enum hide_node_flag {
LIBISO_HIDE_ON_RR = 1 << 0,
LIBISO_HIDE_ON_JOLIET = 1 << 1
};
/**
* El-Torito bootable image type.
*/
enum eltorito_boot_media_type {
ELTORITO_FLOPPY_EMUL,
ELTORITO_HARD_DISC_EMUL,
ELTORITO_NO_EMUL
};
enum ecma119_relaxed_constraints_flag {
ECMA119_OMIT_VERSION_NUMBERS = (1<<0),
/* 37 char filenames involves no version number */
ECMA119_37_CHAR_FILENAMES = (1<<1) | (1<<0),
ECMA119_NO_DIR_REALOCATION = (1<<2),
ECMA119_RELAXED_FILENAMES = (1<<3)
};
/**
* Holds the options for the image generation.
*/
struct ecma119_source_opts {
int volnum; /**< The volume in the set which you want to write (usually 0) */
int level; /**< ISO level to write at. */
int flags; /**< Which extensions to support. */
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
unsigned int no_cache_inodes:1;
/**< If use inode caching or not. Set it to 1 to prevent
* inode caching.
* Usage of inode caching allows detection of hard-links,
* which contents are only written once to disc this way.
* Don't use inode caching in systems with non unique inodes
* per device.
*/
unsigned int sort_files:1;
/**< If files should be sorted based on their weight. */
unsigned int default_mode:1;
/**<
* The default values for files and directory permissions,
* gid and uid. This option can be overwritten when set
* one of the following.
* 0 to use useful values, 1 to use node modes (this are
* the same as filesystem ones if not changed after added
* to tree).
*/
unsigned int replace_dir_mode:1;
/**<
* When 1, permissions for all dirs will be replaced by the
* specified in dir_mode field.
*/
unsigned int replace_file_mode:1;
/**<
* When 1, permissions for all files will be replaced by the
* specified in file_mode field.
*/
unsigned int replace_uid:1;
/**<
* When 1, uid of all nodes (both files and dirs) will be
* replaced by the specified in uid field.
*/
unsigned int replace_gid:1;
/**<
* When 1, gid of all nodes (both files and dirs) will be
* replaced by the specified in gid field.
*/
mode_t dir_mode; /**< Mode to use on dirs when replace_dir_mode is set. */
mode_t file_mode; /**< Mode to use on files when replace_file_mode is set. */
gid_t gid; /**< gid to use when replace_gid is set. */
uid_t uid; /**< uid to use when replace_uid is set. */
char *input_charset; /**< NULL to use default charset */
char *ouput_charset; /**< NULL to use default charset */
};
/**
* This will hold the error code for some functions, if them fail.
*/
int libisofs_errno;
/* an unexpected internal error */
#define INTERNAL_ERROR -1
/* file don't exists, or can't be stat'ed */
#define NO_FILE 1
/* user haven't read access to file */
#define NO_READ_ACCESS 2
/* unexpected file type, eg., passing a dir instead of a regular file */
#define UNEXPECTED_FILE_TYPE 3
/* invalid boot image size */
#define ELTORITO_WRONG_IMAGE_SIZE 4
/**
* Controls the bahavior of iso_tree_radd_dir function
*/
struct iso_tree_radd_dir_behavior {
char** excludes; /**< List of paths (file or directory) to be ignored. */
//int follow_sym_link;
int stop_on_error; /**< Stop when an error was found?. */
int error; /**< set to 1 on error */
//int notify_errors;
//char** errors;
};
/**
* Create a new volume.
* The parameters can be set to NULL if you wish to set them later.
@ -196,7 +49,7 @@ struct iso_volume *iso_volume_new(const char *volume_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_dir *root);
struct iso_tree_node *root);
/**
* Free a volume.
@ -211,7 +64,7 @@ void iso_volset_free(struct iso_volset *volume);
/**
* Get the root directory for a volume.
*/
struct iso_tree_node_dir *iso_volume_get_root(const struct iso_volume *volume);
struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume);
/**
* Fill in the volume identifier for a volume.
@ -231,104 +84,6 @@ void iso_volume_set_publisher_id(struct iso_volume *volume,
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id);
/**
* Fill in the system id for a volume. Up to 32 characters.
*/
void iso_volume_set_system_id(struct iso_volume *volume,
const char *system_id);
/**
* Fill in the application id for a volume. Up to 128 chars.
*/
void iso_volume_set_application_id(struct iso_volume *volume,
const char *application_id);
/**
* Fill copyright information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
*/
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
const char *copyright_file_id);
/**
* Fill abstract information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
*/
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
const char *abstract_file_id);
/**
* Fill biblio information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
*/
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
const char *biblio_file_id);
/**
* Create a bootable volume by adding a El-Torito boot image.
*
* \param volume The volume to make bootable.
* \param image The tree node with the file to use as default boot image.
* \param type The boot media type. This can be one of 3 types:
* - Floppy emulation: Boot image files must be exactly
* 1200 kB, 1440 kB or 2880 kB.
* - Hard disc emulation: The image must begin with a master
* boot record with a single image.
* - No emulation. You should specify load segment and load size
* of image.
* \param dir The directory node where the boot catalog will be located
* in image. Usually both boot catalog and boot image will be
* located in the same dir, maybe /boot.
* \param name The name of the boot catalog.
*
* \return The default El-Torito bootable image. If specified image file
* seems to be not correct, this returns NULL and libisofs_errno
* is set propertly.
*
* \pre \p volume is a volume without any boot catalog yet
* \pre \p image is a file tree node already inserted in the volume tree.
* \pre \p dir is a directory node already inserted in the volume tree.
* \pre \p name There isn't any dir child with the same name.
*
*/
struct el_torito_boot_image *
iso_volume_create_boot_catalog(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name);
/**
* Sets the load segment for the initial boot image. This is only for
* no emulation boot images, and is a NOP for other image types.
*/
void
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment);
/**
* Sets the number of sectors (512b) to be load at load segment during
* the initial boot procedure. This is only for
* no emulation boot images, and is a NOP for other image types.
*/
void
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors);
/**
* Marks the specified boot image as not bootable
*/
void
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg);
/**
* Specifies that this image needs to be patched. This involves the writting
* of a 56 bytes boot information table at offset 8 of the boot image file.
* Be aware that libisofs will modify original boot image file, so do a backup
* if needed.
* This is needed for isolinux boot images.
*/
void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
/**
* Locate a node by its path on disc.
*
@ -337,8 +92,6 @@ el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
*
* \return The node found or NULL.
*
* TODO we need a way to allow developers know which kind of node is.
* Think about this when designing the read api
*/
struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
@ -351,9 +104,9 @@ struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, co
*
* \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);
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.
@ -363,8 +116,8 @@ struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, co
*
* \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);
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.
@ -375,47 +128,59 @@ struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, co
struct iso_volset *iso_volset_new(struct iso_volume *volume,
const char *volset_id);
/**
* Creates a new root dir for a filesystem tree
*/
struct iso_tree_node_dir *iso_tree_new_root();
/**
* Add a file to a directory.
*
* \param path The path, on the local filesystem, of the file.
*
* \pre \p parent is non-NULL.
* \pre \p path is non-NULL.
* \return An iso_tree_node_file whose path is \p path and whose parent is
* \p parent.
* On error, returns NULL and libisofs_errno is set appropriately:
* NO_FILE if path doesn't point to a valid file.
* NO_READ_ACCESS if user haven't read access on file
* UNEXPECTED_FILE_TYPE if path doesn't point to a regular 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_file(struct iso_tree_node_dir *parent,
struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent,
const char *path);
/**
* Add a symbolic link to a directory.
*
* \param name The name of the symbolic link
* \param dest The distination of the link, i.e., the file this link points
* to
*
* \pre \p parent, name and dest are non-NULL.
*
* \return An iso_tree_node_symlink
* 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_add_symlink(struct iso_tree_node_dir *parent,
const char *name, const char *dest);
struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent,
const char *path);
/**
* Add a new, empty directory to the tree.
* Add the path of a file or directory to ignore when adding a directory recursively.
*
* \pre \p parent is non-NULL.
* \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.
*
@ -423,101 +188,13 @@ struct iso_tree_node *iso_tree_add_symlink(struct iso_tree_node_dir *parent,
* POSIX attributes are the same as \p parent's.
* \return a pointer to the newly created directory.
*/
struct iso_tree_node_dir *iso_tree_add_dir(struct iso_tree_node_dir *parent,
const char *name);
/* TODO iso_tree_new_special */
struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent,
const char *name);
/**
* Add a file to a directory.
*
* \param path The path, on the local filesystem, of the file.
*
* \pre \p parent is non-NULL.
* \pre \p path is non-NULL and is a valid path to a file or directory on the local
* filesystem.
* \return An iso_tree_node whose path is \p path and whose parent is \p parent.
* On error, returns NULL and libisofs_errno is set appropriately:
* NO_FILE if path doesn't point to a valid file.
* NO_READ_ACCESS if user haven't read access on file
* UNEXPECTED_FILE_TYPE if path refers to non supported file type
* (at the momment, only dirs, symlinks and regular
* files are supported).
* Set the name of a file (using the current locale).
*/
struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *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, iso_tree_add_node and iso_tree_add_dir.
*
* \param path The path, on the local filesystem, of the directory to add.
*
* \pre \p parent is non-NULL.
* \pre \p path is non-NULL and is a valid path to a directory on the local
* filesystem.
*/
void iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior);
/**
* Set the name of a tree node (using the current locale).
*/
void iso_tree_node_set_name(struct iso_tree_node *node, const char *name);
/**
* Set if the node will be hidden in RR/ISO tree, Joliet tree or both.
*
* If the file is setted as hidden in one tree, it won't be included there, so
* it won't be visible in a OS accessing CD using that tree. For example,
* GNU/Linux systems access to Rock Ridge / ISO9960 tree in order to see
* what is recorded on CD, while MS Windows make use of the Joliet tree. If a
* file is hidden only in Joliet, it won't be visible in Windows systems,
* while still visible in Linux.
*
* If a file is hidden in both trees, it won't be written to image.
*
* \param node The node that is to be hidden.
* \param hide_attrs hide_node_flag's to set the trees in which file
* will be hidden.
*/
void iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs);
/**
* Set the group id for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
*/
void iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid);
/**
* Set the user id for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
*/
void iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid);
/**
* Set the permissions for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
*
* \param mode bitmask with the permissions of the node, as specified
* in 'man 2 stat'. The file type bitfields will be ignored,
* only file permissions will be modified.
*/
void iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode);
/**
* Sets the order in which a node will be written on image. High weihted files
* will be written first, so in a disc them will be written near the center.
*
* \param node The node which weight will be changed. If it's a dir, this
* function will change the weight of all its children. For nodes
* other that dirs or regular files, this function has no effect.
* \param w The weight as a integer number, the greater this value is, the
* closer from the begining of image the file will be written.
*/
void iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w);
void iso_tree_node_set_name(struct iso_tree_node *file, const char *name);
/**
* Recursively print a directory to stdout.
@ -532,13 +209,17 @@ void iso_tree_print(const struct iso_tree_node *root, int spaces);
* until the libburn_source is freed.
*
* \param volumeset The volume set from which you want to write
* \param opts The options for image generation
* \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,
struct ecma119_source_opts *opts);
struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset,
int volnum,
int level,
int flags);
#endif /* LIBISO_LIBISOFS_H */

View File

@ -14,30 +14,6 @@
#include <unistd.h>
#include <sys/stat.h>
/** 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->info.dir.self_susp, ER);
}
/* 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)
@ -48,11 +24,11 @@ uint8_t *rrip_make_PX(struct ecma119_write_target *t,
PX[1] = 'X';
PX[2] = 44;
PX[3] = 1;
iso_bb(&PX[4], node->attrib.st_mode, 4);
iso_bb(&PX[12], node->attrib.st_nlink, 4);
iso_bb(&PX[20], node->attrib.st_uid, 4);
iso_bb(&PX[28], node->attrib.st_gid, 4);
iso_bb(&PX[36], node->attrib.st_ino, 4);
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;
}
@ -61,8 +37,8 @@ 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->info.dir.self_susp, rrip_make_PX(t, node));
susp_append(t, &node->info.dir.parent_susp, rrip_make_PX(t, node));
susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node));
susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node));
}
}
@ -74,8 +50,8 @@ void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
PN[1] = 'N';
PN[2] = 20;
PN[3] = 1;
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4);
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4);
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);
}
@ -126,7 +102,7 @@ static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
int path_size;
int ret, pathsize = 0;
char *path = NULL, *cur, *prev;
int i, j;
@ -137,9 +113,19 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
uint8_t *SL;
path = node->info.dest;
path_size = strlen(path);
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);
@ -148,8 +134,8 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
}
/* if there was no trailing '/', we need to add the last component. */
if (prev == path || prev != &path[path_size - 1]) {
rrip_SL_add_component(prev, &path[path_size], &n_comp, &comp);
if (prev == path || prev != &path[ret - 1]) {
rrip_SL_add_component(prev, &path[ret], &n_comp, &comp);
}
for (i = 0; i < n_comp; i++) {
@ -186,6 +172,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
}
susp_append(t, &node->susp, SL);
free(path);
/* free the components */
for (i = 0; i < n_comp; i++) {
free(comp[i]);
@ -213,7 +200,7 @@ static void rrip_add_NM_single(struct ecma119_write_target *t,
void
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
char *name = node->full_name;
char *name = iso_p_fileid(node->iso_self->name);
int len = name ? strlen(name) : 0;
char *pos = name;
@ -221,8 +208,8 @@ rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
return;
if (node->type == ECMA119_DIR) {
rrip_add_NM_single(t, &node->info.dir.self_susp, pos, 0, 1 << 1);
rrip_add_NM_single(t, &node->info.dir.parent_susp, pos, 0, 1 << 2);
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) {
@ -253,7 +240,7 @@ rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
PL[1] = 'L';
PL[2] = 12;
PL[3] = 1;
susp_append(t, &node->info.dir.parent_susp, PL);
susp_append(t, &node->dir.parent_susp, PL);
}
void
@ -277,10 +264,10 @@ rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
TF[1] = 'F';
TF[2] = 5 + 3 * 7;
TF[3] = 1;
TF[4] = (1 << 1) | (1 << 2) | (1 << 3);
iso_datetime_7(&TF[5], node->attrib.st_mtime);
iso_datetime_7(&TF[12], node->attrib.st_atime);
iso_datetime_7(&TF[19], node->attrib.st_ctime);
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);
}
@ -291,21 +278,21 @@ rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
assert(dir->type == ECMA119_DIR);
if (dir->parent != dir->info.dir.real_parent) {
uint8_t *PL = susp_find(&dir->info.dir.parent_susp, "PL");
if (dir->parent != dir->dir.real_parent) {
uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL");
assert(PL);
iso_bb(&PL[4], dir->info.dir.real_parent->info.dir.block, 4);
iso_bb(&PL[4], dir->dir.real_parent->block, 4);
}
for (i = 0; i < dir->info.dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->info.dir.children[i];
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_PLACEHOLDER) {
if (ch->type == ECMA119_FILE && ch->file.real_me) {
uint8_t *CL = susp_find(&ch->susp, "CL");
assert(CL);
iso_bb(&CL[4], ch->info.real_me->info.dir.block, 4);
iso_bb(&CL[4], ch->file.real_me->block, 4);
} else if (ch->type == ECMA119_DIR) {
rrip_finalize(t, ch);
}

View File

@ -1,11 +1,6 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* Functions and structures used for Rock Ridge support.
*
* See IEEE P1282, Rock Ridge Interchange Protocol, Draft Standard version
* 1.12 for further details.
*/
/** Functions and structures used for Rock Ridge support. */
#ifndef ISO_ROCKRIDGE_H
#define ISO_ROCKRIDGE_H
@ -13,99 +8,18 @@
struct ecma119_write_target;
struct ecma119_tree_node;
/**
* Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
*
* The "ER" System Use Entry is used to uniquely identify a specification
* compliant with SUSP. This method adds to the given tree node "." entry
* the "ER" corresponding to the RR protocol.
*
* See IEEE P1281, section 5.5 and IEEE P1282, section 4.3 for more details.
*/
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a PX System Use Entry to the given tree node and, if that node is
* a directory, to its "." and ".." entries. The PX System Use Entry is
* used to add POSIX file attributes, such as access permissions or user and
* group id, to a ECMA 119 directory record.
*
* See IEEE P1282, section 4.1.1 for more details.
*/
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a PN System Use Entry to the given tree node.
* The PN System Use Entry is used to store the device number, and it's
* mandatory if the tree node corresponds to a character or block device.
*
* See IEEE P1282, section 4.1.2 for more details.
*/
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a SL System Use Entry to the given tree node. This is used to store
* the content of a symbolic link, and is mandatory if the tree node
* indicates a symbolic link.
*
* See IEEE P1282, section 4.1.3 for more details.
*/
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a NM System Use Entry to the given tree node. The purpose of this
* System Use Entry is to store the content of an Alternate Name to support
* POSIX-style or other names.
*
* See IEEE P1282, section 4.1.4 for more details.
*/
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
/*
* The next 3 System Use Entries are used to handle Deep Directory
* Hierarchies, i.e., hierarchies where the number of directory levels
* exceed the eight limit of ECMA-119.
*/
/**
* Add to the given tree node a CL System Use Entry, that is used to record
* the new location of a directory which has been relocated.
*
* See IEEE P1282, section 4.1.5.1 for more details.
*/
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a PL System Use Entry, used to record the location of the original
* parent directory of a directory which has been relocated.
*
* 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.
*
* See IEEE P1282, section 4.1.5.2 for more details.
*/
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a RE System Use Entry to the given tree node. The purpose of the
* this System Use Entry is to indicate to an RRIP-compliant receiving
* system that the Directory Record in which an "RE" System Use Entry is
* recorded has been relocated from another position in the original
* Directory Hierarchy.
*
* See IEEE P1282, section 4.1.5.3 for more details.
*/
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add to the given tree node a TF System Use Entry, used to record some
* time stamps related to the file.
*
* See IEEE P1282, section 4.1.6 for more details.
*/
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 *);

View File

@ -117,8 +117,8 @@ 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->info.dir.self_susp, 34);
try_add_CE(t, &node->info.dir.parent_susp, 34);
try_add_CE(t, &node->dir.self_susp, 34);
try_add_CE(t, &node->dir.parent_susp, 34);
}
}
@ -137,7 +137,7 @@ susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
SP[4] = 0xbe;
SP[5] = 0xef;
SP[6] = 0;
susp_append(t, &dir->info.dir.self_susp, SP);
susp_append(t, &dir->dir.self_susp, SP);
}
#if 0
@ -155,14 +155,38 @@ static void susp_add_ST(struct ecma119_write_target *t,
}
#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->info.dir.block)
* - length of the current directory (dir->info.dir.len)
* - sum of the children's CE lengths (dir->info.dir.CE_len)
* - 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,
@ -184,18 +208,18 @@ static void susp_fin_CE(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
int i;
size_t CE_offset = dir->info.dir.len;
size_t CE_offset = dir->dir.len;
assert(dir->type == ECMA119_DIR);
susp_fin_1_CE(t, &dir->info.dir.self_susp, dir->info.dir.block, &CE_offset);
susp_fin_1_CE(t, &dir->info.dir.parent_susp, dir->info.dir.block, &CE_offset);
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->info.dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->info.dir.children[i];
susp_fin_1_CE(t, &ch->susp, dir->info.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->info.dir.len + dir->info.dir.CE_len);
assert(CE_offset == dir->dir.len + dir->dir.CE_len);
}
void
@ -205,13 +229,13 @@ susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
assert(dir->type = ECMA119_DIR);
if (dir->info.dir.depth != 1) {
if (dir->dir.depth != 1) {
susp_fin_CE(t, dir);
}
for (i = 0; i < dir->info.dir.nchildren; i++) {
if (dir->info.dir.children[i]->type == ECMA119_DIR)
susp_finalize(t, dir->info.dir.children[i]);
for (i = 0; i < dir->dir.nchildren; i++) {
if (dir->dir.children[i]->type == ECMA119_DIR)
susp_finalize(t, dir->dir.children[i]);
}
}

View File

@ -1,10 +1,6 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* Functions and structures used for SUSP (IEEE 1281).
*
* Please refer to IEEE P1281 System Use Sharing Protocol, draft standard
* version 1.12 for more details.
/** Functions and structures used for SUSP (IEEE 1281).
*/
#ifndef __ISO_SUSP
@ -32,23 +28,13 @@ struct susp_info
* will go in a CE area. */
};
/**
* Add a CE System Use Entry to the given tree node. A "CE" is used to add
* a continuation area, where additional System Use Entry can be written.
* See IEEE P1281, section 5.1.
*/
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a SP System Use Entry to the "." entry of the directory. The SP provide
* an identifier that the SUSP is used within the volume. The SP shall be
* recorded in the "." entry of the root directory.
* See IEEE P1281, section 5.3 for more details.
*
* this is special because it doesn't modify the susp fields of the
* directory; it modifies the susp fields of the "." entry in the directory.
*/
/* 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. */

View File

@ -20,6 +20,8 @@
#include <stdio.h>
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "exclude.h"
static void
@ -28,352 +30,171 @@ set_default_stat(struct stat *s)
time_t now = time(NULL);
memset(s, 0, sizeof(struct stat));
s->st_mode = 0555;
s->st_mode = 0777 | S_IFREG;
s->st_atime = s->st_mtime = s->st_ctime = now;
}
void
iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child)
static struct stat
get_attrib(const struct iso_tree_node *node)
{
assert( parent && child);
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;
child->parent = parent;
}
struct iso_tree_node_dir*
iso_tree_new_root()
{
struct iso_tree_node_dir *root;
root = calloc(1, sizeof(struct iso_tree_node_dir));
set_default_stat(&root->node.attrib);
root->node.attrib.st_mode = S_IFDIR | 0777;
root->node.type = LIBISO_NODE_DIR;
return root;
}
struct iso_tree_node*
iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
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)
{
struct iso_tree_node_file *f;
char *p;
struct stat st;
assert( parent && path);
if (lstat(path, &st) == -1) {
libisofs_errno = NO_FILE;
struct iso_tree_node *ret;
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
if (lstat(path, &st) == -1)
return NULL;
}
if ( !S_ISREG(st.st_mode) ) {
libisofs_errno = UNEXPECTED_FILE_TYPE;
return NULL;
}
if ( access(path, R_OK) ) {
libisofs_errno = NO_READ_ACCESS;
return NULL;
}
f = calloc(1, sizeof(struct iso_tree_node_file));
/* fill fields */
f->node.attrib = st;
f->path = strdup(path);
f->node.type = LIBISO_NODE_FILE;
p = strdup(path); /* because basename() might modify its arg */
f->node.name = strdup( basename(p) );
/* 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);
/* add to parent (this also sets f->node->parent) */
iso_tree_add_child(parent, (struct iso_tree_node*) f);
return (struct iso_tree_node*) f;
return ret;
}
struct iso_tree_node*
iso_tree_add_symlink(struct iso_tree_node_dir *parent,
const char *name, const char *dest)
{
struct iso_tree_node_symlink *link;
assert( parent && name && dest);
link = calloc(1, sizeof(struct iso_tree_node_symlink));
/* fill fields */
set_default_stat(&link->node.attrib);
link->node.attrib.st_mode |= S_IFLNK;//TODO Not needed
link->node.name = strdup(name);
link->node.type = LIBISO_NODE_SYMLINK;
link->dest = strdup(dest);
/* add to parent (this also sets link->node->parent) */
iso_tree_add_child(parent, (struct iso_tree_node*) link);
return (struct iso_tree_node*) link;
}
struct iso_tree_node_dir*
iso_tree_add_dir(struct iso_tree_node_dir *parent,
const char *name)
{
struct iso_tree_node_dir *dir;
assert( parent && name );
dir = calloc(1, sizeof(struct iso_tree_node_dir));
dir->node.attrib = parent->node.attrib;
dir->node.type = LIBISO_NODE_DIR;
dir->node.name = strdup(name);
iso_tree_add_child(parent, (struct iso_tree_node*) dir);
return dir;
}
void
iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
{
free(node->name);
node->name = strdup(name);
}
void
iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
{
assert(node);
node->hide_flags = hide_attrs;
}
void
iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
{
assert(node);
node->attrib.st_gid = gid;
}
void
iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
{
assert(node);
node->attrib.st_uid = uid;
}
void
iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
{
assert(node);
node->attrib.st_mode = (node->attrib.st_mode & S_IFMT) |
(mode & ~S_IFMT);
}
void
iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
{
assert(node);
if ( ISO_ISDIR(node) ) {
size_t i;
struct iso_tree_node_dir *dir;
dir = (struct iso_tree_node_dir *) node;
for (i=0; i < dir->nchildren; i++) {
iso_tree_node_set_sort_weight(dir->children[i], w);
}
} else if ( ISO_ISREG(node) ) {
struct iso_tree_node_file *file;
file = (struct iso_tree_node_file *) node;
file->sort_weight = w;
}
}
struct iso_tree_node*
iso_tree_add_node(struct iso_tree_node_dir *parent,
const char *path)
{
struct stat st;
struct iso_tree_node *node;
assert( parent && path);
if (lstat(path, &st) == -1) {
libisofs_errno = NO_FILE;
return NULL;
}
if ( access(path, R_OK) ) {
libisofs_errno = NO_READ_ACCESS;
return NULL;
}
switch (st.st_mode & S_IFMT) {
case S_IFREG:
/* regular file */
node = iso_tree_add_file(parent, path);
break;
case S_IFLNK:
/* symlink */
{
char dest[PATH_MAX];
char *p;
int n;
n = readlink(path, dest, PATH_MAX);
if ( n == -1 ) {
libisofs_errno = INTERNAL_ERROR;
return NULL;
}
dest[n] = '\0';
p = strdup(path); /* because basename() might modify its arg */
node = iso_tree_add_symlink(parent, basename(p), dest);
free(p);
node->attrib = st;
}
break;
case S_IFDIR:
/* directory */
{
char *p;
p = strdup(path); /* because basename() might modify its arg */
node = (struct iso_tree_node*) iso_tree_add_dir(parent, basename(p));
free(p);
node->attrib = st;
}
break;
default:
libisofs_errno = UNEXPECTED_FILE_TYPE;
node = NULL;
break;
}
return node;
}
void
iso_tree_free(struct iso_tree_node *root)
{
if ( ISO_ISDIR(root) ) {
size_t i;
struct iso_tree_node_dir *dir;
dir = (struct iso_tree_node_dir *) root;
for (i=0; i < dir->nchildren; i++) {
iso_tree_free(dir->children[i]);
}
free(dir->children);
} else if ( ISO_ISLNK(root) ) {
struct iso_tree_node_symlink *link;
link = (struct iso_tree_node_symlink *) root;
free(link->dest);
} else if ( ISO_ISREG(root) ) {
struct iso_tree_node_file *file;
file = (struct iso_tree_node_file *) root;
free(file->path);
}
free(root->name);
free(root);
}
static void
iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior,
struct iso_hash_table *excludes)
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;
return new;
}
while ((ent = readdir(dir))) {
char child[strlen(ent->d_name) + strlen(path) + 2];
if (behavior->stop_on_error & behavior->error)
break;
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
continue;
//TODO check if path already finished in '/'
sprintf(child, "%s/%s", path, ent->d_name);
/* see if this child is excluded. */
if (iso_exclude_lookup(excludes, child))
if (iso_exclude_lookup(child))
continue;
new = iso_tree_add_node(parent, child);
if (!new || !ISO_ISDIR(new)) {
if (!new)
behavior->error = 1;
continue;
}
iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child,
behavior, excludes);
iso_tree_radd_dir(new, child);
}
closedir(dir);
return;
return new;
}
void
iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior)
void
iso_tree_free(struct iso_tree_node *root)
{
struct iso_tree_node_dir *dir;
struct iso_hash_table table = { {0,}, 0};
assert ( parent && path );
behavior->error = 0;
/* initialize exclude hash_table */
if ( behavior->excludes ) {
char *exclude;
int i = 0;
while ( (exclude = behavior->excludes[i++]) ) {
iso_exclude_add_path(&table, exclude);
}
size_t i;
for (i=0; i < root->nchildren; i++) {
iso_tree_free(root->children[i]);
}
/* recurse into dir */
iso_tree_radd_dir_aux(parent, path, behavior, &table);
/* clear hashtable */
iso_exclude_empty(&table);
return dir;
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%s\n", sp, root->name);
if ( ISO_ISDIR(root) ) {
size_t i;
struct iso_tree_node_dir *dir;
dir = (struct iso_tree_node_dir *) root;
for (i=0; i < dir->nchildren; i++) {
iso_tree_print(dir->children[i], spaces+2);
}
printf("%s%sn", sp, root->name);
for (i=0; i < root->nchildren; i++) {
iso_tree_print(root->children[i], spaces+2);
}
}
@ -384,18 +205,19 @@ iso_tree_print_verbose(const struct iso_tree_node *root,
void *callback_data,
int spaces)
{
size_t i;
(ISO_ISDIR(root) ? dir : file)
(S_ISDIR(root->attrib.st_mode) ? dir : file)
(root, callback_data, spaces);
if ( ISO_ISDIR(root) ) {
size_t i;
struct iso_tree_node_dir *dir_node;
dir_node = (struct iso_tree_node_dir *) root;
for (i=0; i < dir_node->nchildren; i++) {
iso_tree_print_verbose(dir_node->children[i], dir,
file, callback_data, spaces+2);
}
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);
}

View File

@ -24,31 +24,24 @@
#include "libisofs.h"
//enum file_location {
// LIBISO_FILESYS,
// LIBISO_PREVSESSION,
// LIBISO_NONE /**< for files/dirs that were added with
// * iso_tree_add_new_XXX. */
//};
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;
// /* };*/
//};
enum iso_tree_node_type {
LIBISO_NODE_DIR,
LIBISO_NODE_FILE,
LIBISO_NODE_SYMLINK,
LIBISO_NODE_BOOTCATALOG
struct iso_file_location
{
enum file_location type;
/* union {*/
char *path; /* in the current locale */
uint32_t block;
/* };*/
};
/**
@ -56,61 +49,58 @@ enum iso_tree_node_type {
*/
struct iso_tree_node
{
struct iso_tree_node_dir *parent;
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". */
int hide_flags; /**< If the node is to be hidden in RR/ISO or
* Joilet tree */
enum iso_tree_node_type type;
};
/**
* A node in the filesystem tree that represents a regular file
*/
struct iso_tree_node_file
{
struct iso_tree_node node;
char *path; /**< the path of the file on local filesystem */
int sort_weight; /**< It sorts the order in which the file data is
* written to the CD image. Higher weighting files
* are written at the beginning of image */
/* when read from an existing ISO image, we need to store the
* block where file contents are written, and not the path.
* Maybe instead of a char *path we will need to go back to
* struct iso_file_location loc;
*/
/* struct iso_file_location loc; */
struct iso_file_location loc;
/**< Only used for regular files and symbolic
* links (ie. files for which we might have to
* copy data). */
};
/**
* A node in the filesystem tree that represents a symbolic link
*/
struct iso_tree_node_symlink
{
struct iso_tree_node node;
char *dest; /**< Destination of the link */
};
/**
* A directory on the filesystem tree
*/
struct iso_tree_node_dir
{
struct iso_tree_node node;
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.
*
@ -120,12 +110,6 @@ struct iso_tree_node_dir
*/
void iso_tree_free(struct iso_tree_node *root);
/**
* Adds a child to a directory
*/
void iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child);
/**
* A function that prints verbose information about a directory.
*
@ -170,8 +154,6 @@ void iso_tree_print_verbose(const struct iso_tree_node *root,
void *callback_data,
int spaces);
#define ISO_ISDIR(n) (n->type == LIBISO_NODE_DIR)
#define ISO_ISREG(n) (n->type == LIBISO_NODE_FILE)
#define ISO_ISLNK(n) (n->type == LIBISO_NODE_SYMLINK)
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
#endif /* LIBISO_TREE_H */

View File

@ -16,11 +16,9 @@
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include <locale.h>
#include <limits.h>
#include <locale.h>
#include "util.h"
#include "libisofs.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,
@ -37,141 +35,32 @@ int round_up(int n, int mul)
return div_up(n, mul) * mul;
}
/**
* Convert a string between charsets.
* This assumes '\0' means end-of-string, what is not necessarily true,
* but given there are lots of strdup around there, it will fail in other
* places anyway...
*/
char *
convert_str(const char *str, const char *icharset, const char *ocharset)
{
char *ret;
size_t inbytes;
size_t outbytes;
inbytes = strlen(str);
outbytes = (inbytes+1) * MB_LEN_MAX;
{
/* ensure enought space */
char out[outbytes];
char *src;
size_t n;
iconv_t conv = iconv_open(ocharset, icharset);
if (conv == (iconv_t)(-1)) {
printf("Can't convert from %s to %s\n", icharset, ocharset);
return NULL;
}
src = (char *)str;
ret = (char *)out;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
if (n == -1) {
/* error just return input stream */
perror("Convert error.");
printf("Maybe string %s is not encoded in %s\n", str, icharset);
iconv_close(conv);
return strdup(str);
}
iconv_close(conv);
*ret = '\0';
ret = strdup(out);
}
return ret;
}
/**
* Convert a str in a specified codeset to WCHAR_T.
* The result must be free() when no more needed
*/
static wchar_t *str2wchar(const char *str, const char *codeset)
{
iconv_t conv;
size_t inbytes;
size_t outbytes;
char *ret;
char *src;
wchar_t *wstr;
size_t n;
conv = iconv_open("WCHAR_T", codeset);
if (conv == (iconv_t)-1) {
perror("Invalid encodings\n");
return NULL;
}
inbytes = strlen(str);
outbytes = (inbytes + 1) * sizeof(wchar_t);
/* we are sure that numchars <= inbytes */
wstr = malloc(outbytes);
ret = (char *)wstr;
src = (char *)str;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
while (n == -1) {
if( errno != EINVAL ) {
/* error, should never occur */
iconv_close(conv);
perror("Convert error\n");
return NULL;
}
/* invalid input string charset, just log and ignore */
printf("String %s is not encoded in %s\n", str, codeset);
inbytes--;
if(!inbytes)
break;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
}
iconv_close(conv);
*( (wchar_t *)ret )='\0';
return wstr;
}
/* 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, const char *icharset)
char *str2ascii(const char *src_arg)
{
wchar_t *wsrc_;
char *ret;
wchar_t wsrc_[NAME_BUFFER_SIZE];
char *src = (char*)wsrc_;
char *ret_;
char *src;
char *ret;
mbstate_t state;
iconv_t conv;
size_t numchars;
size_t outbytes;
size_t inbytes;
size_t n;
assert(icharset);
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.
*
* For now, just assume input to be in UTF-8, we can change
* this later.
*/
wsrc_ = str2wchar(src_arg, icharset);
if (!wsrc_)
* 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;
src = (char *)wsrc_;
numchars = wcslen(wsrc_);
inbytes = numchars * sizeof(wchar_t);
@ -181,10 +70,8 @@ char *str2ascii(const char *src_arg, const char *icharset)
/* initialize iconv */
conv = iconv_open("ASCII", "WCHAR_T");
if (conv == (iconv_t)-1) {
free(wsrc_);
if (conv == (iconv_t)-1)
return NULL;
}
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
while(n == -1) {
@ -222,18 +109,17 @@ char *str2ascii(const char *src_arg, const char *icharset)
iconv_close(conv);
*ret='\0';
free(wsrc_);
return ret_;
}
/* FIXME: C&P */
uint16_t *str2ucs(const char *src_arg, const char *icharset)
uint16_t *str2ucs(const char *src_arg)
{
wchar_t *wsrc_;
char *src;
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;
@ -243,17 +129,13 @@ uint16_t *str2ucs(const char *src_arg, const char *icharset)
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.
*/
wsrc_ = str2wchar(src_arg, icharset);
if (!wsrc_)
* 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 */
src = (char*)wsrc_;
numchars = wcslen(wsrc_);
inbytes = numchars * sizeof(wchar_t);
@ -308,6 +190,7 @@ uint16_t *str2ucs(const char *src_arg, const char *icharset)
return (uint16_t*)ret_;
}
static int valid_d_char(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
@ -335,45 +218,9 @@ static int valid_p_char(char c)
|| (c == '.') || (c == '_') || (c == '-');
}
char *str2d_char(const char *str, const char *icharset) {
char *ret;
size_t len, i;
if (!str)
return NULL;
ret = str2ascii(str, icharset);
len = strlen(ret);
for (i = 0; i < len; ++i) {
char c = toupper(ret[i]);
ret[i] = valid_d_char(c) ? c : '_';
}
return ret;
}
char *str2a_char(const char *str, const char *icharset) {
char *ret;
size_t len, i;
if (!str)
return NULL;
ret = str2ascii(str, icharset);
len = strlen(ret);
for (i = 0; i < len; ++i) {
char c = toupper(ret[i]);
ret[i] = valid_a_char(c) ? c : '_';
}
return ret;
}
static char *iso_dirid(const char *src, int size, const char *icharset)
static char *iso_dirid(const char *src, int size)
{
char *ret = str2ascii(src, icharset);
char *ret = str2ascii(src);
size_t len, i;
if (!ret)
@ -392,46 +239,19 @@ static char *iso_dirid(const char *src, int size, const char *icharset)
return ret;
}
char *iso_1_dirid(const char *src, const char *icharset)
char *iso_1_dirid(const char *src)
{
return iso_dirid(src, 8, icharset);
return iso_dirid(src, 8);
}
char *iso_2_dirid(const char *src, const char *icharset)
char *iso_2_dirid(const char *src)
{
return iso_dirid(src, 31, icharset);
return iso_dirid(src, 31);
}
char *iso_r_dirid(const char *src, const char *icharset, int flags)
char *iso_1_fileid(const char *src_arg)
{
char *ret = str2ascii(src, icharset);
size_t size, len, i;
if (!ret)
return NULL;
size = flags & ECMA119_37_CHAR_FILENAMES ? 37 : 31;
len = strlen(ret);
if (len > size) {
ret[size] = '\0';
len = size;
}
if (flags & ECMA119_RELAXED_FILENAMES)
return ret;
for (i = 0; i < len; i++) {
char c = toupper(ret[i]);
ret[i] = valid_d_char(c) ? c : '_';
}
return ret;
}
char *iso_1_fileid(const char *src_arg, const char *icharset)
{
char *src = str2ascii(src_arg, icharset);
char *src = str2ascii(src_arg);
char *dest;
char *dot; /* Position of the last dot in the
filename, will be used to calculate
@ -480,9 +300,9 @@ char *iso_1_fileid(const char *src_arg, const char *icharset)
return dest;
}
char *iso_2_fileid(const char *src_arg, const char *icharset)
char *iso_2_fileid(const char *src_arg)
{
char *src = str2ascii(src_arg, icharset);
char *src = str2ascii(src_arg);
char *dest;
char *dot;
int lname, lext, lnname, lnext, pos, i;
@ -498,7 +318,7 @@ char *iso_2_fileid(const char *src_arg, const char *icharset)
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 + 1) == '\0') {
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
lname = strlen(src);
lnname = (lname > 30) ? 30 : lname;
lext = lnext = 0;
@ -540,88 +360,9 @@ char *iso_2_fileid(const char *src_arg, const char *icharset)
}
char *
iso_r_fileid(const char *src_arg, const char *icharset, int flag)
iso_p_fileid(const char *src)
{
char *src = str2ascii(src_arg, icharset);
char *dest;
char *dot;
int lname, lext, lnname, lnext, pos, i;
size_t size = flag & (1<<1) ? 37 : 33;
if (!src)
return NULL;
dest = malloc(size+1);
if (flag & ECMA119_RELAXED_FILENAMES) {
strncpy(dest, src, size);
dest[size] = '\0'; /* ensure 37 / 33 max length */
pos = strlen(dest);
pos = pos < (size == 37 ? 37 : 31) ? pos : (size == 37 ? 37 : 31);
if ( !(flag & ECMA119_OMIT_VERSION_NUMBERS) ) {
dest[pos++] = ';';
dest[pos++] = '1';
}
dest[pos] = '\0';
return dest;
}
/* no relaxed filenames */
dot = strrchr(src, '.');
size_t max = size == 37 ? 36 : 30;
/* 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 + 1) == '\0') {
lname = strlen(src);
lnname = (lname > max) ? max : lname;
lext = lnext = 0;
} else {
lext = strlen(dot + 1);
lname = strlen(src) - lext - 1;
lnext = (strlen(src) > max + 1 && lext > 3)
? (lname < max - 3 ? max - lname : 3) : lext;
lnname = (strlen(src) > max +1) ? max - 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 : '_';
}
if ( !(flag & ECMA119_OMIT_VERSION_NUMBERS) ) {
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, const char *icharset)
{
char *ret = str2ascii(src, icharset);
char *ret = str2ascii(src);
size_t i, len;
if (!ret)
@ -636,9 +377,9 @@ iso_p_fileid(const char *src, const char *icharset)
}
uint16_t *
iso_j_id(const char *src_arg, const char *icharset)
iso_j_id(const char *src_arg)
{
uint16_t *j_str = str2ucs(src_arg, icharset);
uint16_t *j_str = str2ucs(src_arg);
size_t len = ucslen(j_str);
size_t n;
@ -679,6 +420,7 @@ void iso_bb(uint8_t *buf, uint32_t num, int bytes)
iso_msb(buf+bytes, num, bytes);
}
void iso_datetime_7(unsigned char *buf, time_t t)
{
static int tzsetup = 0;
@ -699,12 +441,12 @@ void iso_datetime_7(unsigned char *buf, time_t t)
buf[4] = tm.tm_min;
buf[5] = tm.tm_sec;
#ifdef HAVE_TM_GMTOFF
tzoffset = tm.tm_gmtoff / 60 / 15;
tzoffset = -tm.tm_gmtoff / 60 / 15;
#else
tzoffset = timezone / 60 / 15;
tzoffset = -timezone / 60 / 15;
#endif
if (tzoffset > 52)
tzoffset -= 101;
if (tzoffset < -48)
tzoffset += 101;
buf[6] = tzoffset;
}
@ -748,12 +490,12 @@ void iso_datetime_17(unsigned char *buf, time_t t)
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;
tzoffset = -tm.tm_gmtoff / 60 / 15;
#else
tzoffset = timezone / 60 / 15;
tzoffset = -timezone / 60 / 15;
#endif
if (tzoffset > 52)
tzoffset -= 101;
if (tzoffset < -48)
tzoffset += 101;
buf[16] = tzoffset;
}
}

View File

@ -30,29 +30,19 @@ extern inline int round_up(int n, int mul)
return div_up(n, mul) * mul;
}
char *convert_str(const char *str, const char *icharset, const char *ocharset);
wchar_t *towcs(const char *);
char *str2ascii(const char*, const char *);
uint16_t *str2ucs(const char *, const char *);
char *str2d_char(const char*, const char *);
char *str2a_char(const char*, const char *);
char *str2ascii(const char*);
uint16_t *str2ucs(const char*);
/**
* Create a level 1 directory identifier.
*/
char *iso_1_dirid(const char *src, const char *);
char *iso_1_dirid(const char *src);
/**
* Create a level 2 directory identifier.
*/
char *iso_2_dirid(const char *src, const char *);
/**
* Create a directory identifier with relaxed constraints
*/
char *iso_r_dirid(const char *src, const char *icharset, int flags);
char *iso_2_dirid(const char *src);
/**
* Create a level 1 file identifier that consists of a name, extension and
@ -61,7 +51,7 @@ char *iso_r_dirid(const char *src, const char *icharset, int flags);
* 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, const char *);
char *iso_1_fileid(const char *src);
/**
* Create a level 2 file identifier that consists of a name, extension and
@ -70,12 +60,7 @@ char *iso_1_fileid(const char *src, const char *);
* 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, const char *);
/**
* Create a file identifier with relaxed constraints.
*/
char *iso_r_fileid(const char *src, const char *icharset, int flags);
char *iso_2_fileid(const char *src);
/**
* Create a Joliet file or directory identifier that consists of a name,
@ -88,7 +73,7 @@ char *iso_r_fileid(const char *src, const char *icharset, int flags);
* @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, const char *icharset);
uint16_t *iso_j_id(const char *src);
/**
* FIXME: what are the requirements for these next two? Is this for RR?
@ -97,7 +82,7 @@ uint16_t *iso_j_id(const char *src, const char *icharset);
* 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, const char *);
char *iso_p_fileid(const char *src);
/**
* Create a POSIX portable directory name.

View File

@ -9,7 +9,6 @@
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "eltorito.h"
struct iso_volset*
iso_volset_new(struct iso_volume *vol, const char *id)
@ -21,6 +20,8 @@ iso_volset_new(struct iso_volume *vol, const char *id)
volset->volume = malloc(sizeof(void *));
volset->volume[0] = vol;
volset->volset_id = strdup(id);
vol->refcount++;
return volset;
}
@ -34,7 +35,6 @@ iso_volset_free(struct iso_volset *volset)
}
free(volset->volume);
free(volset->volset_id);
free(volset);
}
}
@ -53,14 +53,14 @@ 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_dir *root)
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->root = root ? root : iso_tree_new_root(volume);
if (volume_id != NULL)
volume->volume_id = strdup(volume_id);
@ -76,101 +76,39 @@ iso_volume_free(struct iso_volume *volume)
{
/* Only free if no references are in use. */
if (--volume->refcount < 1) {
iso_tree_free( (struct iso_tree_node*) volume->root);
iso_tree_free(volume->root);
free(volume->volume_id);
free(volume->publisher_id);
free(volume->data_preparer_id);
free(volume->system_id);
free(volume->application_id);
free(volume->copyright_file_id);
free(volume->abstract_file_id);
free(volume->biblio_file_id);
if (volume->bootcat)
el_torito_boot_catalog_free(volume->bootcat);
free(volume);
}
}
struct iso_tree_node_dir *
struct iso_tree_node *
iso_volume_get_root(const struct iso_volume *volume)
{
return volume->root;
}
void iso_volume_set_volume_id(struct iso_volume *volume,
const char *volume_id)
{
free(volume->volume_id);
volume->volume_id = strdup(volume_id);
}
void iso_volume_set_publisher_id(struct iso_volume *volume,
const char *publisher_id)
{
free(volume->publisher_id);
volume->publisher_id = strdup(publisher_id);
}
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id)
{
free(volume->data_preparer_id);
volume->data_preparer_id = strdup(data_preparer_id);
}
void iso_volume_set_system_id(struct iso_volume *volume,
const char *system_id)
{
free(volume->system_id);
volume->system_id = strdup(system_id);
}
void iso_volume_set_application_id(struct iso_volume *volume,
const char *application_id)
{
free(volume->application_id);
volume->application_id = strdup(application_id);
}
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
const char *copyright_file_id)
{
free(volume->copyright_file_id);
volume->copyright_file_id = strdup(copyright_file_id);
}
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
const char *abstract_file_id)
{
free(volume->abstract_file_id);
volume->abstract_file_id = strdup(abstract_file_id);
}
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
const char *biblio_file_id)
{
free(volume->biblio_file_id);
volume->biblio_file_id = strdup(biblio_file_id);
}
struct iso_tree_node *
iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
{
struct iso_tree_node *node;
struct iso_tree_node_dir *dir;
char *ptr, *brk_info, *component;
/* get the first child at the root of the volume
* that is "/" */
dir = iso_volume_get_root(volume);
node = (struct iso_tree_node *)dir;
if (!strcmp(path, "/"))
node=iso_volume_get_root(volume);
if (!strcmp (path, "/"))
return node;
if (!dir->nchildren)
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 */
@ -178,18 +116,12 @@ iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
while (component) {
size_t max;
size_t i;
if ( !ISO_ISDIR(node) ) {
node=NULL;
break;
}
dir = (struct iso_tree_node_dir *)node;
/* search among all the children of this directory if this path component exists */
max=dir->nchildren;
max=node->nchildren;
for (i=0; i < max; i++) {
if (!strcmp(component, dir->children[i]->name)) {
node=dir->children[i];
if (!strcmp(component, node->children[i]->name)) {
node=node->children[i];
break;
}
}
@ -204,55 +136,54 @@ iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
}
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_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;
//}
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;
}

View File

@ -18,20 +18,12 @@ struct iso_volume
int refcount; /**< Number of used references to this
volume. */
struct iso_tree_node_dir *root; /**< Root of the directory tree for the
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. */
char *system_id; /**< Volume system identifier. */
char *application_id; /**< Volume application id */
char *copyright_file_id;
char *abstract_file_id;
char *biblio_file_id;
struct el_torito_boot_catalog *bootcat; /**< El-Torito boot catalog */
};
/**

33
test.sh
View File

@ -1,33 +0,0 @@
#!/bin/bash
TEST_ROOT=/tmp/libisofs_test
rm -rf $TEST_ROOT
#create test folders
mkdir -p $TEST_ROOT
mkdir -p $TEST_ROOT/dir1/dir11
chmod 755 $TEST_ROOT/dir1
chmod 755 $TEST_ROOT/dir1/dir11
touch $TEST_ROOT/dir1/dir11/a
echo "This file is to check correct file permissions. set them to 754" > $TEST_ROOT/dir1/permtest
chmod 754 $TEST_ROOT/dir1/permtest
mkdir -p $TEST_ROOT/dir2
ln -s $TEST_ROOT/dir1 "$TEST_ROOT/link to dir1"
echo "README file" > $TEST_ROOT/README
chmod 555 $TEST_ROOT/README
ln -s $TEST_ROOT/README "$TEST_ROOT/link to readme"
echo "No read file" > $TEST_ROOT/no_read
chmod 000 $TEST_ROOT/no_read
if ! make check
then
exit 1
fi
test/test

View File

@ -20,7 +20,7 @@
#define SECSIZE 2048
const char * const optstring = "JRL:b:h";
const char * const optstring = "JRL:h";
extern char *optarg;
extern int optind;
@ -36,7 +36,6 @@ void help()
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -b file Specifies a boot image to add to image\n"
" -h Print this message\n"
);
}
@ -45,14 +44,12 @@ int main(int argc, char **argv)
{
struct iso_volset *volset;
struct iso_volume *volume;
struct iso_tree_node_dir *root;
struct iso_tree_node *root;
struct burn_source *src;
unsigned char buf[2048];
FILE *fd;
int c;
struct iso_tree_radd_dir_behavior behav = {0,0,0};
int level=1, flags=0;
char *boot_img = NULL;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
@ -70,9 +67,6 @@ int main(int argc, char **argv)
case 'L':
level = atoi(optarg);
break;
case 'b':
boot_img = optarg;
break;
case '?':
usage();
exit(1);
@ -95,42 +89,14 @@ int main(int argc, char **argv)
err(1, "error opening output file");
}
root = iso_tree_new_root();
iso_tree_radd_dir(root, argv[optind], &behav);
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 );
if ( boot_img ) {
/* adds El-Torito boot info. Tunned for isolinux */
struct iso_tree_node_dir *boot = (struct iso_tree_node_dir *)
iso_tree_volume_path_to_node(volume, "isolinux");
struct iso_tree_node *img = iso_tree_volume_path_to_node(volume, boot_img);
if (!img) {
err(1, "boot image patch is not valid");
}
struct el_torito_boot_image *bootimg =
iso_volume_create_boot_catalog(volume, img, ELTORITO_NO_EMUL,
boot, "boot.cat");
el_torito_set_load_size(bootimg, 4);
el_torito_set_write_boot_info(bootimg);
}
volset = iso_volset_new( volume, "VOLSETID" );
/* some tests */
iso_volume_set_application_id(volume, "Libburnia");
iso_volume_set_copyright_file_id(volume, "LICENSE");
int constraints = ECMA119_OMIT_VERSION_NUMBERS |
ECMA119_37_CHAR_FILENAMES | ECMA119_NO_DIR_REALOCATION |
ECMA119_RELAXED_FILENAMES;
struct ecma119_source_opts opts = {0, level, flags, constraints, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, "UTF-8", "UTF-8"};
src = iso_source_new_ecma119(volset, &opts);
src = iso_source_new_ecma119(volset, 0, level, flags);
while (src->read(src, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);

View File

@ -1,28 +0,0 @@
#include "test.h"
static void create_test_suite()
{
add_util_suite();
add_tree_suite();
add_exclude_suite();
add_file_hashtable_suite();
add_ecma119_tree_suite();
add_volume_suite();
}
int main(int argc, char **argv)
{
CU_pSuite pSuite = NULL;
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
create_test_suite();
/* Run all tests using the console interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}

View File

@ -1,24 +0,0 @@
#ifndef TEST_H_
#define TEST_H_
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
#include <CUnit/Basic.h>
#include "libisofs.h"
void add_tree_suite();
void add_exclude_suite();
void add_file_hashtable_suite();
void add_util_suite();
void add_ecma119_tree_suite();
void add_volume_suite();
#endif /*TEST_H_*/

View File

@ -1,34 +0,0 @@
/*
* Unit test for ecma119_tree.h
*/
//FIXME not implemented yet!!
#include "libisofs.h"
#include "tree.h"
#include "test.h"
//#include "ecma119_tree.h"
/*
* Also including C file, testing internal functions
*/
//#include "ecma119_tree.c"
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
static void test_calc_dirent_len()
{
}
void add_ecma119_tree_suite()
{
CU_pSuite pSuite = CU_add_suite("Ecma119TreeSuite", NULL, NULL);
//CU_add_test(pSuite, "test of calc_dirent_len()", test_calc_dirent_len);
}

View File

@ -1,33 +0,0 @@
/*
* Unit test for exclude.h
*/
#include "exclude.h"
#include "test.h"
#include <assert.h>
#include <stdio.h>
static void test_exclude()
{
struct iso_hash_table table = { {0,}, 0};
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/otherdir") );
iso_exclude_add_path(&table, "/otherdir");
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/otherdir") );
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
iso_exclude_add_path(&table, "/dir");
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/otherdir") );
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/dir") );
iso_exclude_empty(&table);
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/otherdir") );
}
void add_exclude_suite()
{
CU_pSuite pSuite = CU_add_suite("ExcludeSuite", NULL, NULL);
CU_add_test(pSuite, "test of exclude", test_exclude);
}

View File

@ -1,248 +0,0 @@
/*
* Unit test for file.h
*/
#include "test.h"
#include "file.h"
#include "tree.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void test_iso_file_new()
{
struct iso_tree_node_file *file;
struct iso_file *iso;
file = calloc(1, sizeof(struct iso_tree_node_file) );
file->node.name = "fileName";
file->node.attrib.st_size = 12;
file->node.attrib.st_dev = 15;
file->node.attrib.st_ino = 204;
file->path = "/tmp/filename";
file->sort_weight = 1;
iso = iso_file_new(file);
CU_ASSERT_PTR_NOT_NULL(iso);
CU_ASSERT_STRING_EQUAL(iso->path, "/tmp/filename");
CU_ASSERT_EQUAL(iso->size, 12);
CU_ASSERT_EQUAL(iso->ino, 0);
CU_ASSERT_EQUAL(iso->nlink, 1);
CU_ASSERT_EQUAL(iso->sort_weight, 1);
CU_ASSERT_EQUAL(iso->real_dev, 15);
CU_ASSERT_EQUAL(iso->real_ino, 204);
}
static void test_add_lookup()
{
struct iso_file_table *table;
struct iso_tree_node_file *file1;
struct iso_tree_node_file *file2;
struct iso_file *iso1;
struct iso_file *iso2;
struct iso_file *iso3;
int r;
table = iso_file_table_new(1);
CU_ASSERT_PTR_NOT_NULL( table );
CU_ASSERT_TRUE( table->cache_inodes );
CU_ASSERT_EQUAL(table->count, 0);
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
file1->node.name = "fileName";
file1->node.attrib.st_dev = 15;
file1->node.attrib.st_ino = 204;
file1->path = "/tmp/filename";
iso1 = iso_file_new(file1);
r = iso_file_table_add_file(table, iso1);
CU_ASSERT_EQUAL(r, 1);
CU_ASSERT_EQUAL(table->count, 1);
iso2 = iso_file_table_lookup(table, file1);
CU_ASSERT_PTR_NOT_NULL(iso2);
CU_ASSERT_PTR_EQUAL(iso2, iso1);
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
file2->node.name = "fileName2";
file2->node.attrib.st_dev = 152;
file2->node.attrib.st_ino = 2042;
file2->path = "/tmp/filename2";
iso3 = iso_file_new(file2);
r = iso_file_table_add_file(table, iso3);
CU_ASSERT_EQUAL(r, 1);
CU_ASSERT_EQUAL(table->count, 2);
/* treat to add the same file again */
r = iso_file_table_add_file(table, iso3);
CU_ASSERT_EQUAL(r, 0);
CU_ASSERT_EQUAL(table->count, 2);
iso2 = iso_file_table_lookup(table, file1);
CU_ASSERT_PTR_NOT_NULL(iso2);
CU_ASSERT_PTR_EQUAL(iso2, iso1);
iso2 = iso_file_table_lookup(table, file2);
CU_ASSERT_PTR_NOT_NULL(iso2);
CU_ASSERT_PTR_EQUAL(iso2, iso3);
iso3 = iso_file_new(file2);
r = iso_file_table_add_file(table, iso3);
CU_ASSERT_EQUAL(r, 0);
CU_ASSERT_EQUAL(table->count, 2);
iso_file_table_clear(table);
CU_ASSERT_EQUAL(table->count, 0);
iso2 = iso_file_table_lookup(table, file2);
CU_ASSERT_PTR_NULL(iso2);
free( file1 );
free( file2 );
free( table );
}
static void test_cache_inodes()
{
struct iso_file_table *table;
struct iso_tree_node_file *file1;
struct iso_tree_node_file *file2;
struct iso_file *iso1;
struct iso_file *iso2;
struct iso_file *iso3;
int r;
table = iso_file_table_new(1);
CU_ASSERT_PTR_NOT_NULL( table );
CU_ASSERT_TRUE( table->cache_inodes );
CU_ASSERT_EQUAL(table->count, 0);
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
file1->node.name = "fileName";
file1->node.attrib.st_dev = 15;
file1->node.attrib.st_ino = 204;
file1->path = "/tmp/filename";
iso1 = iso_file_new(file1);
r = iso_file_table_add_file(table, iso1);
CU_ASSERT_EQUAL(r, 1);
/* another file, different but with the same inode id */
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
file2->node.name = "another file";
file2->node.attrib.st_dev = 15;
file2->node.attrib.st_ino = 204;
file2->path = "/tmp/another";
iso2 = iso_file_new(file2);
/* ensure it's not added again... */
r = iso_file_table_add_file(table, iso2);
CU_ASSERT_EQUAL(r, 0);
/* ...and the lookup returns the first */
iso3 = iso_file_table_lookup(table, file2);
CU_ASSERT_PTR_EQUAL(iso1, iso3);
free(iso2);
free(file2);
/* and now a file with same inode but different device */
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
file2->node.name = "different file";
file2->node.attrib.st_dev = 16; /* different dev id */
file2->node.attrib.st_ino = 204;
file2->path = "/tmp/different";
iso2 = iso_file_new(file2);
r = iso_file_table_add_file(table, iso2);
CU_ASSERT_EQUAL(r, 1);
iso3 = iso_file_table_lookup(table, file2);
CU_ASSERT_PTR_NOT_EQUAL(iso3, iso1);
CU_ASSERT_PTR_EQUAL(iso3, iso2);
iso_file_table_clear(table);
free( file1 );
free( file2 );
free( table );
}
static void test_no_cache_inodes()
{
struct iso_file_table *table;
struct iso_tree_node_file *file1;
struct iso_tree_node_file *file2;
struct iso_tree_node_file *file3;
struct iso_file *iso1;
struct iso_file *iso2;
struct iso_file *iso3;
int r;
table = iso_file_table_new(0);
CU_ASSERT_PTR_NOT_NULL( table );
CU_ASSERT_FALSE( table->cache_inodes );
CU_ASSERT_EQUAL(table->count, 0);
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
file1->node.name = "fileName";
file1->node.attrib.st_dev = 15;
file1->node.attrib.st_ino = 204;
file1->path = "/tmp/filename";
iso1 = iso_file_new(file1);
r = iso_file_table_add_file(table, iso1);
CU_ASSERT_EQUAL(r, 1);
/* another file, different but with the same inode id */
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
file2->node.name = "another file";
file2->node.attrib.st_dev = 15;
file2->node.attrib.st_ino = 204;
file2->path = "/tmp/another";
iso2 = iso_file_new(file2);
/* ensure is added */
r = iso_file_table_add_file(table, iso2);
CU_ASSERT_EQUAL(r, 1);
iso3 = iso_file_table_lookup(table, file2);
CU_ASSERT_PTR_EQUAL(iso3, iso2);
/* and now a file with same inode and path */
file3 = calloc(1, sizeof(struct iso_tree_node_file) );
file3->node.name = "different file";
file3->node.attrib.st_dev = 15;
file3->node.attrib.st_ino = 204;
file3->path = "/tmp/filename";
iso3 = iso_file_new(file3);
r = iso_file_table_add_file(table, iso3);
CU_ASSERT_EQUAL(r, 0);
iso3 = iso_file_table_lookup(table, file3);
CU_ASSERT_PTR_EQUAL(iso3, iso1);
iso_file_table_clear(table);
free(file1);
free(file2);
free(file3);
free(table);
}
void add_file_hashtable_suite()
{
CU_pSuite pSuite = CU_add_suite("FileHashtableSuite", NULL, NULL);
CU_add_test(pSuite, "test of iso_file_new()", test_iso_file_new);
CU_add_test(pSuite, "test of add and lookup", test_add_lookup);
CU_add_test(pSuite, "test with cache_inodes", test_cache_inodes);
CU_add_test(pSuite, "test without cache_inodes", test_no_cache_inodes);
}

View File

@ -1,395 +0,0 @@
/*
* Unit test for tree.h
*/
#include "libisofs.h"
#include "tree.h"
#include "test.h"
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
static void test_new_root() {
struct iso_tree_node_dir *root;
root = iso_tree_new_root();
CU_ASSERT_PTR_NOT_NULL(root);
CU_ASSERT_EQUAL(root->nchildren, 0);
CU_ASSERT_PTR_NULL(root->children);
CU_ASSERT_PTR_NULL(root->node.parent);
CU_ASSERT_PTR_NULL(root->node.name);
CU_ASSERT(S_ISDIR(root->node.attrib.st_mode) );
}
static void test_add_dir() {
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *dir;
root = iso_tree_new_root();
CU_ASSERT_PTR_NOT_NULL(root);
dir = iso_tree_add_dir(root, "New dir name");
CU_ASSERT_PTR_NOT_NULL(root);
CU_ASSERT_PTR_NOT_NULL(dir);
CU_ASSERT_PTR_EQUAL(dir->node.parent, root);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)dir);
CU_ASSERT_STRING_EQUAL( dir->node.name, "New dir name");
CU_ASSERT( S_ISDIR(dir->node.attrib.st_mode) );
iso_tree_free((struct iso_tree_node *)root);
}
static void test_add_file() {
struct iso_tree_node_dir *root;
struct iso_tree_node_file *file;
root = iso_tree_new_root();
file = (struct iso_tree_node_file *)
iso_tree_add_file(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(root);
CU_ASSERT_PTR_NOT_NULL(file);
CU_ASSERT_PTR_EQUAL(file->node.parent, root);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)file);
CU_ASSERT_STRING_EQUAL( file->node.name, "README" );
CU_ASSERT_STRING_EQUAL( file->path, "/tmp/libisofs_test/README" );
CU_ASSERT( S_ISREG(file->node.attrib.st_mode) );
iso_tree_free((struct iso_tree_node *)root);
}
static void test_add_symlink() {
struct iso_tree_node_dir *root;
struct iso_tree_node *lnk;
root = iso_tree_new_root();
lnk = iso_tree_add_symlink(root, "read", "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(root);
CU_ASSERT_PTR_NOT_NULL(lnk);
CU_ASSERT_PTR_EQUAL(lnk->parent, root);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)lnk);
CU_ASSERT_STRING_EQUAL( lnk->name, "read");
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_symlink*)lnk)->dest,
"/tmp/libisofs_test/README" );
CU_ASSERT( S_ISLNK(lnk->attrib.st_mode) );
iso_tree_free((struct iso_tree_node *)root);
}
static void test_add_node() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test addition of a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_PTR_EQUAL(node->parent, root);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_PTR_EQUAL(root->children[0], node);
CU_ASSERT_STRING_EQUAL( node->name, "dir1");
CU_ASSERT( ISO_ISDIR(node) );
CU_ASSERT( S_ISDIR(node->attrib.st_mode) );
/* test addition of a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_PTR_EQUAL(node->parent, root);
CU_ASSERT_EQUAL(root->nchildren, 2);
CU_ASSERT_PTR_EQUAL(root->children[1], node);
CU_ASSERT( ISO_ISLNK(node) );
CU_ASSERT( S_ISLNK(node->attrib.st_mode) );
CU_ASSERT_STRING_EQUAL( node->name, "link to readme");
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_symlink*)node)->dest,
"/tmp/libisofs_test/README" );
/* test addition of a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_PTR_EQUAL(node->parent, root);
CU_ASSERT_EQUAL(root->nchildren, 3);
CU_ASSERT_PTR_EQUAL(root->children[2], node);
CU_ASSERT( S_ISREG(node->attrib.st_mode) );
CU_ASSERT( ISO_ISREG(node) );
CU_ASSERT_STRING_EQUAL( node->name, "README" );
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_file *) node)->path,
"/tmp/libisofs_test/README" );
/* test no exiting file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/THISNOTEXIST");
CU_ASSERT_PTR_NULL(node);
CU_ASSERT_EQUAL(libisofs_errno, NO_FILE);
CU_ASSERT_EQUAL(root->nchildren, 3);
/* test no valid file */
node = iso_tree_add_node(root, "/dev/zero");
CU_ASSERT_PTR_NULL(node);
CU_ASSERT_EQUAL(libisofs_errno, UNEXPECTED_FILE_TYPE);
CU_ASSERT_EQUAL(root->nchildren, 3);
/* test no read perm file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/no_read");
CU_ASSERT_PTR_NULL(node);
CU_ASSERT_EQUAL(libisofs_errno, NO_READ_ACCESS);
CU_ASSERT_EQUAL(root->nchildren, 3);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_radd_dir() {
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *child;
struct iso_tree_node_file *file;
struct iso_tree_radd_dir_behavior behavior = {0,0,0};
//TODO write really full test
root = iso_tree_new_root();
CU_ASSERT_PTR_NOT_NULL(root);
iso_tree_radd_dir(root, "/tmp/libisofs_test", &behavior);
/* test _root_ children */
/*
child = (struct iso_tree_node_dir *)root->children[0];
CU_ASSERT( S_ISDIR(child->node.attrib.st_mode) );
CU_ASSERT_EQUAL( child->nchildren, 2);
CU_ASSERT_STRING_EQUAL( child->node.name, "dir1" );
child = (struct iso_tree_node_dir *)root->children[1];
CU_ASSERT( S_ISDIR(child->node.attrib.st_mode) );
CU_ASSERT_EQUAL( child->nchildren, 0);
CU_ASSERT_STRING_EQUAL( child->node.name, "dir2" );
file = (struct iso_tree_node_file *)root->children[2];
CU_ASSERT( S_ISREG(file->node.attrib.st_mode) );
CU_ASSERT_STRING_EQUAL( file->node.name, "README" );
*/
//iso_tree_print( (struct iso_tree_node *)root, 4 );
}
static void test_set_name() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_STRING_EQUAL( node->name, "dir1");
iso_tree_node_set_name(node, "newname");
CU_ASSERT_STRING_EQUAL( node->name, "newname");
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_STRING_EQUAL( node->name, "link to readme");
iso_tree_node_set_name(node, "new link name");
CU_ASSERT_STRING_EQUAL( node->name, "new link name");
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_STRING_EQUAL( node->name, "README" );
iso_tree_node_set_name(node, "new file name");
CU_ASSERT_STRING_EQUAL( node->name, "new file name");
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_hidden() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->hide_flags, 0);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_JOLIET);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->hide_flags, 0);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_JOLIET);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->hide_flags, 0);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_JOLIET);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_gid() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
gid_t mygid = getgid();
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_gid, mygid);
iso_tree_node_set_gid(node, 1234);
CU_ASSERT_EQUAL(node->attrib.st_gid, 1234);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_gid, mygid);
iso_tree_node_set_gid(node, 1234);
CU_ASSERT_EQUAL(node->attrib.st_gid, 1234);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_gid, mygid);
iso_tree_node_set_gid(node, 1234);
CU_ASSERT_EQUAL(node->attrib.st_gid, 1234);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_uid() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
uid_t myuid = getuid();
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_uid, myuid);
iso_tree_node_set_uid(node, 1234);
CU_ASSERT_EQUAL(node->attrib.st_uid, 1234);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_uid, myuid);
iso_tree_node_set_uid(node, 1234);
CU_ASSERT_EQUAL(node->attrib.st_uid, 1234);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_uid, myuid);
iso_tree_node_set_uid(node, 1234);
CU_ASSERT_EQUAL(node->attrib.st_uid, 1234);
//TODO
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_permissions() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0755);
iso_tree_node_set_permissions(node, 0777);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0777);
iso_tree_node_set_permissions(node, 0744);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0744);
iso_tree_node_set_permissions(node, 0411);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0411);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0777);
iso_tree_node_set_permissions(node, 0555);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0555);
iso_tree_node_set_permissions(node, 0744);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0744);
iso_tree_node_set_permissions(node, 0411);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0411);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_PTR_NOT_NULL(node);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0555);
iso_tree_node_set_permissions(node, 0777);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0777);
iso_tree_node_set_permissions(node, 0744);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0744);
iso_tree_node_set_permissions(node, 0411);
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0411);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_sort_weight() {
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *dir;
struct iso_tree_node_file *file;
root = iso_tree_new_root();
dir = iso_tree_add_dir(root, "New dir name");
CU_ASSERT_PTR_NOT_NULL(dir);
file = (struct iso_tree_node_file *)
iso_tree_add_file(dir, "/tmp/libisofs_test/README");
CU_ASSERT_EQUAL(file->sort_weight, 0);
iso_tree_node_set_sort_weight((struct iso_tree_node *) file, 15);
CU_ASSERT_EQUAL(file->sort_weight, 15);
iso_tree_node_set_sort_weight((struct iso_tree_node *) file, -15);
CU_ASSERT_EQUAL(file->sort_weight, -15);
/* changes to dir involve update files inside it */
iso_tree_node_set_sort_weight((struct iso_tree_node *) dir, 28);
CU_ASSERT_EQUAL(file->sort_weight, 28);
iso_tree_free((struct iso_tree_node *)root);
}
void add_tree_suite()
{
CU_pSuite pSuite = CU_add_suite("TreeSuite", NULL, NULL);
CU_add_test(pSuite, "test of iso_tree_new_root()", test_new_root);
CU_add_test(pSuite, "test of iso_tree_add_dir()", test_add_dir);
CU_add_test(pSuite, "test of iso_tree_add_file()", test_add_file);
CU_add_test(pSuite, "test of iso_tree_add_symlink()", test_add_symlink);
CU_add_test(pSuite, "test of iso_tree_add_node()", test_add_node);
CU_add_test(pSuite, "test of iso_tree_radd_dir()", test_radd_dir);
CU_add_test(pSuite, "test of iso_tree_node_set_name()", test_set_name);
CU_add_test(pSuite, "test of iso_tree_node_set_hidden()", test_set_hidden);
CU_add_test(pSuite, "test of iso_tree_node_set_gid()", test_set_gid);
CU_add_test(pSuite, "test of iso_tree_node_set_uid()", test_set_uid);
CU_add_test(pSuite, "test of iso_tree_node_set_permissions()", test_set_permissions);
CU_add_test(pSuite, "test of iso_tree_node_set_sort_weight()", test_set_sort_weight);
}

View File

@ -1,265 +0,0 @@
/*
* Unit test for util.h
*
* This test utiliy functions
*
*/
#include "test.h"
#include "util.h"
static void test_div_up()
{
CU_ASSERT_EQUAL( div_up(1, 2), 1 );
CU_ASSERT_EQUAL( div_up(2, 2), 1 );
CU_ASSERT_EQUAL( div_up(0, 2), 0 );
CU_ASSERT_EQUAL( div_up(-1, 2), 0 );
CU_ASSERT_EQUAL( div_up(3, 2), 2 );
}
static void test_round_up()
{
CU_ASSERT_EQUAL( round_up(1, 2), 2 );
CU_ASSERT_EQUAL( round_up(2, 2), 2 );
CU_ASSERT_EQUAL( round_up(0, 2), 0 );
CU_ASSERT_EQUAL( round_up(-1, 2), 0 );
CU_ASSERT_EQUAL( round_up(3, 2), 4 );
CU_ASSERT_EQUAL( round_up(15, 7), 21 );
CU_ASSERT_EQUAL( round_up(13, 7), 14 );
CU_ASSERT_EQUAL( round_up(14, 7), 14 );
}
static void test_iso_lsb_msb()
{
uint8_t buf[4];
uint32_t num;
num = 0x01020304;
iso_lsb(buf, num, 4);
CU_ASSERT_EQUAL( buf[0], 0x04 );
CU_ASSERT_EQUAL( buf[1], 0x03 );
CU_ASSERT_EQUAL( buf[2], 0x02 );
CU_ASSERT_EQUAL( buf[3], 0x01 );
iso_msb(buf, num, 4);
CU_ASSERT_EQUAL( buf[0], 0x01 );
CU_ASSERT_EQUAL( buf[1], 0x02 );
CU_ASSERT_EQUAL( buf[2], 0x03 );
CU_ASSERT_EQUAL( buf[3], 0x04 );
iso_lsb(buf, num, 2);
CU_ASSERT_EQUAL( buf[0], 0x04 );
CU_ASSERT_EQUAL( buf[1], 0x03 );
iso_msb(buf, num, 2);
CU_ASSERT_EQUAL( buf[0], 0x03 );
CU_ASSERT_EQUAL( buf[1], 0x04 );
}
static void test_iso_1_dirid()
{
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dir1", "UTF-8"), "DIR1" );
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dIR1", "UTF-8"), "DIR1" );
CU_ASSERT_STRING_EQUAL( iso_1_dirid("DIR1", "UTF-8"), "DIR1" );
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dirwithbigname", "UTF-8"), "DIRWITHB");
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dirwith8", "UTF-8"), "DIRWITH8");
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dir.1", "UTF-8"), "DIR_1");
CU_ASSERT_STRING_EQUAL( iso_1_dirid("4f<0KmM::xcvf", "UTF-8"), "4F_0KMM_");
}
static void test_iso_2_dirid()
{
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dir1", "UTF-8"), "DIR1" );
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dIR1", "UTF-8"), "DIR1" );
CU_ASSERT_STRING_EQUAL( iso_2_dirid("DIR1", "UTF-8"), "DIR1" );
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dirwithbigname", "UTF-8"), "DIRWITHBIGNAME");
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dirwith8", "UTF-8"), "DIRWITH8");
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dir.1", "UTF-8"), "DIR_1");
CU_ASSERT_STRING_EQUAL( iso_2_dirid("4f<0KmM::xcvf", "UTF-8"), "4F_0KMM__XCVF");
CU_ASSERT_STRING_EQUAL( iso_2_dirid("directory with 31 characters ok", "UTF-8"), "DIRECTORY_WITH_31_CHARACTERS_OK");
CU_ASSERT_STRING_EQUAL( iso_2_dirid("directory with more than 31 characters", "UTF-8"), "DIRECTORY_WITH_MORE_THAN_31_CHA");
}
static void test_iso_r_dirid()
{
int flag;
/* 1. only ECMA119_37_CHAR_FILENAMES */
flag = ECMA119_37_CHAR_FILENAMES;
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "DIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "DIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "DIRWITHBIGNAME");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "DIRWITH8");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "DIR_1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4F_0KMM__XCVF");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "DIRECTORY_WITH_31_CHARACTERS_OK");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "DIRECTORY_WITH_MORE_THAN_37_CHARACTER");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "DIRECTORY_WITH_JUST_37_CHARACTERS__OK");
/* 2. only ECMA119_RELAXED_FILENAMES */
flag = ECMA119_RELAXED_FILENAMES;
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "dir1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "dIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "dirwithbigname");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "dirwith8");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "dir.1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4f<0KmM::xcvf");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "directory with 31 characters ok");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "directory with more than 37 cha");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "directory with just 37 characte");
/* 3. both ECMA119_RELAXED_FILENAMES and ECMA119_37_CHAR_FILENAMES */
flag = ECMA119_RELAXED_FILENAMES | ECMA119_37_CHAR_FILENAMES;
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "dir1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "dIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "dirwithbigname");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "dirwith8");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "dir.1");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4f<0KmM::xcvf");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "directory with 31 characters ok");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "directory with more than 37 character");
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "directory with just 37 characters ok");
}
static void test_iso_1_fileid()
{
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file1", "UTF-8"), "FILE1.;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fILe1", "UTF-8"), "FILE1.;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("FILE1", "UTF-8"), "FILE1.;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid(".EXT", "UTF-8"), ".EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ext", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fiLE.ext", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.EXt", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("FILE.EXT", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename", "UTF-8"), "BIGFILEN.;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.ext", "UTF-8"), "BIGFILEN.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.e", "UTF-8"), "BIGFILEN.E;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.bigext", "UTF-8"), "FILE.BIG;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid(".bigext", "UTF-8"), ".BIG;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.bigext", "UTF-8"), "BIGFILEN.BIG;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file<:a.ext", "UTF-8"), "FILE__A.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.<:a", "UTF-8"), "FILE.__A;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file<:a.--a", "UTF-8"), "FILE__A.__A;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ex1.ex2", "UTF-8"), "FILE_EX1.EX2;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ex1.ex2.ex3", "UTF-8"), "FILE_EX1.EX3;1");
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fil.ex1.ex2.ex3", "UTF-8"), "FIL_EX1_.EX3;1");
}
static void test_iso_2_fileid()
{
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file1", "UTF-8"), "FILE1.;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fILe1", "UTF-8"), "FILE1.;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("FILE1", "UTF-8"), "FILE1.;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".EXT", "UTF-8"), ".EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ext", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fiLE.ext", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.EXt", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("FILE.EXT", "UTF-8"), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename", "UTF-8"), "BIGFILENAME.;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.ext", "UTF-8"), "BIGFILENAME.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.e", "UTF-8"), "BIGFILENAME.E;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("31 characters filename.extensio", "UTF-8"), "31_CHARACTERS_FILENAME.EXTENSIO;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("32 characters filename.extension", "UTF-8"), "32_CHARACTERS_FILENAME.EXTENSIO;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("more than 30 characters filename.extension", "UTF-8"), "MORE_THAN_30_CHARACTERS_FIL.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.bigext", "UTF-8"), "FILE.BIGEXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".bigext", "UTF-8"), ".BIGEXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.bigext", "UTF-8"), "BIGFILENAME.BIGEXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file<:a.ext", "UTF-8"), "FILE__A.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.<:a", "UTF-8"), "FILE.__A;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file<:a.--a", "UTF-8"), "FILE__A.__A;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ex1.ex2", "UTF-8"), "FILE_EX1.EX2;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ex1.ex2.ex3", "UTF-8"), "FILE_EX1_EX2.EX3;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fil.ex1.ex2.ex3", "UTF-8"), "FIL_EX1_EX2.EX3;1");
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".file.bigext", "UTF-8"), "_FILE.BIGEXT;1");
}
static void test_iso_r_fileid()
{
int flag;
/* 1. only ECMA119_OMIT_VERSION_NUMBERS */
flag = ECMA119_OMIT_VERSION_NUMBERS;
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "FILE1.");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "FILE1.");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31_CHARACTERS_FILENAME.EXTENSIO");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "IT_S_37_CHARACTERS_FILENAME.EXT");
/* 2. only ECMA119_37_CHAR_FILENAMES */
flag = ECMA119_37_CHAR_FILENAMES;
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "FILE1.");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "FILE1.");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1.");
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "FILE.EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "FILE.EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "FILE.EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "BIGFILENAME.");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "BIGFILENAME.EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "BIGFILENAME.E");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "FILE.BIGEXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31_CHARACTERS_FILENAME.EXTENSIO");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "IT_S_37_CHARACTERS_FILENAME.EXTENSION");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("more than 37 characters filename.extension", "UTF-8", flag), "MORE_THAN_37_CHARACTERS_FILENAME.EXTE");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "FILE.THIS_IS_A_37_CHARS_LEN_EXTENSION");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a very very big extension", "UTF-8", flag), "FILE.THIS_IS_A_VERY_VERY_BIG_EXTENSIO");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "FIL_EX1_EX2.EX3");
/* 3. only ECMA119_RELAXED_FILENAMES */
flag = ECMA119_RELAXED_FILENAMES;
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "file1;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "fILe1;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "file.ext;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "fiLE.ext;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "file.EXt;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "bigfilename;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "bigfilename.ext;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "bigfilename.e;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "file.bigext;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31 characters filename.extensio;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "it's 37 characters filename.ext;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "file.this is a 37 chars len ext;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "fil.ex1.ex2.ex3;1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.<:a", "UTF-8", flag), "file.<:a;1");
/* 3. ECMA119_RELAXED_FILENAMES and ECMA119_OMIT_VERSION_NUMBERS*/
flag = ECMA119_RELAXED_FILENAMES | ECMA119_OMIT_VERSION_NUMBERS;
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "file1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "fILe1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1");
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "file.ext");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "fiLE.ext");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "file.EXt");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "bigfilename");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "bigfilename.ext");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "bigfilename.e");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "file.bigext");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31 characters filename.extensio");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "it's 37 characters filename.ext");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "file.this is a 37 chars len ext");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "fil.ex1.ex2.ex3");
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.<:a", "UTF-8", flag), "file.<:a");
}
void add_util_suite()
{
CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
CU_add_test(pSuite, "test of div_up()", test_div_up);
CU_add_test(pSuite, "test of round_up()", test_round_up);
CU_add_test(pSuite, "test of iso_lsb_msb()", test_iso_lsb_msb);
CU_add_test(pSuite, "test of iso_1_dirid()", test_iso_1_dirid);
CU_add_test(pSuite, "test of iso_2_dirid()", test_iso_2_dirid);
CU_add_test(pSuite, "test of iso_r_dirid()", test_iso_r_dirid);
CU_add_test(pSuite, "test of iso_1_fileid()", test_iso_1_fileid);
CU_add_test(pSuite, "test of iso_2_fileid()", test_iso_2_fileid);
CU_add_test(pSuite, "test of iso_r_fileid()", test_iso_r_fileid);
}

View File

@ -1,238 +0,0 @@
/*
* Unit test for volume.h
*/
#include "libisofs.h"
#include "tree.h"
#include "test.h"
#include "volume.h"
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
static void test_iso_volume_new()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NOT_NULL(volume);
CU_ASSERT_EQUAL(volume->refcount, 1);
/* a new root must be created */
CU_ASSERT_PTR_NOT_NULL(volume->root);
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
CU_ASSERT_PTR_NULL(volume->system_id);
CU_ASSERT_PTR_NULL(volume->application_id);
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
CU_ASSERT_PTR_NULL(volume->bootcat);
iso_volume_free(volume);
}
static void test_iso_volume_new_with_root()
{
struct iso_volume *volume;
struct iso_tree_node_dir *root;
root = iso_tree_new_root();
volume = iso_volume_new_with_root("volume_id", "publisher_id",
"data_preparer_id", root);
CU_ASSERT_PTR_NOT_NULL(volume);
CU_ASSERT_EQUAL(volume->refcount, 1);
CU_ASSERT_PTR_NOT_NULL(volume->root);
CU_ASSERT_PTR_EQUAL(volume->root, root);
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
CU_ASSERT_PTR_NULL(volume->system_id);
CU_ASSERT_PTR_NULL(volume->application_id);
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
CU_ASSERT_PTR_NULL(volume->bootcat);
iso_volume_free(volume);
}
static void test_iso_volume_get_root()
{
struct iso_volume *volume;
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *root2;
root = iso_tree_new_root();
volume = iso_volume_new_with_root("volume_id", "publisher_id",
"data_preparer_id", root);
root2 = iso_volume_get_root(volume);
CU_ASSERT_PTR_NOT_NULL(root2);
CU_ASSERT_PTR_EQUAL(root2, volume->root);
CU_ASSERT_PTR_EQUAL(root2, root);
iso_volume_free(volume);
}
static void test_iso_volume_set_volume_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
char *volid = "new volume id";
iso_volume_set_volume_id(volume, volid);
CU_ASSERT_STRING_EQUAL( volume->volume_id, "new volume id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->volume_id, volid );
iso_volume_free(volume);
}
static void test_iso_volume_set_publisher_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
char *pubid = "new publisher id";
iso_volume_set_publisher_id(volume, pubid);
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "new publisher id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->publisher_id, pubid );
iso_volume_free(volume);
}
static void test_iso_volume_set_data_preparer_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
char *dpid = "new data preparer id";
iso_volume_set_data_preparer_id(volume, dpid);
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "new data preparer id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->data_preparer_id, dpid );
iso_volume_free(volume);
}
static void test_iso_volume_set_system_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(volume->system_id);
char *sysid = "new system id";
iso_volume_set_system_id(volume, sysid);
CU_ASSERT_STRING_EQUAL( volume->system_id, "new system id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->system_id, sysid );
iso_volume_free(volume);
}
static void test_iso_volume_set_application_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(volume->application_id);
char *appid = "new application id";
iso_volume_set_application_id(volume, appid);
CU_ASSERT_STRING_EQUAL( volume->application_id, "new application id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->application_id, appid );
iso_volume_free(volume);
}
static void test_iso_volume_set_abstract_file_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
char *absid = "new abstract id";
iso_volume_set_abstract_file_id(volume, absid);
CU_ASSERT_STRING_EQUAL( volume->abstract_file_id, "new abstract id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->abstract_file_id, absid );
iso_volume_free(volume);
}
static void test_iso_volume_set_biblio_file_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
char *bibid = "new biblio id";
iso_volume_set_biblio_file_id(volume, bibid);
CU_ASSERT_STRING_EQUAL( volume->biblio_file_id, "new biblio id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->biblio_file_id, bibid );
iso_volume_free(volume);
}
static void test_iso_volset_new()
{
struct iso_volume *volume;
struct iso_volset *volset;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
volset = iso_volset_new(volume, "volset_id");
CU_ASSERT_PTR_NOT_NULL(volset);
CU_ASSERT_EQUAL(volset->refcount, 1);
CU_ASSERT_EQUAL(volset->volset_size, 1);
CU_ASSERT_PTR_NOT_NULL(volset->volume);
CU_ASSERT_PTR_NOT_NULL(volset->volume[0]);
CU_ASSERT_PTR_EQUAL(volset->volume[0], volume);
CU_ASSERT_STRING_EQUAL( volset->volset_id, "volset_id" );
iso_volset_free(volset);
}
void add_volume_suite()
{
CU_pSuite pSuite = CU_add_suite("VolumeSuite", NULL, NULL);
CU_add_test(pSuite, "test of iso_volume_new()", test_iso_volume_new);
CU_add_test(pSuite, "test of iso_volume_new_with_root()", test_iso_volume_new_with_root);
CU_add_test(pSuite, "test of iso_volume_get_root()", test_iso_volume_get_root);
CU_add_test(pSuite, "test of iso_volume_set_volume_id()", test_iso_volume_set_volume_id);
CU_add_test(pSuite, "test of iso_volume_set_publisher_id()", test_iso_volume_set_publisher_id);
CU_add_test(pSuite, "test of iso_volume_set_data_preparer_id()", test_iso_volume_set_data_preparer_id);
CU_add_test(pSuite, "test of iso_volume_set_system_id()", test_iso_volume_set_system_id);
CU_add_test(pSuite, "test of iso_volume_set_application_id()", test_iso_volume_set_application_id);
CU_add_test(pSuite, "test of iso_volume_set_abstract_file_id()", test_iso_volume_set_abstract_file_id);
CU_add_test(pSuite, "test of iso_volume_set_biblio_file_id()", test_iso_volume_set_biblio_file_id);
CU_add_test(pSuite, "test of iso_volset_new()", test_iso_volset_new);
}