Browse Source

Implemented numeber of multisession options, reading, modifying tree, and a number of improvements

master
Mario Danic 15 years ago
parent
commit
0b1a9c5565
  1. 14
      ChangeLog
  2. 26
      Makefile.am
  3. 14
      TODO
  4. 88
      libisofs/ecma119.c
  5. 3
      libisofs/ecma119.h
  6. 8
      libisofs/eltorito.c
  7. 9
      libisofs/exclude.c
  8. 7
      libisofs/exclude.h
  9. 73
      libisofs/file.c
  10. 4
      libisofs/file.h
  11. 404
      libisofs/libisofs.h
  12. 2
      libisofs/rockridge.c
  13. 246
      libisofs/tree.c
  14. 82
      libisofs/tree.h
  15. 29
      libisofs/util.c
  16. 15
      libisofs/util.h
  17. 76
      libisofs/volume.c
  18. 18
      test/iso.c
  19. 2
      test/test.c
  20. 4
      test/test.h
  21. 108
      test/test_ecma119_tree.c
  22. 92
      test/test_file_hashtable.c
  23. 728
      test/test_tree.c
  24. 142
      test/test_util.c
  25. 137
      test/test_volume.c

14
ChangeLog

@ -1 +1,13 @@
nothing here now
Development
===========
- Support for reading of plain iso images.
- Support for reading RR extensions
Version 0.2.8
=============
TODO

26
Makefile.am

@ -33,7 +33,12 @@ libisofs_libisofs_la_SOURCES = \
libisofs/file.h \
libisofs/file.c \
libisofs/eltorito.h \
libisofs/eltorito.c
libisofs/eltorito.c \
libisofs/data_source.c \
libisofs/ecma119_read.h \
libisofs/ecma119_read.c \
libisofs/ecma119_read_rr.h \
libisofs/ecma119_read_rr.c
libinclude_HEADERS = \
libisofs/libisofs.h
@ -42,12 +47,27 @@ libinclude_HEADERS = \
## Build test applications
noinst_PROGRAMS = \
test/iso
test/iso \
test/isoread \
test/isoms \
test/isoadd
test_iso_CPPFLAGS = -Ilibisofs
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_iso_SOURCES = test/iso.c
test_isoread_CPPFLAGS = -Ilibisofs
test_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoread_SOURCES = test/iso_read.c
test_isoms_CPPFLAGS = -Ilibisofs
test_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoms_SOURCES = test/iso_ms.c
test_isoadd_CPPFLAGS = -Ilibisofs
test_isoadd_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoadd_SOURCES = test/iso_add.c
## Build unit test
check_PROGRAMS = \
@ -64,6 +84,8 @@ test_test_SOURCES = \
test/test_file_hashtable.c \
test/test_util.c \
test/test_volume.c \
test/test_data_source.c \
test/test_read.c \
test/test.c
## ========================================================================= ##

14
TODO

@ -5,9 +5,14 @@ FEATURES
Support for multiple images
HFS/HFS+
CD reading
[ok] plain iso
[ok] Rock Ridge
Joliet
Merge RR and Joliet trees
User options to customize reading
Multisession
UDF
ISO relaxed contraints
[ok] ISO relaxed contraints
ISO 9660:1998
Support for special files (only dirs, reg. files and symlinks are supported).
@ -15,6 +20,9 @@ FEATURES
TESTS
=====
[several done]
Test all util.h functions, especially date-related ones
Test for RR read functions
For all
IMPLEMENTATION
@ -22,8 +30,10 @@ 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
add charset management on image reading
use iso-8859-1 instead of UTF-8 dor RR?
Improve date handling

88
libisofs/ecma119.c

