Implemented numeber of multisession options, reading, modifying tree, and a number of improvements
This commit is contained in:
parent
2e073c258c
commit
0b1a9c5565
14
ChangeLog
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
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
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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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,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)
|
||||
{
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
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;
|
||||