Implemented safety cap and did merge with vreixo branch

This commit is contained in:
Mario Danic 2008-04-22 22:24:00 +02:00
commit 7e617733b1
22 changed files with 3007 additions and 129 deletions

View File

@ -38,3 +38,4 @@ demo/isogrow
doc/html doc/html
doc/doxygen.conf doc/doxygen.conf
libisofs-1.pc libisofs-1.pc
demo/find

View File

@ -16,6 +16,7 @@ libisofs_libisofs_la_SOURCES = \
libisofs/node.c \ libisofs/node.c \
libisofs/tree.h \ libisofs/tree.h \
libisofs/tree.c \ libisofs/tree.c \
libisofs/find.c \
libisofs/image.h \ libisofs/image.h \
libisofs/image.c \ libisofs/image.c \
libisofs/fsource.h \ libisofs/fsource.h \
@ -54,6 +55,8 @@ libisofs_libisofs_la_SOURCES = \
libisofs/iso1999.h \ libisofs/iso1999.h \
libisofs/iso1999.c \ libisofs/iso1999.c \
libisofs/data_source.c libisofs/data_source.c
libisofs_libisofs_la_LIBADD= \
$(THREAD_LIBS)
libinclude_HEADERS = \ libinclude_HEADERS = \
libisofs/libisofs.h libisofs/libisofs.h
@ -65,6 +68,7 @@ noinst_PROGRAMS = \
demo/cat \ demo/cat \
demo/catbuffer \ demo/catbuffer \
demo/tree \ demo/tree \
demo/find \
demo/ecma119tree \ demo/ecma119tree \
demo/iso \ demo/iso \
demo/isoread \ demo/isoread \
@ -89,6 +93,10 @@ demo_tree_CPPFLAGS = -Ilibisofs
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_tree_SOURCES = demo/tree.c demo_tree_SOURCES = demo/tree.c
demo_find_CPPFLAGS = -Ilibisofs
demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_find_SOURCES = demo/find.c
demo_ecma119tree_CPPFLAGS = -Ilibisofs demo_ecma119tree_CPPFLAGS = -Ilibisofs
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_ecma119tree_SOURCES = demo/ecma119_tree.c demo_ecma119tree_SOURCES = demo/ecma119_tree.c

1
TODO
View File

@ -9,7 +9,6 @@ TODO
#00004 (libisofs.h) -> Add a get_mime_type() function. #00004 (libisofs.h) -> Add a get_mime_type() function.
#00005 (node.c) -> optimize iso_dir_iter_take. #00005 (node.c) -> optimize iso_dir_iter_take.
#00006 (libisofs.h) -> define more replace values when adding a node to a dir #00006 (libisofs.h) -> define more replace values when adding a node to a dir
#00007 (libisofs.h) -> expose iso_tree_add_new_file
#00008 (data_dource.c) -> guard against partial reads #00008 (data_dource.c) -> guard against partial reads
#00009 (ecma119_tree.c/h) -> add true support for harlinks and inode numbers #00009 (ecma119_tree.c/h) -> add true support for harlinks and inode numbers
#00010 (buffer.c) -> optimize ring buffer #00010 (buffer.c) -> optimize ring buffer

63
demo/find.c Normal file
View File