@ -246,7 +246,14 @@ calc_file_pos(struct ecma119_write_target *t,
do {
struct iso_file *file = node->file;
if (file->size)
/*
* We only need to write the file when.
* a) The size is greater than 0.
* b) The file is new (not from a previous image) or we
* are writting an image not for ms (i.e., we are modifying an
* image).
*/
if ( file->size && (!file->prev_img || !t->ms_block) )
t->filelist[t->curfile++] = file;
node = node->next;
} while (node);
@ -307,6 +314,9 @@ ecma119_target_new(struct iso_volset *volset,
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->ms_block = opts->ms_block;
t->src = opts->src;
t->file_table = iso_file_table_new(t->cache_inodes);
volset->refcount++;
@ -356,7 +366,8 @@ ecma119_target_new(struct iso_volset *volset,
}
}
t->curblock = 16 /* system area */
t->curblock = t->ms_block /* nwa for ms, usually 0 */
+ 16 /* system area */
+ 1 /* volume desc */
+ 1; /* volume desc terminator */
@ -409,6 +420,9 @@ ecma119_target_new(struct iso_volset *volset,
}
t->total_size = t->curblock * t->block_size;
//TODO how needs to be here for ms?
// a change here requires changes in bs_read!!
t->vol_space_size = t->curblock;
/* prepare for writing */
@ -489,31 +503,51 @@ 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;
if (f->prev_img) {
int block;
assert( !t->ms_block && t->src );
if (!f_st->fd) {
printf("Writing file %s\n", path);
f_st->data_len = f->size;
f_st->fd = fopen(path, "r");
if (!f_st->fd)
err(1, "couldn't open %s for reading", path);
assert(t->curblock == f->block);
}
nread = fread(buf, 1, t->block_size, f_st->fd);
f_st->pos += t->block_size;
if (nread < 0)
warn("problem reading from %s", path);
else if (nread != t->block_size && f_st->pos < f_st->data_len)
warnx("incomplete read from %s", path);
if (f_st->pos >= f_st->data_len) {
fclose(f_st->fd);
f_st->fd = 0;
f_st->pos = 0;
f_st->file++;
if (f_st->file >= t->filelist_len)
next_state(t);
/**
* f->block block where file read begins
* t->curblock block we're writting now
* f->real_ino initial block for file on source
*/
block = t->curblock - f->block;
if ( t->src->read_block(t->src, f->real_ino + block, buf) ) {
warn("problem reading from previous image");
}
if ( f->size <= (off_t) (block+1) * t->block_size ) {
f_st->file++;
if (f_st->file >= t->filelist_len)
next_state(t);
}
} else {
const char *path = f->path;
if (!f_st->fd) {
printf("Writing file %s\n", path);
f_st->data_len = f->size;
f_st->fd = fopen(path, "r");
if (!f_st->fd)
err(1, "couldn't open %s for reading", path);
assert(t->curblock + t->ms_block == f->block);
}
nread = fread(buf, 1, t->block_size, f_st->fd);
f_st->pos += t->block_size;
if (nread < 0)
warn("problem reading from %s", path);
else if (nread != t->block_size && f_st->pos < f_st->data_len)
warnx("incomplete read from %s", path);
if (f_st->pos >= f_st->data_len) {
fclose(f_st->fd);
f_st->fd = 0;
f_st->pos = 0;
f_st->file++;
if (f_st->file >= t->filelist_len)
next_state(t);
}
}
}
@ -790,7 +824,7 @@ bs_read(struct burn_source *bs, unsigned char *buf, int size)
warnx("you must read data in block-sized chunks (%d bytes)",
(int)t->block_size);
return 0;
} else if (t->curblock >= t->vol_space_size) {
} else if (t->curblock + t->ms_block >= t->vol_space_size) {
return 0;
}
if (t->state_data_valid)

3
libisofs/ecma119.h

@ -98,6 +98,9 @@ struct ecma119_write_target
*/
ino_t ino;
uint32_t ms_block; /**< if != 0, nwa for multisession */
struct data_source* src;
int curblock;
uint16_t block_size;
uint32_t path_table_size;

8
libisofs/eltorito.c

@ -125,7 +125,7 @@ create_image(struct iso_tree_node *image,
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);
fd = open(((struct iso_tree_node_file*)image)->loc.path, O_RDONLY);
if ( fd == -1 ) {
fprintf(stderr, "Can't open image file\n");
return NULL;
@ -344,10 +344,10 @@ patch_boot_file(struct el_torito_boot_image *img)
memset(&info, 0, sizeof(info));
/* open image */
fd = open(img->image->path, O_RDWR);
fd = open(img->image->loc.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);
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path);
close(fd);
return;
}
@ -364,7 +364,7 @@ patch_boot_file(struct el_torito_boot_image *img)
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);
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path);
close(fd);
return;
}

9
libisofs/exclude.c