@ -0,0 +1,63 @@
/*
* Little program that import a directory, find matching nodes and prints the
* resulting iso tree.
*/
#include "libisofs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static void
print_dir(IsoDir *dir)
{
IsoDirIter *iter;
IsoNode *node;
IsoFindCondition *cond, *c1, *c2;
c1 = iso_new_find_conditions_name("*a*");
c2 = iso_new_find_conditions_mode(S_IFREG);
cond = iso_new_find_conditions_and(c1, c2);
iso_dir_find_children(dir, cond, &iter);
while (iso_dir_iter_next(iter, &node) == 1) {
char *path = iso_tree_get_node_path(node);
printf(" %s\n", path);
free(path);
}
iso_dir_iter_free(iter);
}
int main(int argc, char **argv)
{
int result;
IsoImage *image;
if (argc != 2) {
printf ("You need to specify a valid path\n");
return 1;
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
result = iso_image_new("volume_id", &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
print_dir(iso_image_get_root(image));
iso_image_unref(image);
iso_finish();
return 0;
}

View File

@ -53,11 +53,12 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
return ret; return ret;
} }
/* take a ref to the src, as stream has taken our ref */
iso_file_source_ref(src);
name = iso_file_source_get_name(src); name = iso_file_source_get_name(src);
ret = iso_node_new_file(name, stream, &node); ret = iso_node_new_file(name, stream, &node);
if (ret < 0) { if (ret < 0) {
/* the stream has taken our ref to src, so we need to add one */
iso_file_source_ref(src);
iso_stream_unref(stream); iso_stream_unref(stream);
free(name); free(name);
return ret; return ret;

View File

@ -34,8 +34,7 @@ struct Iso_Node_Builder
* In that case, if the implementation can't do the conversion, it * In that case, if the implementation can't do the conversion, it
* should fail propertly. * should fail propertly.
* *
* On sucess, the ref. to src will be owned by file, so you musn't * Note that the src is never unref, so you need to free it.
* unref it.
* *
* @return * @return
* 1 on success, < 0 on error * 1 on success, < 0 on error

View File

@ -57,7 +57,7 @@ int ds_open(IsoDataSource *src)
data = (struct file_data_src*) src->data; data = (struct file_data_src*) src->data;
if (data->fd != -1) { if (data->fd != -1) {
return ISO_FILE_ALREADY_OPENNED; return ISO_FILE_ALREADY_OPENED;
} }
fd = open(data->path, O_RDONLY); fd = open(data->path, O_RDONLY);
@ -81,7 +81,7 @@ int ds_close(IsoDataSource *src)
data = (struct file_data_src*) src->data; data = (struct file_data_src*) src->data;
if (data->fd == -1) { if (data->fd == -1) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
/* close can fail if fd is not valid, but that should never happen */ /* close can fail if fd is not valid, but that should never happen */
@ -102,7 +102,7 @@ static int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
data = (struct file_data_src*) src->data; data = (struct file_data_src*) src->data;
if (data->fd == -1) { if (data->fd == -1) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
/* goes to requested block */ /* goes to requested block */

View File

@ -538,7 +538,7 @@ int catalog_open(IsoStream *stream)
data = stream->data; data = stream->data;
if (data->offset != -1) { if (data->offset != -1) {
return ISO_FILE_ALREADY_OPENNED; return ISO_FILE_ALREADY_OPENED;
} }
memset(data->buffer, 0, BLOCK_SIZE); memset(data->buffer, 0, BLOCK_SIZE);
@ -563,7 +563,7 @@ int catalog_close(IsoStream *stream)
data = stream->data; data = stream->data;
if (data->offset == -1) { if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
data->offset = -1; data->offset = -1;
return ISO_SUCCESS; return ISO_SUCCESS;
@ -589,7 +589,7 @@ int catalog_read(IsoStream *stream, void *buf, size_t count)
data = stream->data; data = stream->data;
if (data->offset == -1) { if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
len = MIN(count, BLOCK_SIZE - data->offset); len = MIN(count, BLOCK_SIZE - data->offset);

View File

@ -33,6 +33,12 @@ int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag)
} }
original = file->stream; original = file->stream;
if (!iso_stream_is_repeatable(original)) {
/* TODO use custom error */
return ISO_WRONG_ARG_VALUE;
}
ret = filter->get_filter(filter, original, &filtered); ret = filter->get_filter(filter, original, &filtered);
if (ret < 0) { if (ret < 0) {
return ret; return ret;

761
libisofs/find.c Normal file
View File

@ -0,0 +1,761 @@
/*
* Copyright (c) 2008 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "node.h"
#include <fnmatch.h>
#include <string.h>
struct iso_find_condition
{
/*
* Check whether the given node matches this condition.
*
* @param cond
* The condition to check
* @param node
* The node that should be checked
* @return
* 1 if the node matches the condition, 0 if not
*/
int (*matches)(IsoFindCondition *cond, IsoNode *node);
/**
* Free condition specific data
*/
void (*free)(IsoFindCondition*);
/** condition specific data */
void *data;
};
struct find_iter_data
{
IsoDir *dir; /**< original dir of the iterator */
IsoDirIter *iter;
IsoDirIter *itersec; /**< iterator to deal with child dirs */
IsoFindCondition *cond;
int err; /**< error? */
IsoNode *current; /**< node to be returned next */
IsoNode *prev; /**< last returned node, needed for removal */
int free_cond; /**< whether to free cond on iter_free */
};
static
int get_next(struct find_iter_data *iter, IsoNode **n)
{
int ret;
if (iter->itersec != NULL) {
ret = iso_dir_iter_next(iter->itersec, n);
if (ret <= 0) {
/* secondary item no more needed */
iso_dir_iter_free(iter->itersec);
iter->itersec = NULL;
}
if (ret != 0) {
/* succes or error */
return ret;
}
}
/*
* we reach here if:
* - no secondary item is present
* - secondary item has no more items
*/
while ((ret = iso_dir_iter_next(iter->iter, n)) == 1) {
if (iter->cond->matches(iter->cond, *n)) {
return ISO_SUCCESS;
} else if (ISO_NODE_IS_DIR(*n)) {
/* recurse on child dir */
struct find_iter_data *data;
ret = iso_dir_find_children((IsoDir*)*n, iter->cond,
&iter->itersec);
if (ret < 0) {
return ret;
}
data = iter->itersec->data;
data->free_cond = 0; /* we don't need sec iter to free cond */
return get_next(iter, n);
}
}
return ret;
}
static
void update_next(IsoDirIter *iter)
{
int ret;
IsoNode *n;
struct find_iter_data *data = iter->data;
if (data->prev) {
iso_node_unref(data->prev);
}
data->prev = data->current;
if (data->itersec == NULL && data->current != NULL
&& ISO_NODE_IS_DIR(data->current)) {
/* we need to recurse on child dir */
struct find_iter_data *data2;
ret = iso_dir_find_children((IsoDir*)data->current, data->cond,
&data->itersec);
if (ret < 0) {
data->current = NULL;
data->err = ret;
return;
}
data2 = data->itersec->data;
data2->free_cond = 0; /* we don't need sec iter to free cond */
}
ret = get_next(data, &n);
iso_node_unref((IsoNode*)iter->dir);
if (ret == 1) {
data->current = n;
iso_node_ref(n);
data->err = 0;
iter->dir = n->parent;
} else {
data->current = NULL;
data->err = ret;
iter->dir = data->dir;
}
iso_node_ref((IsoNode*)iter->dir);
}
static
int find_iter_next(IsoDirIter *iter, IsoNode **node)
{
struct find_iter_data *data = iter->data;
if (iter == NULL || node == NULL) {
return ISO_NULL_POINTER;
}
if (data->err < 0) {
return data->err;
}
*node = data->current;
update_next(iter);
return (*node == NULL) ? 0 : ISO_SUCCESS;
}
static
int find_iter_has_next(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
return (data->current != NULL);
}
static
void find_iter_free(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
if (data->free_cond) {
data->cond->free(data->cond);
free(data->cond);
}
iso_node_unref((IsoNode*)data->dir);
/* free refs to nodes */
if (data->prev) {
iso_node_unref(data->prev);
}
if (data->current) {
iso_node_unref(data->current);
}
/* free underlying iter */
iso_dir_iter_free(data->iter);
free(iter->data);
}
static
int find_iter_take(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
if (data->prev == NULL) {
return ISO_ERROR; /* next not called or end of dir */
}
return iso_node_take(data->prev);
}
static
int find_iter_remove(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
if (data->prev == NULL) {
return ISO_ERROR; /* next not called or end of dir */
}
return iso_node_remove(data->prev);
}
void find_notify_child_taken(IsoDirIter *iter, IsoNode *node)
{
struct find_iter_data *data = iter->data;
if (data->prev == node) {
/* free our ref */
iso_node_unref(node);
data->prev = NULL;
} else if (data->current == node) {
iso_node_unref(node);
data->current = NULL;
update_next(iter);
}
}
static
struct iso_dir_iter_iface find_iter_class = {
find_iter_next,
find_iter_has_next,
find_iter_free,
find_iter_take,
find_iter_remove,
find_notify_child_taken
};
int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
IsoDirIter **iter)
{
int ret;
IsoDirIter *children;
IsoDirIter *it;
struct find_iter_data *data;
if (dir == NULL || cond == NULL || iter == NULL) {
return ISO_NULL_POINTER;
}
it = malloc(sizeof(IsoDirIter));
if (it == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct find_iter_data));
if (data == NULL) {
free(it);
return ISO_OUT_OF_MEM;
}
ret = iso_dir_get_children(dir, &children);
if (ret < 0) {
free(it);
free(data);
return ret;
}
it->class = &find_iter_class;
it->dir = (IsoDir*)dir;
data->iter = children;
data->itersec = NULL;
data->cond = cond;
data->free_cond = 1;
data->err = 0;
data->prev = data->current = NULL;
it->data = data;
if (iso_dir_iter_register(it) < 0) {
free(it);
return ISO_OUT_OF_MEM;
}
iso_node_ref((IsoNode*)dir);
/* take another ref to the original dir */
data->dir = (IsoDir*)dir;
iso_node_ref((IsoNode*)dir);
update_next(it);
*iter = it;
return ISO_SUCCESS;
}
/*************** find by name wildcard condition *****************/
static
int cond_name_matches(IsoFindCondition *cond, IsoNode *node)
{
char *pattern = (char*) cond->data;
int ret = fnmatch(pattern, node->name, 0);
return ret == 0 ? 1 : 0;
}
static
void cond_name_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks if the node name matches the given
* wildcard.
*
* @param wildcard
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_name(const char *wildcard)
{
IsoFindCondition *cond;
if (wildcard == NULL) {
return NULL;
}
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
cond->data = strdup(wildcard);
cond->free = cond_name_free;
cond->matches = cond_name_matches;
return cond;
}
/*************** find by mode condition *****************/
static
int cond_mode_matches(IsoFindCondition *cond, IsoNode *node)
{
mode_t *mask = (mode_t*) cond->data;
return node->mode & *mask ? 1 : 0;
}
static
void cond_mode_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the node mode against a mode mask. It
* can be used to check both file type and permissions.
*
* For example:
*
* iso_new_find_conditions_mode(S_IFREG) : search for regular files
* iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
* devices where owner has write permissions.
*
* @param mask
* Mode mask to AND against node mode.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_mode(mode_t mask)
{
IsoFindCondition *cond;
mode_t *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(mode_t));
if (data == NULL) {
free(cond);
return NULL;
}
*data = mask;
cond->data = data;
cond->free = cond_mode_free;
cond->matches = cond_mode_matches;
return cond;
}
/*************** find by gid condition *****************/
static
int cond_gid_matches(IsoFindCondition *cond, IsoNode *node)
{
gid_t *gid = (gid_t*) cond->data;
return node->gid == *gid ? 1 : 0;
}
static
void cond_gid_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the node gid.
*
* @param gid
* Desired Group Id.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_gid(gid_t gid)
{
IsoFindCondition *cond;
gid_t *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(gid_t));
if (data == NULL) {
free(cond);
return NULL;
}
*data = gid;
cond->data = data;
cond->free = cond_gid_free;
cond->matches = cond_gid_matches;
return cond;
}
/*************** find by uid condition *****************/
static
int cond_uid_matches(IsoFindCondition *cond, IsoNode *node)
{
uid_t *uid = (uid_t*) cond->data;
return node->uid == *uid ? 1 : 0;
}
static
void cond_uid_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the node uid.
*
* @param uid
* Desired User Id.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_uid(uid_t uid)
{
IsoFindCondition *cond;
uid_t *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(uid_t));
if (data == NULL) {
free(cond);
return NULL;
}
*data = uid;
cond->data = data;
cond->free = cond_uid_free;
cond->matches = cond_uid_matches;
return cond;
}
/*************** find by timestamps condition *****************/
struct cond_times
{
time_t time;
int what_time; /* 0 atime, 1 mtime, 2 ctime */
enum iso_find_comparisons comparison;
};
static
int cond_time_matches(IsoFindCondition *cond, IsoNode *node)
{
time_t node_time;
struct cond_times *data = cond->data;
switch (data->what_time) {
case 0: node_time = node->atime; break;
case 1: node_time = node->mtime; break;
default: node_time = node->ctime; break;
}
switch (data->comparison) {
case ISO_FIND_COND_GREATER:
return node_time > data->time ? 1 : 0;
case ISO_FIND_COND_GREATER_OR_EQUAL:
return node_time >= data->time ? 1 : 0;
case ISO_FIND_COND_EQUAL:
return node_time == data->time ? 1 : 0;
case ISO_FIND_COND_LESS:
return node_time < data->time ? 1 : 0;
case ISO_FIND_COND_LESS_OR_EQUAL:
return node_time <= data->time ? 1 : 0;
}
/* should never happen */
return 0;
}
static
void cond_time_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the time of last access.
*
* @param time
* Time to compare against IsoNode atime.
* @param comparison
* Comparison to be done between IsoNode atime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_atime(time_t time,
enum iso_find_comparisons comparison)
{
IsoFindCondition *cond;
struct cond_times *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct cond_times));
if (data == NULL) {
free(cond);
return NULL;
}
data->time = time;
data->comparison = comparison;
data->what_time = 0; /* atime */
cond->data = data;
cond->free = cond_time_free;
cond->matches = cond_time_matches;
return cond;
}
/**
* Create a new condition that checks the time of last modification.
*
* @param time
* Time to compare against IsoNode mtime.
* @param comparison
* Comparison to be done between IsoNode mtime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
enum iso_find_comparisons comparison)
{
IsoFindCondition *cond;
struct cond_times *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct cond_times));
if (data == NULL) {
free(cond);
return NULL;
}
data->time = time;
data->comparison = comparison;
data->what_time = 1; /* mtime */
cond->data = data;
cond->free = cond_time_free;
cond->matches = cond_time_matches;
return cond;
}
/**
* Create a new condition that checks the time of last status change.
*
* @param time
* Time to compare against IsoNode ctime.
* @param comparison
* Comparison to be done between IsoNode ctime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
enum iso_find_comparisons comparison)
{
IsoFindCondition *cond;
struct cond_times *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct cond_times));
if (data == NULL) {
free(cond);
return NULL;
}
data->time = time;
data->comparison = comparison;
data->what_time = 2; /* ctime */
cond->data = data;
cond->free = cond_time_free;
cond->matches = cond_time_matches;
return cond;
}
/*************** logical operations on conditions *****************/
struct logical_binary_conditions {
IsoFindCondition *a;
IsoFindCondition *b;
};
static
void cond_logical_binary_free(IsoFindCondition *cond)
{
struct logical_binary_conditions *data;
data = cond->data;
data->a->free(data->a);
free(data->a);
data->b->free(data->b);
free(data->b);
free(cond->data);
}
static
int cond_logical_and_matches(IsoFindCondition *cond, IsoNode *node)
{
struct logical_binary_conditions *data = cond->data;
return data->a->matches(data->a, node) && data->b->matches(data->b, node);
}
/**
* Create a new condition that check if the two given conditions are
* valid.
*
* @param a
* @param b
* IsoFindCondition to compare
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
IsoFindCondition *b)
{
IsoFindCondition *cond;
struct logical_binary_conditions *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct logical_binary_conditions));
if (data == NULL) {
free(cond);
return NULL;
}
data->a = a;
data->b = b;
cond->data = data;
cond->free = cond_logical_binary_free;
cond->matches = cond_logical_and_matches;
return cond;
}
static
int cond_logical_or_matches(IsoFindCondition *cond, IsoNode *node)
{
struct logical_binary_conditions *data = cond->data;
return data->a->matches(data->a, node) || data->b->matches(data->b, node);
}
/**
* Create a new condition that check if at least one the two given conditions
* is valid.
*
* @param a
* @param b
* IsoFindCondition to compare
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
IsoFindCondition *b)
{
IsoFindCondition *cond;
struct logical_binary_conditions *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct logical_binary_conditions));
if (data == NULL) {
free(cond);
return NULL;
}
data->a = a;
data->b = b;
cond->data = data;
cond->free = cond_logical_binary_free;
cond->matches = cond_logical_or_matches;
return cond;
}
static
void cond_not_free(IsoFindCondition *cond)
{
IsoFindCondition *negate = cond->data;
negate->free(negate);
free(negate);
}
static
int cond_not_matches(IsoFindCondition *cond, IsoNode *node)
{
IsoFindCondition *negate = cond->data;
return !(negate->matches(negate, node));
}
/**
* Create a new condition that check if the given conditions is false.
*
* @param negate
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate)
{
IsoFindCondition *cond;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
cond->data = negate;
cond->free = cond_not_free;
cond->matches = cond_not_matches;
return cond;
}

View File

@ -474,7 +474,7 @@ int ifs_open(IsoFileSource *src)
data = (ImageFileSourceData*)src->data; data = (ImageFileSourceData*)src->data;
if (data->opened) { if (data->opened) {
return ISO_FILE_ALREADY_OPENNED; return ISO_FILE_ALREADY_OPENED;
} }
if (S_ISDIR(data->info.st_mode)) { if (S_ISDIR(data->info.st_mode)) {
@ -530,7 +530,7 @@ int ifs_close(IsoFileSource *src)
data = (ImageFileSourceData*)src->data; data = (ImageFileSourceData*)src->data;
if (!data->opened) { if (!data->opened) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
if (data->opened == 2) { if (data->opened == 2) {
@ -569,7 +569,7 @@ int ifs_close(IsoFileSource *src)
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
* ISO_FILE_IS_DIR * ISO_FILE_IS_DIR
* ISO_OUT_OF_MEM * ISO_OUT_OF_MEM
* ISO_INTERRUPTED * ISO_INTERRUPTED
@ -590,7 +590,7 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
data = (ImageFileSourceData*)src->data; data = (ImageFileSourceData*)src->data;
if (!data->opened) { if (!data->opened) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} else if (data->opened != 1) { } else if (data->opened != 1) {
return ISO_FILE_IS_DIR; return ISO_FILE_IS_DIR;
} }
@ -632,6 +632,60 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
return read; return read;
} }
static
off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
{
ImageFileSourceData *data;
if (src == NULL) {
return (off_t)ISO_NULL_POINTER;
}
if (offset < (off_t)0) {
return (off_t)ISO_WRONG_ARG_VALUE;
}
data = src->data;
if (!data->opened) {
return (off_t)ISO_FILE_NOT_OPENED;
} else if (data->opened != 1) {
return (off_t)ISO_FILE_IS_DIR;
}
switch (flag) {
case 0: /* SEEK_SET */
data->data.offset = offset;
break;
case 1: /* SEEK_CUR */
data->data.offset += offset;
break;
case 2: /* SEEK_END */
/* do this make sense? */
data->data.offset = data->info.st_size + offset;
break;
default:
return (off_t)ISO_WRONG_ARG_VALUE;
}
if (data->data.offset % BLOCK_SIZE != 0) {
/* we need to buffer the block */
uint32_t block;
_ImageFsData *fsdata;
if (data->data.offset < data->info.st_size) {
int ret;
fsdata = data->fs->data;
block = data->block + (data->data.offset / BLOCK_SIZE);
ret = fsdata->src->read_block(fsdata->src, block,
data->data.content);
if (ret < 0) {
return (off_t)ret;
}
}
}
return data->data.offset;
}
static static
int ifs_readdir(IsoFileSource *src, IsoFileSource **child) int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
{ {
@ -644,7 +698,7 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
data = (ImageFileSourceData*)src->data; data = (ImageFileSourceData*)src->data;
if (!data->opened) { if (!data->opened) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} else if (data->opened != 2) { } else if (data->opened != 2) {
return ISO_FILE_IS_NOT_DIR; return ISO_FILE_IS_NOT_DIR;
} }
@ -774,7 +828,8 @@ IsoFileSourceIface ifs_class = {
ifs_readdir, ifs_readdir,
ifs_readlink, ifs_readlink,
ifs_get_filesystem, ifs_get_filesystem,
ifs_free ifs_free,
ifs_lseek
}; };
/** /**
@ -2081,7 +2136,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
free(name); free(name);
return ret; return ret;
} }
link = malloc(sizeof(IsoSymlink)); link = calloc(1, sizeof(IsoSymlink));
if (link == NULL) { if (link == NULL) {
free(name); free(name);
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
@ -2099,7 +2154,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
{ {
/* source is an special file */ /* source is an special file */
IsoSpecial *special; IsoSpecial *special;
special = malloc(sizeof(IsoSpecial)); special = calloc(1, sizeof(IsoSpecial));
if (special == NULL) { if (special == NULL) {
free(name); free(name);
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;

View File

@ -190,7 +190,7 @@ int lfs_open(IsoFileSource *src)
data = src->data; data = src->data;
if (data->openned) { if (data->openned) {
return ISO_FILE_ALREADY_OPENNED; return ISO_FILE_ALREADY_OPENED;
} }
/* is a file or a dir ? */ /* is a file or a dir ? */
@ -251,7 +251,7 @@ int lfs_close(IsoFileSource *src)
ret = closedir(data->info.dir) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR; ret = closedir(data->info.dir) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR;
break; break;
default: default:
ret = ISO_FILE_NOT_OPENNED; ret = ISO_FILE_NOT_OPENED;
break; break;
} }
if (ret == ISO_SUCCESS) { if (ret == ISO_SUCCESS) {
@ -300,7 +300,53 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count)
case 2: /* directory */ case 2: /* directory */
return ISO_FILE_IS_DIR; return ISO_FILE_IS_DIR;
default: default:
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
}
}
static
off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag)
{
_LocalFsFileSource *data;
int whence;
if (src == NULL) {
return (off_t)ISO_NULL_POINTER;
}
switch (flag) {
case 0:
whence = SEEK_SET; break;
case 1:
whence = SEEK_CUR; break;
case 2:
whence = SEEK_END; break;
default:
return (off_t)ISO_WRONG_ARG_VALUE;
}
data = src->data;
switch (data->openned) {
case 1: /* not dir */
{
off_t ret;
ret = lseek(data->info.fd, offset, whence);
if (ret < 0) {
/* error on read */
switch (errno) {
case ESPIPE:
ret = (off_t)ISO_FILE_ERROR;
break;
default:
ret = (off_t)ISO_ERROR;
break;
}
}
return ret;
}
case 2: /* directory */
return (off_t)ISO_FILE_IS_DIR;
default:
return (off_t)ISO_FILE_NOT_OPENED;
} }
} }
@ -341,7 +387,7 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
return ret; return ret;
} }
default: default:
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
} }
@ -433,7 +479,8 @@ IsoFileSourceIface lfs_class = {
lfs_readdir, lfs_readdir,
lfs_readlink, lfs_readlink,
lfs_get_filesystem, lfs_get_filesystem,
lfs_free lfs_free,
lfs_lseek
}; };
/** /**

View File

@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
return src->class->read(src, buf, count); return src->class->read(src, buf, count);
} }
inline
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag)
{
return src->class->lseek(src, offset, flag);
}
inline inline
int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child) int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child)
{ {

View File

@ -519,7 +519,7 @@ struct IsoFileSource_Iface
* Opens the source. * Opens the source.
* @return 1 on success, < 0 on error * @return 1 on success, < 0 on error
* Error codes: * Error codes:
* ISO_FILE_ALREADY_OPENNED * ISO_FILE_ALREADY_OPENED
* ISO_FILE_ACCESS_DENIED * ISO_FILE_ACCESS_DENIED
* ISO_FILE_BAD_PATH * ISO_FILE_BAD_PATH
* ISO_FILE_DOESNT_EXIST * ISO_FILE_DOESNT_EXIST
@ -535,7 +535,7 @@ struct IsoFileSource_Iface
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
*/ */
int (*close)(IsoFileSource *src); int (*close)(IsoFileSource *src);
@ -552,7 +552,7 @@ struct IsoFileSource_Iface
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
* ISO_WRONG_ARG_VALUE -> if count == 0 * ISO_WRONG_ARG_VALUE -> if count == 0
* ISO_FILE_IS_DIR * ISO_FILE_IS_DIR
* ISO_OUT_OF_MEM * ISO_OUT_OF_MEM
@ -578,7 +578,7 @@ struct IsoFileSource_Iface
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
* ISO_FILE_IS_NOT_DIR * ISO_FILE_IS_NOT_DIR
* ISO_OUT_OF_MEM * ISO_OUT_OF_MEM
*/ */
@ -623,6 +623,26 @@ struct IsoFileSource_Iface
*/ */
void (*free)(IsoFileSource *src); void (*free)(IsoFileSource *src);
/**
* Repositions the offset of the IsoFileSource (must be opened) to the
* given offset according to the value of flag.
*
* @param offset
* in bytes
* @param flag
* 0 The offset is set to offset bytes (SEEK_SET)
* 1 The offset is set to its current location plus offset bytes
* (SEEK_CUR)
* 2 The offset is set to the size of the file plus offset bytes
* (SEEK_END).
* @return
* Absolute offset posistion on the file, or < 0 on error. Cast the
* returning value to int to get a valid libisofs error.
*
* @since 0.6.4
*/
off_t (*lseek)(IsoFileSource *src, off_t offset, int flag);
/* /*
* TODO #00004 Add a get_mime_type() function. * TODO #00004 Add a get_mime_type() function.
* This can be useful for GUI apps, to choose the icon of the file * This can be useful for GUI apps, to choose the icon of the file
@ -1800,6 +1820,78 @@ void iso_node_unref(IsoNode *node);
*/ */
enum IsoNodeType iso_node_get_type(IsoNode *node); enum IsoNodeType iso_node_get_type(IsoNode *node);
/**
* Function to handle particular extended information. The function
* pointer acts as an identifier for the type of the information. Structs
* with same information type must use the same function.
*
* @param data
* Attached data
* @param flag
* What to do with the data. At this time the following values are
* defined:
* -> 1 the data must be freed
* @return
* 1 in any case.
*
* @since 0.6.4
*/
typedef int (*iso_node_xinfo_func)(void *data, int flag);
/**
* Add extended information to the given node. Extended info allows
* applications (and libisofs itself) to add more information to an IsoNode.
* You can use this facilities to associate new information with a given
* node.
*
* Each node keeps a list of added extended info, meaning you can add several
* extended info data to each node. Each extended info you add is identified
* by the proc parameter, a pointer to a function that knows how to manage
* the external info data. Thus, in order to add several types of extended
* info, you need to define a "proc" function for each type.
*
* @param node
* The node where to add the extended info
* @param proc
* A function pointer used to identify the type of the data, and that
* knows how to manage it
* @param data
* Extended info to add.
* @return
* 1 if success, 0 if the given node already has extended info of the
* type defined by the "proc" function, < 0 on error
*
* @since 0.6.4
*/
int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data);
/**
* Remove the given extended info (defined by the proc function) from the
* given node.
*
* @return
* 1 on success, 0 if node does not have extended info of the requested
* type, < 0 on error
*
* @since 0.6.4
*/
int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc);
/**
* Get the given extended info (defined by the proc function) from the
* given node.
*
* @param data
* Will be filled with the extended info corresponding to the given proc
* function
* @return
* 1 on success, 0 if node does not have extended info of the requested
* type, < 0 on error
*
* @since 0.6.4
*/
int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data);
/** /**
* Set the name of a node. Note that if the node is already added to a dir * Set the name of a node. Note that if the node is already added to a dir
* this can fail if dir already contains a node with the new name. * this can fail if dir already contains a node with the new name.
@ -2062,7 +2154,7 @@ IsoDir *iso_node_get_parent(IsoNode *node);
* you should free the iterator with iso_dir_iter_free. * you should free the iterator with iso_dir_iter_free.
* You musn't delete a child of the same dir, using iso_node_take() or * You musn't delete a child of the same dir, using iso_node_take() or
* iso_node_remove(), while you're using the iterator. You can use * iso_node_remove(), while you're using the iterator. You can use
* iso_node_take_iter() or iso_node_remove_iter() instead. * iso_dir_iter_take() or iso_dir_iter_remove() instead.
* *
* You can use the iterator in the way like this * You can use the iterator in the way like this
* *
@ -2131,8 +2223,8 @@ void iso_dir_iter_free(IsoDirIter *iter);
* It's like iso_node_take(), but to be used during a directory iteration. * It's like iso_node_take(), but to be used during a directory iteration.
* The node removed will be the last returned by the iteration. * The node removed will be the last returned by the iteration.
* *
* The behavior on two call to this function without calling iso_dir_iter_next * If you call this function twice without calling iso_dir_iter_next between
* between then is undefined, and should never occur. (TODO protect against this?) * them is not allowed and you will get an ISO_ERROR in second call.
* *
* @return * @return
* 1 on succes, < 0 error * 1 on succes, < 0 error
@ -2150,8 +2242,8 @@ int iso_dir_iter_take(IsoDirIter *iter);
* It's like iso_node_remove(), but to be used during a directory iteration. * It's like iso_node_remove(), but to be used during a directory iteration.
* The node removed will be the last returned by the 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 * If you call this function twice without calling iso_dir_iter_next between
* between then is undefined, and should never occur. (TODO protect against this?) * them is not allowed and you will get an ISO_ERROR in second call.
* *
* @return * @return
* 1 on succes, < 0 error * 1 on succes, < 0 error
@ -2164,6 +2256,191 @@ int iso_dir_iter_take(IsoDirIter *iter);
*/ */
int iso_dir_iter_remove(IsoDirIter *iter); int iso_dir_iter_remove(IsoDirIter *iter);
/**
* @since 0.6.4
*/
typedef struct iso_find_condition IsoFindCondition;
/**
* Create a new condition that checks if the node name matches the given
* wildcard.
*
* @param wildcard
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_name(const char *wildcard);
/**
* Create a new condition that checks the node mode against a mode mask. It
* can be used to check both file type and permissions.
*
* For example:
*
* iso_new_find_conditions_mode(S_IFREG) : search for regular files
* iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
* devices where owner has write permissions.
*
* @param mask
* Mode mask to AND against node mode.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_mode(mode_t mask);
/**
* Create a new condition that checks the node gid.
*
* @param gid
* Desired Group Id.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_gid(gid_t gid);
/**
* Create a new condition that checks the node uid.
*
* @param uid
* Desired User Id.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_uid(uid_t uid);
/**
* Possible comparison between IsoNode and given conditions.
*
* @since 0.6.4
*/
enum iso_find_comparisons {
ISO_FIND_COND_GREATER,
ISO_FIND_COND_GREATER_OR_EQUAL,
ISO_FIND_COND_EQUAL,
ISO_FIND_COND_LESS,
ISO_FIND_COND_LESS_OR_EQUAL
};
/**
* Create a new condition that checks the time of last access.
*
* @param time
* Time to compare against IsoNode atime.
* @param comparison
* Comparison to be done between IsoNode atime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_atime(time_t time,
enum iso_find_comparisons comparison);
/**
* Create a new condition that checks the time of last modification.
*
* @param time
* Time to compare against IsoNode mtime.
* @param comparison
* Comparison to be done between IsoNode mtime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
enum iso_find_comparisons comparison);
/**
* Create a new condition that checks the time of last status change.
*
* @param time
* Time to compare against IsoNode ctime.
* @param comparison
* Comparison to be done between IsoNode ctime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
enum iso_find_comparisons comparison);
/**
* Create a new condition that check if the two given conditions are
* valid.
*
* @param a
* @param b
* IsoFindCondition to compare
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
IsoFindCondition *b);
/**
* Create a new condition that check if at least one the two given conditions
* is valid.
*
* @param a
* @param b
* IsoFindCondition to compare
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
IsoFindCondition *b);
/**
* Create a new condition that check if the given conditions is false.
*
* @param negate
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate);
/**
* Find all directory children that match the given condition.
*
* @param dir
* Directory where we will search children.
* @param cond
* Condition that the children must match in order to be returned.
* It will be free together with the iterator. Remember to delete it
* if this function return error.
* @param iter
* Iterator that returns only the children that match condition.
* @return
* 1 on success, < 0 on error
*
* @since 0.6.4
*/
int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
IsoDirIter **iter);
/** /**
* Get the destination of a node. * Get the destination of a node.
* The returned string belongs to the node and should not be modified nor * The returned string belongs to the node and should not be modified nor
@ -2230,6 +2507,35 @@ off_t iso_file_get_size(IsoFile *file);
*/ */
IsoStream *iso_file_get_stream(IsoFile *file); IsoStream *iso_file_get_stream(IsoFile *file);
/**
* Get the block lba of a file node, if it was imported from an old image.
*
* @param file
* The file
* @param lba
* Will be filled with the kba
* @param flag
* Reserved for future usage, submit 0
* @return
* 1 if lba is valid (file comes from old image), 0 if file was newly
* added, i.e. it does not come from an old image, < 0 error
*
* @since 0.6.4
*/
int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag);
/*
* Like iso_file_get_old_image_lba(), but take an IsoNode.
*
* @return
* 1 if lba is valid (file comes from old image), 0 if file was newly
* added, i.e. it does not come from an old image, 2 node type has no
* LBA (no regular file), < 0 error
*
* @since 0.6.4
*/
int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag);
/** /**
* Add a new directory to the iso tree. Permissions, owner and hidden atts * Add a new directory to the iso tree. Permissions, owner and hidden atts
* are taken from parent, you can modify them later. * are taken from parent, you can modify them later.
@ -2255,10 +2561,36 @@ IsoStream *iso_file_get_stream(IsoFile *file);
*/ */
int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir);
/* /**
TODO #00007 expose Stream and this function: * Add a new regular file to the iso tree. Permissions are set to 0444,
int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file) * owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new file will be created
* @param name
* name for the new file. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param stream
* IsoStream for the contents of the file. The reference will be taken
* by the newly created file, you will need to take an extra ref to it
* if you need it.
* @param file
* place where to store a pointer to the newly created file. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/ */
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
IsoFile **file);
/** /**
* Add a new symlink to the directory tree. Permissions are set to 0777, * Add a new symlink to the directory tree. Permissions are set to 0777,
@ -2517,6 +2849,73 @@ void iso_tree_set_report_callback(IsoImage *image,
int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path, int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
IsoNode **node); IsoNode **node);
/**
* Add a new node to the image tree, from an existing file, and with the
* given name, that must not exist on dir.
*
* @param image
* The image
* @param parent
* The directory in the image tree where the node will be added.
* @param name
* The name that the node will have on image.
* @param path
* The path of the file to add in the filesystem.
* @param node
* place where to store a pointer to the newly added file. No
* extra ref is addded, so you will need to call iso_node_ref() if you
* really need it. You can pass NULL in this parameter if you don't need
* the pointer.
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if image, parent or path are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
const char *path, IsoNode **node);
/**
* Add a new node to the image tree, from an existing file, and with the
* given name, that must not exist on dir. The node will be cut-out to the
* submitted size, and its contents will be read from the given offset. This
* function is thus suitable for adding only a piece of a file to the image.
*
* @param image
* The image
* @param parent
* The directory in the image tree where the node will be added.
* @param name
* The name that the node will have on image.
* @param path
* The path of the file to add in the filesystem. For now only regular
* files and symlinks to regular files are supported.
* @param offset
* Offset on the given file from where to start reading data.
* @param size
* Max size of the file.
* @param node
* place where to store a pointer to the newly added file. No
* extra ref is addded, so you will need to call iso_node_ref() if you
* really need it. You can pass NULL in this parameter if you don't need
* the pointer.
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if image, parent or path are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
const char *name, const char *path,
off_t offset, off_t size,
IsoNode **node);
/** /**
* Add the contents of a dir to a given directory of the iso tree. * Add the contents of a dir to a given directory of the iso tree.
* *
@ -2556,6 +2955,16 @@ int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir);
*/ */
int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node); int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node);
/**
* Get the path on image of the given node.
*
* @return
* The path on the image, that must be freed when no more needed. If the
* given node is not added to any image, this returns NULL.
* @since 0.6.4
*/
char *iso_tree_get_node_path(IsoNode *node);
/** /**
* Increments the reference counting of the given IsoDataSource. * Increments the reference counting of the given IsoDataSource.
* *
@ -2893,7 +3302,7 @@ int iso_file_source_stat(IsoFileSource *src, struct stat *info);
* Opens the source. * Opens the source.
* @return 1 on success, < 0 on error * @return 1 on success, < 0 on error
* Error codes: * Error codes:
* ISO_FILE_ALREADY_OPENNED * ISO_FILE_ALREADY_OPENED
* ISO_FILE_ACCESS_DENIED * ISO_FILE_ACCESS_DENIED
* ISO_FILE_BAD_PATH * ISO_FILE_BAD_PATH
* ISO_FILE_DOESNT_EXIST * ISO_FILE_DOESNT_EXIST
@ -2911,7 +3320,7 @@ int iso_file_source_open(IsoFileSource *src);
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
* *
* @since 0.6.2 * @since 0.6.2
*/ */
@ -2937,7 +3346,7 @@ int iso_file_source_close(IsoFileSource *src);
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
* ISO_WRONG_ARG_VALUE -> if count == 0 * ISO_WRONG_ARG_VALUE -> if count == 0
* ISO_FILE_IS_DIR * ISO_FILE_IS_DIR
* ISO_OUT_OF_MEM * ISO_OUT_OF_MEM
@ -2947,6 +3356,25 @@ int iso_file_source_close(IsoFileSource *src);
*/ */
int iso_file_source_read(IsoFileSource *src, void *buf, size_t count); int iso_file_source_read(IsoFileSource *src, void *buf, size_t count);
/**
* Repositions the offset of the given IsoFileSource (must be opened) to the
* given offset according to the value of flag.
*
* @param offset
* in bytes
* @param flag
* 0 The offset is set to offset bytes (SEEK_SET)
* 1 The offset is set to its current location plus offset bytes
* (SEEK_CUR)
* 2 The offset is set to the size of the file plus offset bytes
* (SEEK_END).
* @return
* Absolute offset posistion on the file, or < 0 on error. Cast the
* returning value to int to get a valid libisofs error.
* @since 0.6.4
*/
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag);
/** /**
* Read a directory. * Read a directory.
* *
@ -2965,7 +3393,7 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count);
* Error codes: * Error codes:
* ISO_FILE_ERROR * ISO_FILE_ERROR
* ISO_NULL_POINTER * ISO_NULL_POINTER
* ISO_FILE_NOT_OPENNED * ISO_FILE_NOT_OPENED
* ISO_FILE_IS_NOT_DIR * ISO_FILE_IS_NOT_DIR
* ISO_OUT_OF_MEM * ISO_OUT_OF_MEM
* *
@ -3280,6 +3708,9 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
#define ISO_FILE_ERROR 0xE830FF80 #define ISO_FILE_ERROR 0xE830FF80
/** Trying to open an already openned file (FAILURE,HIGH, -129) */ /** Trying to open an already openned file (FAILURE,HIGH, -129) */
#define ISO_FILE_ALREADY_OPENED 0xE830FF7F
/* @deprecated use ISO_FILE_ALREADY_OPENED instead */
#define ISO_FILE_ALREADY_OPENNED 0xE830FF7F #define ISO_FILE_ALREADY_OPENNED 0xE830FF7F
/** Access to file is not allowed (FAILURE,HIGH, -130) */ /** Access to file is not allowed (FAILURE,HIGH, -130) */
@ -3292,7 +3723,10 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
#define ISO_FILE_DOESNT_EXIST 0xE830FF7C #define ISO_FILE_DOESNT_EXIST 0xE830FF7C
/** Trying to read or close a file not openned (FAILURE,HIGH, -133) */ /** Trying to read or close a file not openned (FAILURE,HIGH, -133) */
#define ISO_FILE_NOT_OPENNED 0xE830FF7B #define ISO_FILE_NOT_OPENED 0xE830FF7B
/* @deprecated use ISO_FILE_NOT_OPENED instead */
#define ISO_FILE_NOT_OPENNED ISO_FILE_NOT_OPENED
/** Directory used where no dir is expected (FAILURE,HIGH, -134) */ /** Directory used where no dir is expected (FAILURE,HIGH, -134) */
#define ISO_FILE_IS_DIR 0xE830FF7A #define ISO_FILE_IS_DIR 0xE830FF7A
@ -3326,10 +3760,16 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
/** /**
* File path break specification constraints and will be ignored * File path break specification constraints and will be ignored
* (HINT,MEDIUM, -141) * (HINT,MEDIUM, -144)
*/ */
#define ISO_FILE_IMGPATH_WRONG 0xC020FF70 #define ISO_FILE_IMGPATH_WRONG 0xC020FF70
/**
* Offset greater than file size (FAILURE,HIGH, -145)
* @since 0.6.4
*/
#define ISO_FILE_OFFSET_TOO_BIG 0xE830FF6A
/** Charset conversion error (FAILURE,HIGH, -256) */ /** Charset conversion error (FAILURE,HIGH, -256) */
#define ISO_CHARSET_CONV_ERROR 0xE830FF00 #define ISO_CHARSET_CONV_ERROR 0xE830FF00

View File

@ -136,16 +136,16 @@ const char *iso_error_to_msg(int errcode)
return "Trying to use an invalid file as boot image"; return "Trying to use an invalid file as boot image";
case ISO_FILE_ERROR: case ISO_FILE_ERROR:
return "Error on file operation"; return "Error on file operation";
case ISO_FILE_ALREADY_OPENNED: case ISO_FILE_ALREADY_OPENED:
return "Trying to open an already openned file"; return "Trying to open an already opened file";
case ISO_FILE_ACCESS_DENIED: case ISO_FILE_ACCESS_DENIED:
return "Access to file is not allowed"; return "Access to file is not allowed";
case ISO_FILE_BAD_PATH: case ISO_FILE_BAD_PATH:
return "Incorrect path to file"; return "Incorrect path to file";
case ISO_FILE_DOESNT_EXIST: case ISO_FILE_DOESNT_EXIST:
return "The file does not exist in the filesystem"; return "The file does not exist in the filesystem";
case ISO_FILE_NOT_OPENNED: case ISO_FILE_NOT_OPENED:
return "Trying to read or close a file not openned"; return "Trying to read or close a file not opened";
case ISO_FILE_IS_DIR: case ISO_FILE_IS_DIR:
return "Directory used where no dir is expected"; return "Directory used where no dir is expected";
case ISO_FILE_READ_ERROR: case ISO_FILE_READ_ERROR:

View File

@ -15,6 +15,17 @@
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
struct dir_iter_data
{
/* points to the last visited child, to NULL before start */
IsoNode *pos;
/* Some control flags.
* bit 0 -> 1 if next called, 0 reseted at start or on deletion
*/
int flag;
};
/** /**
* Increments the reference counting of the given node. * Increments the reference counting of the given node.
*/ */
@ -59,18 +70,143 @@ void iso_node_unref(IsoNode *node)
break; break;
} }
#ifdef LIBISO_EXTENDED_INFORMATION
if (node->xinfo) { if (node->xinfo) {
/* free extended info */ IsoExtendedInfo *info = node->xinfo;
node->xinfo->process(node->xinfo->data, 1); while (info != NULL) {
free(node->xinfo); IsoExtendedInfo *tmp = info->next;
/* free extended info */
info->process(info->data, 1);
free(info);
info = tmp;
}
} }
#endif
free(node->name); free(node->name);
free(node); free(node);
} }
} }
/**
* Add extended information to the given node. Extended info allows
* applications (and libisofs itself) to add more information to an IsoNode.
* You can use this facilities to associate new information with a given
* node.
*
* Each node keeps a list of added extended info, meaning you can add several
* extended info data to each node. Each extended info you add is identified
* by the proc parameter, a pointer to a function that knows how to manage
* the external info data. Thus, in order to add several types of extended
* info, you need to define a "proc" function for each type.
*
* @param node
* The node where to add the extended info
* @param proc
* A function pointer used to identify the type of the data, and that
* knows how to manage it
* @param data
* Extended info to add.
* @return
* 1 if success, 0 if the given node already has extended info of the
* type defined by the "proc" function, < 0 on error
*/
int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data)
{
IsoExtendedInfo *info;
IsoExtendedInfo *pos;
if (node == NULL || proc == NULL) {
return ISO_NULL_POINTER;
}
pos = node->xinfo;
while (pos != NULL) {
if (pos->process == proc) {
return 0; /* extended info already added */
}
pos = pos->next;
}
info = malloc(sizeof(IsoExtendedInfo));
if (info == NULL) {
return ISO_OUT_OF_MEM;
}
info->next = node->xinfo;
info->data = data;
info->process = proc;
node->xinfo = info;
return ISO_SUCCESS;
}
/**
* Remove the given extended info (defined by the proc function) from the
* given node.
*
* @return
* 1 on success, 0 if node does not have extended info of the requested
* type, < 0 on error
*/
int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc)
{
IsoExtendedInfo *pos, *prev;
if (node == NULL || proc == NULL) {
return ISO_NULL_POINTER;
}
prev = NULL;
pos = node->xinfo;
while (pos != NULL) {
if (pos->process == proc) {
/* this is the extended info we want to remove */
pos->process(pos->data, 1);
if (prev != NULL) {
prev->next = pos->next;
} else {
node->xinfo = pos->next;
}
free(pos);
return ISO_SUCCESS;
}
prev = pos;
pos = pos->next;
}
/* requested xinfo not found */
return 0;
}
/**
* Get the given extended info (defined by the proc function) from the
* given node.
*
* @param data
* Will be filled with the extended info corresponding to the given proc
* function
* @return
* 1 on success, 0 if node does not have extended info of the requested
* type, < 0 on error
*/
int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data)
{
IsoExtendedInfo *pos;
if (node == NULL || proc == NULL || data == NULL) {
return ISO_NULL_POINTER;
}
pos = node->xinfo;
while (pos != NULL) {
if (pos->process == proc) {
/* this is the extended info we want */
*data = pos->data;
return ISO_SUCCESS;
}
pos = pos->next;
}
/* requested xinfo not found */
return 0;
}
/** /**
* Get the type of an IsoNode. * Get the type of an IsoNode.
*/ */
@ -354,42 +490,53 @@ int iso_dir_get_children_count(IsoDir *dir)
return dir->nchildren; return dir->nchildren;
} }
int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) static
int iter_next(IsoDirIter *iter, IsoNode **node)
{ {
IsoDirIter *it; struct dir_iter_data *data;
if (dir == NULL || iter == NULL) {
return ISO_NULL_POINTER;
}
it = malloc(sizeof(IsoDirIter));
if (it == NULL) {
return ISO_OUT_OF_MEM;
}
it->dir = dir;
it->pos = dir->children;
*iter = it;
return ISO_SUCCESS;
}
int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
{
IsoNode *n;
if (iter == NULL || node == NULL) { if (iter == NULL || node == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
n = iter->pos;
if (n == NULL) { data = iter->data;
*node = NULL;
return 0; /* clear next flag */
data->flag &= ~0x01;
if (data->pos == NULL) {
/* we are at the beginning */
data->pos = iter->dir->children;
if (data->pos == NULL) {
/* empty dir */
*node = NULL;
return 0;
}
} else {
if (data->pos->parent != iter->dir) {
/* this can happen if the node has been moved to another dir */
/* TODO specific error */
return ISO_ERROR;
}
if (data->pos->next == NULL) {
/* no more children */
*node = NULL;
return 0;
} else {
/* free reference to current position */
iso_node_unref(data->pos); /* it is never last ref!! */
/* advance a position */
data->pos = data->pos->next;
}
} }
if (n->parent != iter->dir) {
/* this can happen if the node has been moved to another dir */ /* ok, take a ref to the current position, to prevent internal errors
return ISO_ERROR; * if deleted somewhere */
} iso_node_ref(data->pos);
*node = n; data->flag |= 0x01; /* set next flag */
iter->pos = n->next;
/* return pointed node */
*node = data->pos;
return ISO_SUCCESS; return ISO_SUCCESS;
} }
@ -401,17 +548,30 @@ int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
* Possible errors: * Possible errors:
* ISO_NULL_POINTER, if iter is NULL * ISO_NULL_POINTER, if iter is NULL
*/ */
int iso_dir_iter_has_next(IsoDirIter *iter) static
int iter_has_next(IsoDirIter *iter)
{ {
struct dir_iter_data *data;
if (iter == NULL) { if (iter == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
return iter->pos == NULL ? 0 : 1; data = iter->data;
if (data->pos == NULL) {
return iter->dir->children == NULL ? 0 : 1;
} else {
return data->pos->next == NULL ? 0 : 1;
}
} }
void iso_dir_iter_free(IsoDirIter *iter) static
void iter_free(IsoDirIter *iter)
{ {
free(iter); struct dir_iter_data *data;
data = iter->data;
if (data->pos != NULL) {
iso_node_unref(data->pos);
}
free(data);
} }
static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node) static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node)
@ -448,8 +608,12 @@ int iso_node_take(IsoNode *node)
pos = iso_dir_find_node(dir, node); pos = iso_dir_find_node(dir, node);
if (pos == NULL) { if (pos == NULL) {
/* should never occur */ /* should never occur */
return ISO_ERROR; return ISO_ASSERT_FAILURE;
} }
/* notify iterators just before remove */
iso_notify_dir_iters(node, 0);
*pos = node->next; *pos = node->next;
node->parent = NULL; node->parent = NULL;
node->next = NULL; node->next = NULL;
@ -492,43 +656,167 @@ IsoDir *iso_node_get_parent(IsoNode *node)
} }
/* TODO #00005 optimize iso_dir_iter_take */ /* TODO #00005 optimize iso_dir_iter_take */
int iso_dir_iter_take(IsoDirIter *iter) static
int iter_take(IsoDirIter *iter)
{ {
IsoNode *pos; struct dir_iter_data *data;
if (iter == NULL) { if (iter == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
pos = iter->dir->children; data = iter->data;
if (iter->pos == pos) {
return ISO_ERROR; if (!(data->flag & 0x01)) {
return ISO_ERROR; /* next not called or end of dir */
} }
while (pos != NULL && pos->next == iter->pos) {
pos = pos->next; if (data->pos == NULL) {
return ISO_ASSERT_FAILURE;
} }
if (pos == NULL) {
return ISO_ERROR; /* clear next flag */
data->flag &= ~0x01;
return iso_node_take(data->pos);
}
static
int iter_remove(IsoDirIter *iter)
{
int ret;
IsoNode *pos;
struct dir_iter_data *data;
if (iter == NULL) {
return ISO_NULL_POINTER;
} }
return iso_node_take(pos); data = iter->data;
pos = data->pos;
ret = iter_take(iter);
if (ret == ISO_SUCCESS) {
/* remove node */
iso_node_unref(pos);
}
return ret;
}
void iter_notify_child_taken(IsoDirIter *iter, IsoNode *node)
{
IsoNode *pos, *pre;
struct dir_iter_data *data;
data = iter->data;
if (data->pos == node) {
pos = iter->dir->children;
pre = NULL;
while (pos != NULL && pos != data->pos) {
pre = pos;
pos = pos->next;
}
if (pos == NULL || pos != data->pos) {
return;
}
/* dispose iterator reference */
iso_node_unref(data->pos);
if (pre == NULL) {
/* node is a first position */
iter->dir->children = pos->next;
data->pos = NULL;
} else {
pre->next = pos->next;
data->pos = pre;
iso_node_ref(pre); /* take iter ref */
}
}
}
static
struct iso_dir_iter_iface iter_class = {
iter_next,
iter_has_next,
iter_free,
iter_take,
iter_remove,
iter_notify_child_taken
};
int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter)
{
IsoDirIter *it;
struct dir_iter_data *data;
if (dir == NULL || iter == NULL) {
return ISO_NULL_POINTER;
}
it = malloc(sizeof(IsoDirIter));
if (it == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct dir_iter_data));
if (data == NULL) {
free(it);
return ISO_OUT_OF_MEM;
}
it->class = &iter_class;
it->dir = (IsoDir*)dir;
data->pos = NULL;
data->flag = 0x00;
it->data = data;
if (iso_dir_iter_register(it) < 0) {
free(it);
return ISO_OUT_OF_MEM;
}
iso_node_ref((IsoNode*)dir); /* tak a ref to the dir */
*iter = it;
return ISO_SUCCESS;
}
int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
{
if (iter == NULL || node == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->next(iter, node);
}
int iso_dir_iter_has_next(IsoDirIter *iter)
{
if (iter == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->has_next(iter);
}
void iso_dir_iter_free(IsoDirIter *iter)
{
if (iter != NULL) {
iso_dir_iter_unregister(iter);
iter->class->free(iter);
iso_node_unref((IsoNode*)iter->dir);
free(iter);
}
}
int iso_dir_iter_take(IsoDirIter *iter)
{
if (iter == NULL) {
return ISO_NULL_POINTER;
}
return iter->class->take(iter);
} }
int iso_dir_iter_remove(IsoDirIter *iter) int iso_dir_iter_remove(IsoDirIter *iter)
{ {
IsoNode *pos;
if (iter == NULL) { if (iter == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
pos = iter->dir->children; return iter->class->remove(iter);
if (iter->pos == pos) {
return ISO_ERROR;
}
while (pos != NULL && pos->next == iter->pos) {
pos = pos->next;
}
if (pos == NULL) {
return ISO_ERROR;
}
return iso_node_remove(pos);
} }
/** /**
@ -618,6 +906,58 @@ IsoStream *iso_file_get_stream(IsoFile *file)
return file->stream; return file->stream;
} }
/**
* Get the block lba of a file node, if it was imported from an old image.
*
* @param file
* The file
* @param lba
* Will be filled with the kba
* @param flag
* Reserved for future usage, submit 0
* @return
* 1 if lba is valid (file comes from old image), 0 if file was newly
* added, i.e. it does not come from an old image, < 0 error
*
* @since 0.6.4
*/
int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag)
{
if (file == NULL || lba == NULL) {
return ISO_NULL_POINTER;
}
if (flag != 0) {
return ISO_WRONG_ARG_VALUE;
}
if (file->msblock != 0) {
*lba = file->msblock;
return 1;
}
return 0;
}
/*
* Like iso_file_get_old_image_lba(), but take an IsoNode.
*
* @return
* 1 if lba is valid (file comes from old image), 0 if file was newly
* added, i.e. it does not come from an old image, 2 node type has no
* LBA (no regular file), < 0 error
*
* @since 0.6.4
*/
int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag)
{
if (node == NULL) {
return ISO_NULL_POINTER;
}
if (ISO_NODE_IS_FILE(node)) {
return iso_file_get_old_image_lba((IsoFile*)node, lba, flag);
} else {
return 2;
}
}
/** /**
* Check if a given name is valid for an iso node. * Check if a given name is valid for an iso node.
* *
@ -765,6 +1105,63 @@ int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
return ++dir->nchildren; return ++dir->nchildren;
} }
/* iterators are stored in a linked list */
struct iter_reg_node {
IsoDirIter *iter;
struct iter_reg_node *next;
};
/* list header */
static
struct iter_reg_node *iter_reg = NULL;
/**
* Add a new iterator to the registry. The iterator register keeps track of
* all iterators being used, and are notified when directory structure
* changes.
*/
int iso_dir_iter_register(IsoDirIter *iter)
{
struct iter_reg_node *new;
new = malloc(sizeof(struct iter_reg_node));
if (new == NULL) {
return ISO_OUT_OF_MEM;
}
new->iter = iter;
new->next = iter_reg;
iter_reg = new;
return ISO_SUCCESS;
}
/**
* Unregister a directory iterator.
*/
void iso_dir_iter_unregister(IsoDirIter *iter)
{
struct iter_reg_node **pos;
pos = &iter_reg;
while (*pos != NULL && (*pos)->iter != iter) {
pos = &(*pos)->next;
}
if (*pos) {
struct iter_reg_node *tmp = (*pos)->next;
free(*pos);
*pos = tmp;
}
}
void iso_notify_dir_iters(IsoNode *node, int flag)
{
struct iter_reg_node *pos = iter_reg;
while (pos != NULL) {
IsoDirIter *iter = pos->iter;
if (iter->dir == node->parent) {
iter->class->notify_child_taken(iter, node);
}
pos = pos->next;
}
}
int iso_node_new_root(IsoDir **root) int iso_node_new_root(IsoDir **root)
{ {
IsoDir *dir; IsoDir *dir;

View File

@ -20,9 +20,6 @@
#include <unistd.h> #include <unistd.h>
#include <stdint.h> #include <stdint.h>
/* #define LIBISO_EXTENDED_INFORMATION */
#ifdef LIBISO_EXTENDED_INFORMATION
/** /**
* The extended information is a way to attach additional information to each * The extended information is a way to attach additional information to each
* IsoNode. External applications may want to use this extension system to * IsoNode. External applications may want to use this extension system to
@ -55,7 +52,7 @@ struct iso_extended_info {
* @return * @return
* 1 * 1
*/ */
int (*process)(void *data, int flag); iso_node_xinfo_func process;
/** /**
* Pointer to information specific data. * Pointer to information specific data.
@ -63,8 +60,6 @@ struct iso_extended_info {
void *data; void *data;
}; };
#endif
/** /**
* *
*/ */
@ -102,12 +97,10 @@ struct Iso_Node
*/ */
IsoNode *next; IsoNode *next;
#ifdef LIBISO_EXTENDED_INFORMATION
/** /**
* Extended information for the node. * Extended information for the node.
*/ */
IsoExtendedInfo *xinfo; IsoExtendedInfo *xinfo;
#endif
}; };
struct Iso_Dir struct Iso_Dir
@ -148,13 +141,37 @@ struct Iso_Special
dev_t dev; dev_t dev;
}; };
struct iso_dir_iter_iface
{
int (*next)(IsoDirIter *iter, IsoNode **node);
int (*has_next)(IsoDirIter *iter);
void (*free)(IsoDirIter *iter);
int (*take)(IsoDirIter *iter);
int (*remove)(IsoDirIter *iter);
/**
* This is called just before remove a node from a directory. The iterator
* may want to update its internal state according to this.
*/
void (*notify_child_taken)(IsoDirIter *iter, IsoNode *node);
};
/** /**
* An iterator for directory children. * An iterator for directory children.
*/ */
struct Iso_Dir_Iter struct Iso_Dir_Iter
{ {
const IsoDir *dir; struct iso_dir_iter_iface *class;
IsoNode *pos;
/* the directory this iterator iterates over */
IsoDir *dir;
void *data;
}; };
int iso_node_new_root(IsoDir **root); int iso_node_new_root(IsoDir **root);
@ -303,4 +320,18 @@ int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos);
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
enum iso_replace_mode replace); enum iso_replace_mode replace);
/**
* Add a new iterator to the registry. The iterator register keeps track of
* all iterators being used, and are notified when directory structure
* changes.
*/
int iso_dir_iter_register(IsoDirIter *iter);
/**
* Unregister a directory iterator.
*/
void iso_dir_iter_unregister(IsoDirIter *iter);
void iso_notify_dir_iters(IsoNode *node, int flag);
#endif /*LIBISO_NODE_H_*/ #endif /*LIBISO_NODE_H_*/