@ -9,15 +9,6 @@ iso_exclude_add_path(struct iso_hash_table *table, const char *path)
table->num += iso_hash_insert(table->table, path);
}
/*void
iso_exclude_remove_path(struct iso_hash_table *table, const char *path)
{
if (!table->num || !path)
return;
table->num -= iso_hash_remove(table->table, path);
}*/
void
iso_exclude_empty(struct iso_hash_table *table)
{

7
libisofs/exclude.h

@ -22,13 +22,6 @@ int iso_exclude_lookup(struct iso_hash_table *table, const char *path);
*/
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.
*/

73
libisofs/file.c

@ -8,17 +8,30 @@
#include "file.h"
#include "tree.h"
//TODO: refactor both hash and this hash table into a single one!!
//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 */
if (f->node.procedence == LIBISO_NEW) {
file->path = f->loc.path; /*TODO strdup? it needs to be free on clear then */
file->real_dev = f->node.attrib.st_dev;
file->real_ino = f->node.attrib.st_ino;
} else {
file->block = f->loc.block;
file->prev_img = 1;
file->real_dev = 0; /* we use 0 as dev for prev. session files */
/* don't take care about inode number read from RR TX, block
* number is good enouht for this. Moreover, when we are modifying
* an image, we will modify file->block with the block where the
* file needs to be written in the new image. So, we store the block
* in original image here, because we will need to use it for
* reading file contents */
file->real_ino = f->loc.block;
}
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;
}
@ -98,6 +111,13 @@ static int
iso_table_compare_files(struct iso_file_table *ft,
struct iso_file *f1, struct iso_file *f2)
{
assert(ft && f1 && f2);
if (f1->prev_img || f2->prev_img) {
if (f1->prev_img && f2->prev_img)
return f1->real_ino != f2->real_ino;
else
return 1;
}
if (ft->cache_inodes) {
return (f1->real_dev != f2->real_dev) || (f1->real_ino != f2->real_ino);
} else {
@ -111,8 +131,12 @@ iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
struct iso_file_hash_node *node;
unsigned int hash_num;
assert(ft && f);
/* find the hash number */
if (ft->cache_inodes)
if (f->prev_img)
hash_num = f->real_ino % FILE_HASH_NODES;
else 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);
@ -146,6 +170,27 @@ iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
return 1;
}
/** 0 on equal, != 0 otherwise */
static int
iso_table_compare_node_file(struct iso_file_table *ft,
struct iso_tree_node_file *f1, struct iso_file *f2)
{
assert(ft && f1 && f2);
if (f1->node.procedence || f2->prev_img) {
if (f1->node.procedence && f2->prev_img)
return f1->loc.block != f2->real_ino;
else
return 1;
}
if (ft->cache_inodes) {
return (f1->node.attrib.st_dev != f2->real_dev)
|| (f1->node.attrib.st_ino != f2->real_ino);
} else {
return strcmp(f1->loc.path, f2->path);
}
}
struct iso_file *
iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
{
@ -153,32 +198,30 @@ iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
unsigned int hash_num;
int equal;
assert(ft && f);
/* find the hash number */
if ( ft->cache_inodes )
if (f->node.procedence == LIBISO_PREVIMG)
hash_num = f->loc.block % FILE_HASH_NODES;
else 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);
hash_num = iso_file_table_hash(f->loc.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);
equal = !iso_table_compare_node_file(ft, f, node->file);
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);
equal = !iso_table_compare_node_file(ft, f, node->file);
if (equal)
return node->file;
}

4
libisofs/file.h