View File

@ -17,6 +17,7 @@
ino_t serial_id = (ino_t)1; ino_t serial_id = (ino_t)1;
ino_t mem_serial_id = (ino_t)1; ino_t mem_serial_id = (ino_t)1;
ino_t cut_out_serial_id = (ino_t)1;
typedef struct typedef struct
{ {
@ -175,7 +176,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
} }
data = malloc(sizeof(FSrcStreamData)); data = malloc(sizeof(FSrcStreamData));
if (str == NULL) { if (data == NULL) {
free(str); free(str);
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
} }
@ -212,6 +213,193 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
return ISO_SUCCESS; return ISO_SUCCESS;
} }
struct cut_out_stream
{
IsoFileSource *src;
/* key for file identification inside filesystem */
dev_t dev_id;
ino_t ino_id;
off_t offset; /**< offset where read begins */
off_t size; /**< size of this file */
off_t pos; /* position on the file for read */
};
static
int cut_out_open(IsoStream *stream)
{
int ret;
struct stat info;
IsoFileSource *src;
struct cut_out_stream *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
src = data->src;
ret = iso_file_source_stat(data->src, &info);
if (ret < 0) {
return ret;
}
ret = iso_file_source_open(src);
if (ret < 0) {
return ret;
}
{
off_t ret;
if (data->offset > info.st_size) {
/* file is smaller than expected */
ret = iso_file_source_lseek(src, info.st_size, 0);
} else {
ret = iso_file_source_lseek(src, data->offset, 0);
}
if (ret < 0) {
return (int) ret;
}
}
data->pos = 0;
if (data->offset + data->size > info.st_size) {
return 3; /* file smaller than expected */
} else {
return ISO_SUCCESS;
}
}
static
int cut_out_close(IsoStream *stream)
{
IsoFileSource *src;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
src = ((struct cut_out_stream*)stream->data)->src;
return iso_file_source_close(src);
}
static
off_t cut_out_get_size(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
return data->size;
}
static
int cut_out_read(IsoStream *stream, void *buf, size_t count)
{
struct cut_out_stream *data = stream->data;
count = (size_t)MIN(data->size - data->pos, count);
if (count == 0) {
return 0;
}
return iso_file_source_read(data->src, buf, count);
}
static
int cut_out_is_repeatable(IsoStream *stream)
{
/* reg files are always repeatable */
return 1;
}
static
void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id)
{
FSrcStreamData *data;
IsoFilesystem *fs;
data = (FSrcStreamData*)stream->data;
fs = iso_file_source_get_filesystem(data->src);
*fs_id = fs->get_id(fs);
*dev_id = data->dev_id;
*ino_id = data->ino_id;
}
static
void cut_out_free(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
iso_file_source_unref(data->src);
free(data);
}
IsoStreamIface cut_out_stream_class = {
0,
"cout",
cut_out_open,
cut_out_close,
cut_out_get_size,
cut_out_read,
cut_out_is_repeatable,
cut_out_get_id,
cut_out_free
};
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream)
{
int r;
struct stat info;
IsoStream *str;
struct cut_out_stream *data;
if (src == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (size == 0) {
return ISO_WRONG_ARG_VALUE;
}
r = iso_file_source_stat(src, &info);
if (r < 0) {
return r;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset > info.st_size) {
return ISO_FILE_OFFSET_TOO_BIG;
}
/* check for read access to contents */
r = iso_file_source_access(src);
if (r < 0) {
return r;
}
str = malloc(sizeof(IsoStream));
if (str == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct cut_out_stream));
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* take a new ref to IsoFileSource */
data->src = src;
iso_file_source_ref(src);
data->offset = offset;
data->size = MIN(info.st_size - offset, size);
/* get the id numbers */
data->dev_id = (dev_t) 0;
data->ino_id = cut_out_serial_id++;
str->refcount = 1;
str->data = data;
str->class = &cut_out_stream_class;
*stream = str;
return ISO_SUCCESS;
}
typedef struct typedef struct
@ -231,7 +419,7 @@ int mem_open(IsoStream *stream)
} }
data = (MemStreamData*)stream->data; data = (MemStreamData*)stream->data;
if (data->offset != -1) { if (data->offset != -1) {
return ISO_FILE_ALREADY_OPENNED; return ISO_FILE_ALREADY_OPENED;
} }
data->offset = 0; data->offset = 0;
return ISO_SUCCESS; return ISO_SUCCESS;
@ -246,7 +434,7 @@ int mem_close(IsoStream *stream)
} }
data = (MemStreamData*)stream->data; data = (MemStreamData*)stream->data;
if (data->offset == -1) { if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
data->offset = -1; data->offset = -1;
return ISO_SUCCESS; return ISO_SUCCESS;
@ -275,7 +463,7 @@ int mem_read(IsoStream *stream, void *buf, size_t count)
data = stream->data; data = stream->data;
if (data->offset == -1) { if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED; return ISO_FILE_NOT_OPENED;
} }
if (data->offset >= data->size) { if (data->offset >= data->size) {
@ -400,7 +588,12 @@ off_t iso_stream_get_size(IsoStream *stream)
inline inline
int iso_stream_read(IsoStream *stream, void *buf, size_t count) int iso_stream_read(IsoStream *stream, void *buf, size_t count)
{ {
return stream->class->read(stream, buf, count); int ret;
ret= stream->class->read(stream, buf, count);
if(ret<0)
return ISO_FILE_READ_ERROR;
return ret;
} }
inline inline

View File

@ -33,6 +33,16 @@ void iso_stream_get_file_name(IsoStream *stream, char *name);
*/ */
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream); int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream);
/**
* Create a new stream to read a chunk of an IsoFileSource..
* The stream will add a ref. to the IsoFileSource.
*
* @return
* 1 sucess, < 0 error
*/
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream);
/** /**
* Create a stream for reading from a arbitrary memory buffer. * Create a stream for reading from a arbitrary memory buffer.
* When the Stream refcount reach 0, the buffer is free(3). * When the Stream refcount reach 0, the buffer is free(3).

View File

@ -256,6 +256,81 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
} }
/**
* Add a new regular file to the iso tree. Permissions are set to 0444,
* owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new file will be created
* @param name
* name for the new file. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param stream
* IsoStream for the contents of the file
* @param file
* place where to store a pointer to the newly created file. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
IsoFile **file)
{
int ret;
char *n;
IsoFile *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (file) {
*file = NULL;
}
/* find place where to insert */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
ret = iso_node_new_file(n, stream, &node);
if (ret < 0) {
free(n);
return ret;
}
/* permissions from parent */
iso_node_set_permissions((IsoNode*)node, 0444);
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (file) {
*file = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/** /**
* Set whether to follow or not symbolic links when added a file from a source * Set whether to follow or not symbolic links when added a file from a source
* to IsoImage. * to IsoImage.
@ -475,6 +550,139 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
return result; return result;
} }
int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
const char *path, IsoNode **node)
{
int result;
IsoFilesystem *fs;
IsoFileSource *file;
IsoNode *new;
IsoNode **pos;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &file);
if (result < 0) {
return result;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
iso_file_source_unref(file);
return ISO_NODE_NAME_NOT_UNIQUE;
}
result = image->builder->create_node(image->builder, image, file, &new);
/* free the file */
iso_file_source_unref(file);
if (result < 0) {
return result;
}
result = iso_node_set_name(new, name);
if (result < 0) {
iso_node_unref(new);
return result;
}
if (node) {
*node = new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
}
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
const char *name, const char *path,
off_t offset, off_t size,
IsoNode **node)
{
int result;
struct stat info;
IsoFilesystem *fs;
IsoFileSource *src;
IsoFile *new;
IsoNode **pos;
IsoStream *stream;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &src);
if (result < 0) {
return result;
}
result = iso_file_source_stat(src, &info);
if (result < 0) {
iso_file_source_unref(src);
return result;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset >= info.st_size) {
return ISO_WRONG_ARG_VALUE;
}
/* force regular file */
result = image->builder->create_file(image->builder, image, src, &new);
/* free the file */
iso_file_source_unref(src);
if (result < 0) {
return result;
}
/* replace file iso stream with a cut-out-stream */
result = iso_cut_out_stream_new(src, offset, size, &stream);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
iso_stream_unref(new->stream);
new->stream = stream;
result = iso_node_set_name((IsoNode*)new, name);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
if (node) {
*node = (IsoNode*)new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
}
static static
int check_excludes(IsoImage *image, const char *path) int check_excludes(IsoImage *image, const char *path)
{ {
@ -749,3 +957,27 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
} }
return result; return result;
} }
char *iso_tree_get_node_path(IsoNode *node)
{
if (node == NULL || node->parent == NULL) {
return NULL;
}
if ((IsoNode*)node->parent == node) {
return strdup("/");
} else {
char path[PATH_MAX];
char *parent_path = iso_tree_get_node_path((IsoNode*)node->parent);
if (parent_path == NULL) {
return NULL;
}
if (strlen(parent_path) == 1) {
snprintf(path, PATH_MAX, "/%s", node->name);
} else {
snprintf(path, PATH_MAX, "%s/%s", parent_path, node->name);
}
free(parent_path);
return strdup(path);
}
}