@ -17,14 +17,16 @@
#ifndef FILE_H_
#define FILE_H_
#include <stdint.h>
#define FILE_HASH_NODES 2048
struct iso_file {
unsigned int prev_img:1; /**< if the file comes from a previous image */
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 */
uint32_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;

404
libisofs/libisofs.h

@ -13,6 +13,7 @@
#define LIBISO_LIBISOFS_H
#include <sys/types.h>
#include <stdint.h>
/* #include <libburn.h> */
struct burn_source;
@ -31,15 +32,43 @@ struct iso_volset;
/**
* A node in the filesystem tree.
*
* This is opaque struct that represent any kind of nodes. When needed,
* you can get the type with iso_tree_node_get_type and cast it to the
* appropiate subtype:
*
* iso_tree_node_dir
* iso_tree_node_file
* iso_tree_node_symlink
*
* \see tree.h
*/
struct iso_tree_node;
/**
* El-Torito boot image
* \see eltorito.h
* The type of an iso_tree_node.
* When an user gets an iso_tree_node from libisofs, (s)he can use
* iso_tree_node_get_type to get the current type of the node, and then
* cast to the appropriate subtype. For example:
*
* struct iso_tree_node *node = iso... TODO
* if ( iso_tree_node_get_type(node) == LIBISO_NODE_DIR ) {
* struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *)node;
* ...
* }
*
* Useful macros are provided.
*/
struct el_torito_boot_image;
enum iso_tree_node_type {
LIBISO_NODE_DIR,
LIBISO_NODE_FILE,
LIBISO_NODE_SYMLINK,
LIBISO_NODE_BOOTCATALOG
};
#define LIBISO_ISDIR(n) (iso_tree_node_get_type(n) == LIBISO_NODE_DIR)
#define LIBISO_ISREG(n) (iso_tree_node_get_type(n) == LIBISO_NODE_FILE)
#define LIBISO_ISLNK(n) (iso_tree_node_get_type(n) == LIBISO_NODE_SYMLINK)
/**
* A directory in the filesystem tree.
@ -48,6 +77,44 @@ struct el_torito_boot_image;
*/
struct iso_tree_node_dir;
/**
* A node in the filesystem tree that represents a regular file
*/
struct iso_tree_node_file;
/**
* A node in the filesystem tree that represents a symbolic link
*/
struct iso_tree_node_symlink;
/**
* A node that represents a boot catalog
* FIXME I'm not very sure how this should be treated.
*/
struct iso_tree_node_boot_catalog;
/**
* El-Torito boot image
* \see eltorito.h
*/
struct el_torito_boot_image;
/** Iterator for dir children. */
struct iso_tree_iter;
/**
* The procedence of the node.
*/
enum tree_node_from {
/** The node has been added by the user */
LIBISO_NEW = 0,
/**
* The node comes from a previous image. That can be from a previous
* session on disc, or from an ISO file we want to modify.
*/
LIBISO_PREVIMG
};
/**
* 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
@ -155,6 +222,81 @@ struct ecma119_source_opts {
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 */
uint32_t ms_block;
/**<
* Start block for multisession. When this is greater than 0,
* it's suppossed to be the lba of the next writable address
* on disc; all block lba on image will take this into account,
* and files from a previous session will not be written on
* image. This behavior is only suitable for images to be
* appended to a multisession disc.
* When this is 0, no multisession image will be created. If
* some files are taken from a previous image, its contents
* will be written again to the new image. Use this with new
* images or if you plan to modify an existin image.
*/
struct data_source* src;
/**<
* When modifying a image, this is the source of the original
* image, used to read file contents.
* Otherwise it can be NULL.
*/
};
/**
* FIXME documentar isto!!!
*/
struct ecma119_read_opts {
int tree_to_read;
int block; /** Block where the image begins, usually 0, can be
* different on a multisession disc.
*/
//TODO....
unsigned int norock:1; /*< Do not read Rock Ridge extensions */
//nojoliet
//check -> convert names to lower case
//uid, gid (when no RR)
//file and dir mode (when no RR)
/* modified by the function */
unsigned int hasRR:1; /*< It will be set to 1 if RR extensions are present,
to 0 if not. */
//hasJoliet
int error;
};
/**
* Data source used by libisofs for reading an existing image.
* It contains suitable methods to read arbitrary block. Usually, the block
* size is 2048 bytes.
*/
struct data_source {
/**
* Reference count for the data source. Should be 1 when a new source
* is created. Increment it to take a reference for yourself. Use
* data_source_free to destroy your reference to it.
*/
int refcount;
/**
* Read data from the source.
* @param lba Block to be read.
* @param buffer Buffer where the data will be written. Its size must
* be at least 2048 bytes.
* @return
* 0 if ok, < 0 on error
*/
int (*read_block)(struct data_source *src, int lba, unsigned char *buffer);
/** Get the size (number of block) of the source's data */
int (*get_size)(struct data_source *);
/** Clean up the source specific data */
void (*free_data)(struct data_source *);
/** Source specific data */
void *data;
};
/**
@ -208,6 +350,11 @@ void iso_volume_free(struct iso_volume *volume);
*/
void iso_volset_free(struct iso_volset *volume);
/**
* Get a volume from a volume set.
*/
struct iso_volume *iso_volset_get_volume(struct iso_volset *volset, int volnum);
/**
* Get the root directory for a volume.
*/
@ -219,30 +366,65 @@ struct iso_tree_node_dir *iso_volume_get_root(const struct iso_volume *volume);
void iso_volume_set_volume_id(struct iso_volume *volume,
const char *volume_id);
/**
* Get the volume identifier.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_volume_id(struct iso_volume *volume);
/**
* Fill in the publisher for a volume.
*/
void iso_volume_set_publisher_id(struct iso_volume *volume,
const char *publisher_id);
/**
* Get the publisher of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_publisher_id(struct iso_volume *volume);
/**
* Fill in the data preparer for a volume.
*/
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id);
/**
* Get the data preparer of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_data_preparer_id(struct iso_volume *volume);
/**
* 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);
/**
* Get the system id of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_system_id(struct iso_volume *volume);
/**
* 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);
/**
* Get the application id of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_application_id(struct iso_volume *volume);
/**
* Fill copyright information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
@ -250,6 +432,13 @@ void iso_volume_set_application_id(struct iso_volume *volume,
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
const char *copyright_file_id);
/**
* Get the copyright information of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_copyright_file_id(struct iso_volume *volume);
/**
* Fill abstract information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
@ -257,6 +446,13 @@ void iso_volume_set_copyright_file_id(struct iso_volume *volume,
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
const char *abstract_file_id);
/**
* Get the abstract information of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_abstract_file_id(struct iso_volume *volume);
/**
* Fill biblio information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
@ -264,6 +460,13 @@ void iso_volume_set_abstract_file_id(struct iso_volume *volume,
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
const char *biblio_file_id);
/**
* Get the biblio information of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_biblio_file_id(struct iso_volume *volume);
/**
* Create a bootable volume by adding a El-Torito boot image.
*
@ -336,13 +539,12 @@ el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
* \param path The path, in the image, of the file.
*
* \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);
/**
* TODO I don't like this kind of functions here. I think it should be
* in genisofs
* Add a file or a directory (recursively) to a volume by specifying its path on the volume.
*
* \param volume The volume to add the file to.
@ -356,6 +558,8 @@ struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, co
// const char *path);
/**
* TODO I don't like this kind of functions here. I think it should be
* in genisofs
* Creates a new, empty directory on the volume.
*
* \param volume The volume to add the directory to.
@ -448,6 +652,9 @@ struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent,
const char *path);
/**
* TODO I don't like this kind of functions here. I think it should be
* in genisofs
*
* 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,
@ -462,11 +669,23 @@ struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent,
void iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior);
/**
* Get the type of an iso_tree_node
*/
enum iso_tree_node_type iso_tree_node_get_type(struct iso_tree_node *node);
/**
* 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);
/**
* Get the name of a tree node (using the current locale).
* The returned string belongs to the node and should not be modified nor
* freed. Use strdup if you really need your own copy.
*/
const char *iso_tree_node_get_name(struct iso_tree_node *node);
/**
* Set if the node will be hidden in RR/ISO tree, Joliet tree or both.
*
@ -485,18 +704,37 @@ void iso_tree_node_set_name(struct iso_tree_node *node, const char *name);
*/
void iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs);
/**
* Check if a node will be hidden in RR/ISO tree, Joliet tree or both.
*
* @return
* 0 if the node won't be hidden, otherwise you can AND the return value
* with hide_node_flag's to get in what trees the node will be hidden.
*/
int iso_tree_node_is_hidden(struct iso_tree_node *node);
/**
* 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);
/**
* Get the group id of the node.
*/
gid_t iso_tree_node_get_gid(struct iso_tree_node *node);
/**
* 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);
/**
* Get the user id of the node.
*/
uid_t iso_tree_node_get_uid(struct iso_tree_node *node);
/**
* Set the permissions for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
@ -507,6 +745,9 @@ void iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid);
*/
void iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode);
/** Get the permissions for the node */
mode_t iso_tree_node_get_permissions(struct iso_tree_node *node);
/**
* 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.
@ -519,6 +760,139 @@ void iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode);
*/
void iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w);
/**
* Sets the destination of a symbolic link
*/
void iso_tree_node_symlink_set_dest(struct iso_tree_node_symlink *node, const char *dest);
/**
* Get the destination of a symbolic link.
* The returned string is owned by libisofs and should not be freed nor modified.
*/
const char *iso_tree_node_symlink_get_dest(struct iso_tree_node_symlink *node);
/**
* Get an iterator for the children of the given dir.
* You can iterate over the children with iso_tree_iter_next. When finished,
* you should free the iterator with iso_tree_iter_free.
* You musn't delete a child of the same dir, using iso_tree_node_take() or
* iso_tree_node_remove(), while you're using the iterator. You can use
* iso_tree_node_take_iter() or iso_tree_node_remove_iter() instead.
*
* The usage of an iterator is:
*
* struct iso_tree_iter *iter;
* struct iso_tree_node *node;
* iter = iso_tree_node_children(dir);
* while ( (node = iso_tree_iter_next(iter)) != NULL ) {
* // do something with the child
* }
* iso_tree_iter_free(iter);
*
* An iterator is intended to be used in a single iteration over the
* children of a dir. Thus, it should be treated as a temporary object,
* and free as soon as possible.
*/
struct iso_tree_iter *iso_tree_node_children(struct iso_tree_node_dir *dir);
/**
* Get the next child.
* Take care that the node is owned by libisofs, and will be freed whit the
* tree it belongs. If you want your own ref to it, call iso_tree_node_ref()
* on it.
* This returns NULL if no more children are available.
*/
struct iso_tree_node *iso_tree_iter_next(struct iso_tree_iter *iter);
/** Free an iteration */
void iso_tree_iter_free(struct iso_tree_iter *iter);
/**
* Removes a child from a directory.
* The child is not freed, so you will become the owner of the node. Later
* you can add the node to another dir (calling iso_tree_add_child), or free
* it if you don't need it (with iso_tree_free).
*
* @return 0 on success, -1 if the node doesn't belong to the dir.
*/
int iso_tree_node_take(struct iso_tree_node_dir *dir,
struct iso_tree_node *node);
/**
* Removes a child from a directory and free (unref) it.
* If you want to keep the child alive, you need to iso_tree_node_ref() it
* before this call, but in that case iso_tree_node_take() is a better
* alternative.
*
* @return 0 on success, -1 if the node doesn't belong to the dir (in this
* last case the node is not freed).
*/
int iso_tree_node_remove(struct iso_tree_node_dir *dir,
struct iso_tree_node *node);
/**
* Removes a child from a directory during an iteration, without freeing it.
* It's like iso_tree_node_take(), but to be used during a directory
* iteration.
* The node removed will be the last returned by the iteration.
*
* The behavior on two call to this function without calling iso_tree_iter_next
* between then is undefined, and should never occur. (TODO protect against this?)
*
* @return 0 on success, < 0 on an invalid usage, i.e., if the user call this
* before an inicial iso_tree_iter_next() or if last
* iso_tree_iter_next() has returned NULL.
*/
int iso_tree_node_take_iter(struct iso_tree_iter *iter);
/**
* Removes a child from a directory during an iteration and free it.
* It's like iso_tree_node_remove(), but to be used during a directory
* iteration.
* The node removed will be the last returned by the iteration.
*
* The behavior on two call to this function without calling iso_tree_iter_next
* between then is undefined, and should never occur. (TODO protect against this?)
*
* @return 0 on success, < 0 on an invalid usage, i.e., if the user call this
* before an inicial iso_tree_iter_next() or if last
* iso_tree_iter_next() has returned NULL.
*/
int iso_tree_node_remove_iter(struct iso_tree_iter *iter);
/*
* Get the parent of the given iso tree node.
* This returns NULL if the node is the root of the tree, or is a node
* that doesn't pertain to any tree (it was removed/take)
*/
struct iso_tree_node_dir *iso_tree_node_get_parent(struct iso_tree_node *node);
/**
* Adds a child to a directory.
* The child will be freed when the parent is freed, so you must be the
* owner of the child (maybe calling iso_tree_node_ref) before calling this.
*
* \pre parent has no child with the same name as \p child
*/
void iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child);
/**
* Increments the reference counting of the given node.
* If you call this, you must remember call iso_tree_free when the
* node is no more needed.
*/
void iso_tree_node_ref(struct iso_tree_node *node);
/**
* Recursively free a directory.
*
* \param root The root of the directory heirarchy to free.
*
* \pre \p root is non-NULL.
*/
void iso_tree_free(struct iso_tree_node *root);
/**
* Recursively print a directory to stdout.
* \param spaces The initial number of spaces on the left. Set to 0 if you
@ -541,4 +915,22 @@ void iso_tree_print(const struct iso_tree_node *root, int spaces);
struct burn_source* iso_source_new_ecma119(struct iso_volset *volumeset,
struct ecma119_source_opts *opts);
/**
* Creates a new data source from the given file.
*
* Returns NULL on error
*/
struct data_source *data_source_from_file(const char *path);
/** Free a given data source (decrease its refcount and maybe free it) */
void data_source_free(struct data_source*);
/**
* Read an existing ISO image.
*
* TODO documentar
*/
struct iso_volset *iso_volset_read(struct data_source *src,
struct ecma119_read_opts *opts);
#endif /* LIBISO_LIBISOFS_H */

2
libisofs/rockridge.c

@ -14,7 +14,7 @@
#include <unistd.h>
#include <sys/stat.h>
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
/** See IEEE P1281 Draft Version 1.12/5.5 */
void
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{

246
libisofs/tree.c

@ -53,6 +53,7 @@ iso_tree_new_root()
root = calloc(1, sizeof(struct iso_tree_node_dir));
set_default_stat(&root->node.attrib);
root->node.refcount = 1;
root->node.attrib.st_mode = S_IFDIR | 0777;
root->node.type = LIBISO_NODE_DIR;
return root;
@ -85,8 +86,9 @@ iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
f = calloc(1, sizeof(struct iso_tree_node_file));
/* fill fields */
f->node.refcount = 1;
f->node.attrib = st;
f->path = strdup(path);
f->loc.path = strdup(path);
f->node.type = LIBISO_NODE_FILE;
p = strdup(path); /* because basename() might modify its arg */
@ -111,7 +113,8 @@ iso_tree_add_symlink(struct iso_tree_node_dir *parent,
/* fill fields */
set_default_stat(&link->node.attrib);
link->node.attrib.st_mode |= S_IFLNK;//TODO Not needed
link->node.refcount = 1;
link->node.attrib.st_mode |= S_IFLNK;
link->node.name = strdup(name);
link->node.type = LIBISO_NODE_SYMLINK;
link->dest = strdup(dest);
@ -132,6 +135,7 @@ iso_tree_add_dir(struct iso_tree_node_dir *parent,
dir = calloc(1, sizeof(struct iso_tree_node_dir));
dir->node.refcount = 1;
dir->node.attrib = parent->node.attrib;
dir->node.type = LIBISO_NODE_DIR;
dir->node.name = strdup(name);
@ -140,6 +144,13 @@ iso_tree_add_dir(struct iso_tree_node_dir *parent,
return dir;
}
enum iso_tree_node_type
iso_tree_node_get_type(struct iso_tree_node *node)
{
assert(node);
return node->type;
}
void
iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
{
@ -147,6 +158,13 @@ iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
node->name = strdup(name);
}
const char *
iso_tree_node_get_name(struct iso_tree_node *node)
{
assert(node);
return node->name;
}
void
iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
{
@ -154,6 +172,13 @@ iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
node->hide_flags = hide_attrs;
}
int
iso_tree_node_is_hidden(struct iso_tree_node *node)
{
assert(node);
return node->hide_flags;
}
void
iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
{
@ -161,6 +186,13 @@ iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
node->attrib.st_gid = gid;
}
gid_t
iso_tree_node_get_gid(struct iso_tree_node *node)
{
assert(node);
return node->attrib.st_gid;
}
void
iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
{
@ -168,6 +200,13 @@ iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
node->attrib.st_uid = uid;
}
uid_t
iso_tree_node_get_uid(struct iso_tree_node *node)
{
assert(node);
return node->attrib.st_uid;
}
void
iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
{
@ -176,6 +215,13 @@ iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
(mode & ~S_IFMT);
}
mode_t
iso_tree_node_get_permissions(struct iso_tree_node *node)
{
assert(node);
return node->attrib.st_mode & ~S_IFMT;
}
void
iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
{
@ -194,6 +240,22 @@ iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
}
}
void
iso_tree_node_symlink_set_dest(struct iso_tree_node_symlink *node,
const char *dest)
{
assert(node && dest);
free(node->dest);
node->dest = strdup(dest);
}
const char *
iso_tree_node_symlink_get_dest(struct iso_tree_node_symlink *node)
{
assert(node);
return node->dest;
}
struct iso_tree_node*
iso_tree_add_node(struct iso_tree_node_dir *parent,
const char *path)
@ -255,28 +317,172 @@ iso_tree_add_node(struct iso_tree_node_dir *parent,
return node;
}
struct iso_tree_iter *
iso_tree_node_children(struct iso_tree_node_dir *dir)
{
struct iso_tree_iter *iter;
assert(dir);
iter = malloc(sizeof(struct iso_tree_iter));
iter->dir = dir;
iter->index = -1;
return iter;
}
struct iso_tree_node *
iso_tree_iter_next(struct iso_tree_iter *iter)
{
assert(iter);
if ( ++iter->index < iter->dir->nchildren )
return iter->dir->children[iter->index];
else
return NULL;
}
void
iso_tree_iter_free(struct iso_tree_iter *iter)
{
free(iter);
}
int
iso_tree_node_take(struct iso_tree_node_dir *dir, struct iso_tree_node *node)
{
int i;
assert(dir && node);
/* search for the node in the dir */
for (i = 0; i < dir->nchildren; ++i) {
if ( dir->children[i] == node )
break;
}
if (i < dir->nchildren) {
int j;
for (j = i+1; j < dir->nchildren; ++j) {
dir->children[j-1] = dir->children[j];
}
--dir->nchildren;
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
node->parent = NULL;
return 0;
} else {
/* the node doesn't exist on dir */
return -1;
}
}
int
iso_tree_node_remove(struct iso_tree_node_dir *dir, struct iso_tree_node *node)
{
int res;
assert(dir && node);
res = iso_tree_node_take(dir, node);
if (!res)
iso_tree_free(node);
return res;
}
int
iso_tree_node_take_iter(struct iso_tree_iter *iter)
{
int j;
struct iso_tree_node_dir *dir;
struct iso_tree_node *node;
assert(iter);
dir = iter->dir;
if (iter->index < 0)
return -1; /* index before beginning */
if (iter->index >= dir->nchildren)
return -2; /* index after end */
node = dir->children[iter->index];
node->parent = NULL;
for (j = iter->index+1; j < dir->nchildren; ++j) {
dir->children[j-1] = dir->children[j];
}
--dir->nchildren;
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
/* update iter index */
--iter->index;
return 0;
}
int
iso_tree_node_remove_iter(struct iso_tree_iter *iter)
{
int j;
struct iso_tree_node_dir *dir;
struct iso_tree_node *node;
assert(iter);
dir = iter->dir;
if (iter->index < 0)
return -1; /* index before beginning */
if (iter->index >= dir->nchildren)
return -2; /* index after end */
node = dir->children[iter->index];
for (j = iter->index+1; j < dir->nchildren; ++j) {
dir->children[j-1] = dir->children[j];
}
--dir->nchildren;
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
/* update iter index */
--iter->index;
/* and free node */
node->parent = NULL;
iso_tree_free(node);
return 0;
}
struct iso_tree_node_dir *
iso_tree_node_get_parent(struct iso_tree_node *node)
{
assert(node);
return node->parent;
}
void
iso_tree_node_ref(struct iso_tree_node *node)
{
++node->refcount;
}
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]);
if (--root->refcount < 1) {
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;
if (root->procedence == LIBISO_NEW)
free(file->loc.path);
}
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);
}
free(root->name);
free(root);
}
static void
@ -352,8 +558,6 @@ iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
/* clear hashtable */
iso_exclude_empty(&table);
return dir;
}
void

82
libisofs/tree.h

@ -8,7 +8,7 @@
* (for multisession).
*
* This tree preserves as much information as it can about the files; names
* are stored in wchar_t and we preserve POSIX attributes. This tree does
* are stored in UTF-8 and we preserve POSIX attributes. This tree does
* *not* include information that is necessary for writing out, for example,
* an ISO level 1 tree. That information will go in a different tree because
* the structure is sufficiently different.
@ -20,42 +20,29 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <wchar.h>
#include "libisofs.h"
//enum file_location {
// LIBISO_FILESYS,
// LIBISO_PREVSESSION,
// LIBISO_NONE /**< for files/dirs that were added with
// * iso_tree_add_new_XXX. */
//};
/**
* This tells us where to read the data from a file. Either we read from the
* local filesystem or we just point to the block on a previous session.
*/
//struct iso_file_location
//{
// enum file_location type;
// /* union {*/
// char *path; /* in the current locale */
// uint32_t block;
// /* };*/