View File

@ -410,6 +410,7 @@ void test_iso_dir_get_node()
free(dir); free(dir);
} }
static
void test_iso_dir_get_children() void test_iso_dir_get_children()
{ {
int result; int result;
@ -419,11 +420,13 @@ void test_iso_dir_get_children()
/* init dir with default values, not all field need to be initialized */ /* init dir with default values, not all field need to be initialized */
dir = malloc(sizeof(IsoDir)); dir = malloc(sizeof(IsoDir));
dir->node.refcount = 1;
dir->children = NULL; dir->children = NULL;
dir->nchildren = 0; dir->nchildren = 0;
result = iso_dir_get_children(dir, &iter); result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1); CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->node.refcount, 2);
/* item should have no items */ /* item should have no items */
result = iso_dir_iter_has_next(iter); result = iso_dir_iter_has_next(iter);
@ -436,6 +439,7 @@ void test_iso_dir_get_children()
/* 1st node to be added */ /* 1st node to be added */
node1 = calloc(1, sizeof(IsoNode)); node1 = calloc(1, sizeof(IsoNode));
node1->name = "Node1"; node1->name = "Node1";
node1->refcount = 1;
result = iso_dir_add_node(dir, node1, 0); result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1); CU_ASSERT_EQUAL(dir->nchildren, 1);
@ -461,6 +465,7 @@ void test_iso_dir_get_children()
/* add another node */ /* add another node */
node2 = calloc(1, sizeof(IsoNode)); node2 = calloc(1, sizeof(IsoNode));
node2->name = "A node to be added first"; node2->name = "A node to be added first";
node2->refcount = 1;
result = iso_dir_add_node(dir, node2, 0); result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2); CU_ASSERT_EQUAL(result, 2);
@ -490,6 +495,7 @@ void test_iso_dir_get_children()
/* addition of a 3rd node, to be inserted last */ /* addition of a 3rd node, to be inserted last */
node3 = calloc(1, sizeof(IsoNode)); node3 = calloc(1, sizeof(IsoNode));
node3->name = "This node will be inserted last"; node3->name = "This node will be inserted last";
node3->refcount = 1;
result = iso_dir_add_node(dir, node3, 0); result = iso_dir_add_node(dir, node3, 0);
CU_ASSERT_EQUAL(result, 3); CU_ASSERT_EQUAL(result, 3);
@ -520,13 +526,446 @@ void test_iso_dir_get_children()
CU_ASSERT_EQUAL(result, 0); CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_PTR_NULL(node); CU_ASSERT_PTR_NULL(node);
iso_dir_iter_free(iter); iso_dir_iter_free(iter);
CU_ASSERT_EQUAL(dir->node.refcount, 1);
/* assert correct refcount */
CU_ASSERT_EQUAL(node1->refcount, 1);
free(node1); free(node1);
CU_ASSERT_EQUAL(node2->refcount, 1);
free(node2); free(node2);
CU_ASSERT_EQUAL(node3->refcount, 1);
free(node3); free(node3);
free(dir); free(dir);
} }
static
void test_iso_dir_iter_take()
{
int result;
IsoDirIter *iter;
IsoDir *dir;
IsoNode *node, *node1, *node2, *node3;
/* init dir with default values, not all field need to be initialized */
dir = malloc(sizeof(IsoDir));
dir->node.refcount = 1;
dir->children = NULL;
dir->nchildren = 0;
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->node.refcount, 2);
/* remove on empty dir! */
result = iso_dir_iter_take(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
iso_dir_iter_free(iter);
/* 1st node to be added */
node1 = calloc(1, sizeof(IsoNode));
node1->name = "Node1";
node1->refcount = 1;
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1);
/* test iteration again */
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* remove before iso_dir_iter_next() */
result = iso_dir_iter_take(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
result = iso_dir_iter_next(iter, &node);
/* this should remove the child */
result = iso_dir_iter_take(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 0);
CU_ASSERT_PTR_NULL(dir->children);
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
iso_dir_iter_free(iter);
/* add two node */
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1);
node2 = calloc(1, sizeof(IsoNode));
node2->name = "A node to be added first";
node2->refcount = 1;
result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* remove before iso_dir_iter_next() */
result = iso_dir_iter_take(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
/* iter should have two items... */
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
/* remove node 2 */
result = iso_dir_iter_take(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 1);
CU_ASSERT_PTR_EQUAL(dir->children, node1);
/* we can't take two times without next()!! */
result = iso_dir_iter_take(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
/* next should still work */
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node1);
/* ...and no more */
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_PTR_NULL(node);
iso_dir_iter_free(iter);
/* now remove only last child */
result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node1);
/* take last child */
result = iso_dir_iter_take(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 1);
CU_ASSERT_PTR_EQUAL(dir->children, node2);
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_PTR_NULL(node);
iso_dir_iter_free(iter);
/* Ok, now another situation. Modification of dir during iteration */
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
/* returned dir is node2, it should be the node taken next, but
* let's insert a node after node2 and before node1 */
node3 = calloc(1, sizeof(IsoNode));
node3->name = "A node to be added second";
node3->refcount = 1;
result = iso_dir_add_node(dir, node3, 0);
CU_ASSERT_EQUAL(dir->nchildren, 3);
/* is the node 2 the removed one? */
result = iso_dir_iter_take(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 2);
CU_ASSERT_PTR_EQUAL(dir->children, node3);
CU_ASSERT_PTR_EQUAL(node3->next, node1);
iso_dir_iter_free(iter);
CU_ASSERT_EQUAL(dir->node.refcount, 1);
/* assert correct refcount */
CU_ASSERT_EQUAL(node1->refcount, 1);
free(node1);
CU_ASSERT_EQUAL(node2->refcount, 1);
free(node2);
CU_ASSERT_EQUAL(node3->refcount, 1);
free(node3);
free(dir);
}
static
void test_iso_dir_iter_remove()
{
int result;
IsoDirIter *iter;
IsoDir *dir;
IsoNode *node, *node1, *node2, *node3;
/* init dir with default values, not all field need to be initialized */
dir = malloc(sizeof(IsoDir));
dir->node.refcount = 1;
dir->children = NULL;
dir->nchildren = 0;
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* remove on empty dir! */
result = iso_dir_iter_remove(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
iso_dir_iter_free(iter);
/* 1st node to be added */
node1 = calloc(1, sizeof(IsoNode));
node1->name = "Node1";
node1->refcount = 2;
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1);
/* test iteration again */
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* remove before iso_dir_iter_next() */
result = iso_dir_iter_remove(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
result = iso_dir_iter_next(iter, &node);
/* this should remove the child */
result = iso_dir_iter_remove(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 0);
CU_ASSERT_PTR_NULL(dir->children);
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
iso_dir_iter_free(iter);
/* add two node */
node1->refcount++; /* was removed above */
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1);
node2 = calloc(1, sizeof(IsoNode));
node2->name = "A node to be added first";
node2->refcount = 2;
result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* remove before iso_dir_iter_next() */
result = iso_dir_iter_remove(iter);
CU_ASSERT_TRUE(result < 0); /* should fail */
/* iter should have two items... */
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
/* remove node 2 */
result = iso_dir_iter_remove(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 1);
CU_ASSERT_PTR_EQUAL(dir->children, node1);
/* next should still work */
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node1);
/* ...and no more */
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_PTR_NULL(node);
iso_dir_iter_free(iter);
/* now remove only last child */
node2->refcount++; /* was removed above */
result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node1);
/* take last child */
result = iso_dir_iter_remove(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 1);
CU_ASSERT_PTR_EQUAL(dir->children, node2);
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 0);
CU_ASSERT_PTR_NULL(node);
iso_dir_iter_free(iter);
/* Ok, now another situation. Modification of dir during iteration */
node1->refcount++;
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
/* returned dir is node2, it should be the node taken next, but
* let's insert a node after node2 and before node1 */
node3 = calloc(1, sizeof(IsoNode));
node3->name = "A node to be added second";
node3->refcount = 2;
result = iso_dir_add_node(dir, node3, 0);
CU_ASSERT_EQUAL(dir->nchildren, 3);
/* is the node 2 the removed one? */
result = iso_dir_iter_remove(iter);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_EQUAL(dir->nchildren, 2);
CU_ASSERT_PTR_EQUAL(dir->children, node3);
CU_ASSERT_PTR_EQUAL(node3->next, node1);
iso_dir_iter_free(iter);
/* assert correct refcount */
CU_ASSERT_EQUAL(node1->refcount, 2); /* node1 is not removed */
free(node1);
CU_ASSERT_EQUAL(node2->refcount, 1);
free(node2);
CU_ASSERT_EQUAL(node3->refcount, 2); /* node3 is not removed */
free(node3);
free(dir);
}
static
void test_iso_dir_iter_when_external_take()
{
int result;
IsoDirIter *iter;
IsoDir *dir;
IsoNode *node, *node1, *node2;
/* init dir with default values, not all field need to be initialized */
dir = malloc(sizeof(IsoDir));
dir->node.refcount = 1;
dir->children = NULL;
dir->nchildren = 0;
/* 1st node to be added */
node1 = calloc(1, sizeof(IsoNode));
node1->name = "Node1";
node1->refcount = 1;
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1);
/* test iteration again */
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* take node */
result = iso_node_take(node1);
CU_ASSERT_EQUAL(result, 1);
/* iter should reflect changes */
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 0);
iso_dir_iter_free(iter);
/* add two nodes */
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 1);
node2 = calloc(1, sizeof(IsoNode));
node2->name = "A node to be added first";
node2->refcount = 1;
result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
/* iter should have two items... */
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
/* remove node 1 asynchronously */
result = iso_node_take(node1);
CU_ASSERT_EQUAL(result, 1);
/* iter should reflect changes */
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 0);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 0);
iso_dir_iter_free(iter);
/* now remove iter has itered */
result = iso_dir_add_node(dir, node1, 0);
CU_ASSERT_EQUAL(dir->nchildren, 2);
result = iso_dir_get_children(dir, &iter);
CU_ASSERT_EQUAL(result, 1);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node2);
/* remove node 2 asynchronously */
result = iso_node_take(node2);
CU_ASSERT_EQUAL(result, 1);
/* iter should reflect changes */
result = iso_dir_iter_has_next(iter);
CU_ASSERT_EQUAL(result, 1);
result = iso_dir_iter_next(iter, &node);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(node, node1);
iso_dir_iter_free(iter);
/* assert correct refcount */
CU_ASSERT_EQUAL(node1->refcount, 1);
free(node1);
CU_ASSERT_EQUAL(node2->refcount, 1);
free(node2);
free(dir);
}
static
void test_iso_node_take() void test_iso_node_take()
{ {
int result; int result;
@ -541,6 +980,7 @@ void test_iso_node_take()
/* 1st node to be added */ /* 1st node to be added */
node1 = calloc(1, sizeof(IsoNode)); node1 = calloc(1, sizeof(IsoNode));
node1->name = "Node1"; node1->name = "Node1";
node1->refcount = 1;
/* addition of node to an empty dir */ /* addition of node to an empty dir */
result = iso_dir_add_node(dir, node1, 0); result = iso_dir_add_node(dir, node1, 0);
@ -561,6 +1001,7 @@ void test_iso_node_take()
/* addition of a 2nd node, to be inserted before */ /* addition of a 2nd node, to be inserted before */
node2 = calloc(1, sizeof(IsoNode)); node2 = calloc(1, sizeof(IsoNode));
node2->name = "A node to be added first"; node2->name = "A node to be added first";
node2->refcount = 1;
result = iso_dir_add_node(dir, node2, 0); result = iso_dir_add_node(dir, node2, 0);
CU_ASSERT_EQUAL(result, 2); CU_ASSERT_EQUAL(result, 2);
@ -595,6 +1036,7 @@ void test_iso_node_take()
/* ...and a 3rd child, to be inserted last */ /* ...and a 3rd child, to be inserted last */
node3 = calloc(1, sizeof(IsoNode)); node3 = calloc(1, sizeof(IsoNode));
node3->name = "This node will be inserted last"; node3->name = "This node will be inserted last";
node3->refcount = 1;
result = iso_dir_add_node(dir, node3, 0); result = iso_dir_add_node(dir, node3, 0);
CU_ASSERT_EQUAL(result, 3); CU_ASSERT_EQUAL(result, 3);
@ -610,8 +1052,12 @@ void test_iso_node_take()
CU_ASSERT_PTR_NULL(node1->next); CU_ASSERT_PTR_NULL(node1->next);
CU_ASSERT_PTR_NULL(node1->parent); CU_ASSERT_PTR_NULL(node1->parent);
/* assert correct refcount */
CU_ASSERT_EQUAL(node1->refcount, 1);
free(node1); free(node1);
CU_ASSERT_EQUAL(node2->refcount, 1);
free(node2); free(node2);
CU_ASSERT_EQUAL(node3->refcount, 1);
free(node3); free(node3);
free(dir); free(dir);
} }
@ -668,6 +1114,183 @@ void test_iso_node_set_name()
free(dir); free(dir);
} }
static
int xinfo_a(void *data, int flag) {
return 1;
}
static
int xinfo_b(void *data, int flag) {
return 1;
}
static
void test_iso_node_add_xinfo()
{
int result;
IsoNode *node;
/* cretae a node */
node = calloc(1, sizeof(IsoNode));
/* add xinfo data */
result = iso_node_add_xinfo(node, xinfo_a, NULL);
CU_ASSERT_EQUAL(result, 1);
/* we can't add again the same xinfo type */
result = iso_node_add_xinfo(node, xinfo_a, &result);
CU_ASSERT_EQUAL(result, 0);
result = iso_node_add_xinfo(node, xinfo_b, NULL);
CU_ASSERT_EQUAL(result, 1);
free(node->xinfo->next);
free(node->xinfo);
free(node);
}
static
void test_iso_node_get_xinfo()
{
int result;
IsoNode *node;
char *one_data = "my data";
char *another_data = "my data 2";
void *data;
/* cretae a node */
node = calloc(1, sizeof(IsoNode));
/* at the beginning we have no data */
result = iso_node_get_xinfo(node, xinfo_b, &data);
CU_ASSERT_EQUAL(result, 0);
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 0);
/* add xinfo data */
result = iso_node_add_xinfo(node, xinfo_a, one_data);
CU_ASSERT_EQUAL(result, 1);
/* we get the correct data */
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
/* we can't add again the same xinfo type */
result = iso_node_add_xinfo(node, xinfo_a, &result);
CU_ASSERT_EQUAL(result, 0);
/* we get the correct data again */
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
/* xinfo_b has no data */
result = iso_node_get_xinfo(node, xinfo_b, &data);
CU_ASSERT_EQUAL(result, 0);
/* add another xinfo */
result = iso_node_add_xinfo(node, xinfo_b, another_data);
CU_ASSERT_EQUAL(result, 1);
/* test both data is returned propertly */
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
result = iso_node_get_xinfo(node, xinfo_b, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, another_data);
free(node->xinfo->next);
free(node->xinfo);
free(node);
}
static
void test_iso_node_remove_xinfo()
{
int result;
IsoNode *node;
char *one_data = "my data";
char *another_data = "my data 2";
void *data;
/* cretae a node */
node = calloc(1, sizeof(IsoNode));
/* try to remove inexistent data */
result = iso_node_remove_xinfo(node, xinfo_b);
CU_ASSERT_EQUAL(result, 0);
result = iso_node_remove_xinfo(node, xinfo_a);
CU_ASSERT_EQUAL(result, 0);
/* add xinfo data */
result = iso_node_add_xinfo(node, xinfo_a, one_data);
CU_ASSERT_EQUAL(result, 1);
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
/* remove it */
result = iso_node_remove_xinfo(node, xinfo_b);
CU_ASSERT_EQUAL(result, 0);
result = iso_node_remove_xinfo(node, xinfo_a);
CU_ASSERT_EQUAL(result, 1);
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 0);
/* add again the same xinfo type */
result = iso_node_add_xinfo(node, xinfo_a, one_data);
CU_ASSERT_EQUAL(result, 1);
/* we get the correct data again */
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
/* add another xinfo */
result = iso_node_add_xinfo(node, xinfo_b, another_data);
CU_ASSERT_EQUAL(result, 1);
/* test both data is returned propertly */
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
result = iso_node_get_xinfo(node, xinfo_b, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, another_data);
/* remove b */
result = iso_node_remove_xinfo(node, xinfo_b);
CU_ASSERT_EQUAL(result, 1);
/* only a can be get */
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 1);
CU_ASSERT_PTR_EQUAL(data, one_data);
result = iso_node_get_xinfo(node, xinfo_b, &data);
CU_ASSERT_EQUAL(result, 0);
/* try to remove b again */
result = iso_node_remove_xinfo(node, xinfo_b);
CU_ASSERT_EQUAL(result, 0);
/* remove a */
result = iso_node_remove_xinfo(node, xinfo_a);
CU_ASSERT_EQUAL(result, 1);
result = iso_node_get_xinfo(node, xinfo_a, &data);
CU_ASSERT_EQUAL(result, 0);
result = iso_node_get_xinfo(node, xinfo_b, &data);
CU_ASSERT_EQUAL(result, 0);
free(node);
}
void add_node_suite() void add_node_suite()
{ {
CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL); CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL);
@ -685,6 +1308,12 @@ void add_node_suite()
CU_add_test(pSuite, "iso_dir_add_node()", test_iso_dir_add_node); CU_add_test(pSuite, "iso_dir_add_node()", test_iso_dir_add_node);
CU_add_test(pSuite, "iso_dir_get_node()", test_iso_dir_get_node); CU_add_test(pSuite, "iso_dir_get_node()", test_iso_dir_get_node);
CU_add_test(pSuite, "iso_dir_get_children()", test_iso_dir_get_children); CU_add_test(pSuite, "iso_dir_get_children()", test_iso_dir_get_children);
CU_add_test(pSuite, "iso_dir_iter_take()", test_iso_dir_iter_take);
CU_add_test(pSuite, "iso_dir_iter_remove()", test_iso_dir_iter_remove);
CU_add_test(pSuite, "iso_node_take()", test_iso_node_take); CU_add_test(pSuite, "iso_node_take()", test_iso_node_take);
CU_add_test(pSuite, "iso_node_take() during iteration", test_iso_dir_iter_when_external_take);
CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name); CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name);
CU_add_test(pSuite, "iso_node_add_xinfo()", test_iso_node_add_xinfo);
CU_add_test(pSuite, "iso_node_get_xinfo()", test_iso_node_get_xinfo);
CU_add_test(pSuite, "iso_node_remove_xinfo()", test_iso_node_remove_xinfo);
} }

View File

@ -43,13 +43,13 @@ void test_mem_open()
/* try to open an already opened stream */ /* try to open an already opened stream */
ret = iso_stream_open(stream); ret = iso_stream_open(stream);
CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENNED); CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENED);
ret = iso_stream_close(stream); ret = iso_stream_close(stream);
CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(ret, 1);
ret = iso_stream_close(stream); ret = iso_stream_close(stream);
CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENNED); CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENED);
iso_stream_unref(stream); iso_stream_unref(stream);
} }