Implemented safety cap and did merge with vreixo branch
This commit is contained in:
commit
7e617733b1
@ -38,3 +38,4 @@ demo/isogrow
|
||||
doc/html
|
||||
doc/doxygen.conf
|
||||
libisofs-1.pc
|
||||
demo/find
|
||||
|
@ -16,6 +16,7 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/node.c \
|
||||
libisofs/tree.h \
|
||||
libisofs/tree.c \
|
||||
libisofs/find.c \
|
||||
libisofs/image.h \
|
||||
libisofs/image.c \
|
||||
libisofs/fsource.h \
|
||||
@ -54,6 +55,8 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/iso1999.h \
|
||||
libisofs/iso1999.c \
|
||||
libisofs/data_source.c
|
||||
libisofs_libisofs_la_LIBADD= \
|
||||
$(THREAD_LIBS)
|
||||
libinclude_HEADERS = \
|
||||
libisofs/libisofs.h
|
||||
|
||||
@ -65,6 +68,7 @@ noinst_PROGRAMS = \
|
||||
demo/cat \
|
||||
demo/catbuffer \
|
||||
demo/tree \
|
||||
demo/find \
|
||||
demo/ecma119tree \
|
||||
demo/iso \
|
||||
demo/isoread \
|
||||
@ -89,6 +93,10 @@ demo_tree_CPPFLAGS = -Ilibisofs
|
||||
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
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_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_ecma119tree_SOURCES = demo/ecma119_tree.c
|
||||
|
1
TODO
1
TODO
@ -9,7 +9,6 @@ TODO
|
||||
#00004 (libisofs.h) -> Add a get_mime_type() function.
|
||||
#00005 (node.c) -> optimize iso_dir_iter_take.
|
||||
#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
|
||||
#00009 (ecma119_tree.c/h) -> add true support for harlinks and inode numbers
|
||||
#00010 (buffer.c) -> optimize ring buffer
|
||||
|
63
demo/find.c
Normal file
63
demo/find.c
Normal 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;
|
||||
}
|
@ -52,12 +52,13 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
|
||||
if (ret < 0) {
|
||||
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);
|
||||
ret = iso_node_new_file(name, stream, &node);
|
||||
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);
|
||||
free(name);
|
||||
return ret;
|
||||
|
@ -34,8 +34,7 @@ struct Iso_Node_Builder
|
||||
* In that case, if the implementation can't do the conversion, it
|
||||
* should fail propertly.
|
||||
*
|
||||
* On sucess, the ref. to src will be owned by file, so you musn't
|
||||
* unref it.
|
||||
* Note that the src is never unref, so you need to free it.
|
||||
*
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
|
@ -57,7 +57,7 @@ int ds_open(IsoDataSource *src)
|
||||
|
||||
data = (struct file_data_src*) src->data;
|
||||
if (data->fd != -1) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
fd = open(data->path, O_RDONLY);
|
||||
@ -81,7 +81,7 @@ int ds_close(IsoDataSource *src)
|
||||
|
||||
data = (struct file_data_src*) src->data;
|
||||
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 */
|
||||
@ -102,7 +102,7 @@ static int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
|
||||
|
||||
data = (struct file_data_src*) src->data;
|
||||
if (data->fd == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
/* goes to requested block */
|
||||
|
@ -538,7 +538,7 @@ int catalog_open(IsoStream *stream)
|
||||
data = stream->data;
|
||||
|
||||
if (data->offset != -1) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
memset(data->buffer, 0, BLOCK_SIZE);
|
||||
@ -563,7 +563,7 @@ int catalog_close(IsoStream *stream)
|
||||
data = stream->data;
|
||||
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
data->offset = -1;
|
||||
return ISO_SUCCESS;
|
||||
@ -589,7 +589,7 @@ int catalog_read(IsoStream *stream, void *buf, size_t count)
|
||||
data = stream->data;
|
||||
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
len = MIN(count, BLOCK_SIZE - data->offset);
|
||||
|
@ -33,6 +33,12 @@ int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag)
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
|
761
libisofs/find.c
Normal file
761
libisofs/find.c
Normal 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;
|
||||
}
|
||||
|
@ -474,7 +474,7 @@ int ifs_open(IsoFileSource *src)
|
||||
data = (ImageFileSourceData*)src->data;
|
||||
|
||||
if (data->opened) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
if (S_ISDIR(data->info.st_mode)) {
|
||||
@ -530,7 +530,7 @@ int ifs_close(IsoFileSource *src)
|
||||
data = (ImageFileSourceData*)src->data;
|
||||
|
||||
if (!data->opened) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
if (data->opened == 2) {
|
||||
@ -569,7 +569,7 @@ int ifs_close(IsoFileSource *src)
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
* ISO_FILE_IS_DIR
|
||||
* ISO_OUT_OF_MEM
|
||||
* ISO_INTERRUPTED
|
||||
@ -590,7 +590,7 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
|
||||
data = (ImageFileSourceData*)src->data;
|
||||
|
||||
if (!data->opened) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
} else if (data->opened != 1) {
|
||||
return ISO_FILE_IS_DIR;
|
||||
}
|
||||
@ -632,6 +632,60 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
|
||||
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
|
||||
int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||
{
|
||||
@ -644,7 +698,7 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||
data = (ImageFileSourceData*)src->data;
|
||||
|
||||
if (!data->opened) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
} else if (data->opened != 2) {
|
||||
return ISO_FILE_IS_NOT_DIR;
|
||||
}
|
||||
@ -774,7 +828,8 @@ IsoFileSourceIface ifs_class = {
|
||||
ifs_readdir,
|
||||
ifs_readlink,
|
||||
ifs_get_filesystem,
|
||||
ifs_free
|
||||
ifs_free,
|
||||
ifs_lseek
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2081,7 +2136,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
free(name);
|
||||
return ret;
|
||||
}
|
||||
link = malloc(sizeof(IsoSymlink));
|
||||
link = calloc(1, sizeof(IsoSymlink));
|
||||
if (link == NULL) {
|
||||
free(name);
|
||||
return ISO_OUT_OF_MEM;
|
||||
@ -2099,7 +2154,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
{
|
||||
/* source is an special file */
|
||||
IsoSpecial *special;
|
||||
special = malloc(sizeof(IsoSpecial));
|
||||
special = calloc(1, sizeof(IsoSpecial));
|
||||
if (special == NULL) {
|
||||
free(name);
|
||||
return ISO_OUT_OF_MEM;
|
||||
|
@ -190,7 +190,7 @@ int lfs_open(IsoFileSource *src)
|
||||
|
||||
data = src->data;
|
||||
if (data->openned) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
break;
|
||||
default:
|
||||
ret = ISO_FILE_NOT_OPENNED;
|
||||
ret = ISO_FILE_NOT_OPENED;
|
||||
break;
|
||||
}
|
||||
if (ret == ISO_SUCCESS) {
|
||||
@ -300,7 +300,53 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count)
|
||||
case 2: /* directory */
|
||||
return ISO_FILE_IS_DIR;
|
||||
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;
|
||||
}
|
||||
default:
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +479,8 @@ IsoFileSourceIface lfs_class = {
|
||||
lfs_readdir,
|
||||
lfs_readlink,
|
||||
lfs_get_filesystem,
|
||||
lfs_free
|
||||
lfs_free,
|
||||
lfs_lseek
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t 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
|
||||
int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||
{
|
||||
|
@ -519,7 +519,7 @@ struct IsoFileSource_Iface
|
||||
* Opens the source.
|
||||
* @return 1 on success, < 0 on error
|
||||
* Error codes:
|
||||
* ISO_FILE_ALREADY_OPENNED
|
||||
* ISO_FILE_ALREADY_OPENED
|
||||
* ISO_FILE_ACCESS_DENIED
|
||||
* ISO_FILE_BAD_PATH
|
||||
* ISO_FILE_DOESNT_EXIST
|
||||
@ -535,7 +535,7 @@ struct IsoFileSource_Iface
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
*/
|
||||
int (*close)(IsoFileSource *src);
|
||||
|
||||
@ -552,7 +552,7 @@ struct IsoFileSource_Iface
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
* ISO_WRONG_ARG_VALUE -> if count == 0
|
||||
* ISO_FILE_IS_DIR
|
||||
* ISO_OUT_OF_MEM
|
||||
@ -578,7 +578,7 @@ struct IsoFileSource_Iface
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
* ISO_FILE_IS_NOT_DIR
|
||||
* ISO_OUT_OF_MEM
|
||||
*/
|
||||
@ -622,6 +622,26 @@ struct IsoFileSource_Iface
|
||||
* Use iso_file_source_unref() instead.
|
||||
*/
|
||||
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.
|
||||
@ -1800,6 +1820,78 @@ void iso_node_unref(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
|
||||
* 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 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_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
|
||||
*
|
||||
@ -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.
|
||||
* 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
|
||||
* between then is undefined, and should never occur. (TODO protect against this?)
|
||||
* If you call this function twice without calling iso_dir_iter_next between
|
||||
* them is not allowed and you will get an ISO_ERROR in second call.
|
||||
*
|
||||
* @return
|
||||
* 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.
|
||||
* The node removed will be the last returned by the iteration.
|
||||
*
|
||||
* The behavior on two call to this function without calling iso_tree_iter_next
|
||||
* between then is undefined, and should never occur. (TODO protect against this?)
|
||||
* If you call this function twice without calling iso_dir_iter_next between
|
||||
* them is not allowed and you will get an ISO_ERROR in second call.
|
||||
*
|
||||
* @return
|
||||
* 1 on succes, < 0 error
|
||||
@ -2164,6 +2256,191 @@ int iso_dir_iter_take(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.
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/*
|
||||
TODO #00007 expose Stream and this function:
|
||||
int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file)
|
||||
/**
|
||||
* 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. 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,
|
||||
@ -2517,6 +2849,73 @@ void iso_tree_set_report_callback(IsoImage *image,
|
||||
int iso_tree_add_node(IsoImage *image, IsoDir *parent, 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -2893,7 +3302,7 @@ int iso_file_source_stat(IsoFileSource *src, struct stat *info);
|
||||
* Opens the source.
|
||||
* @return 1 on success, < 0 on error
|
||||
* Error codes:
|
||||
* ISO_FILE_ALREADY_OPENNED
|
||||
* ISO_FILE_ALREADY_OPENED
|
||||
* ISO_FILE_ACCESS_DENIED
|
||||
* ISO_FILE_BAD_PATH
|
||||
* ISO_FILE_DOESNT_EXIST
|
||||
@ -2911,7 +3320,7 @@ int iso_file_source_open(IsoFileSource *src);
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
*
|
||||
* @since 0.6.2
|
||||
*/
|
||||
@ -2937,7 +3346,7 @@ int iso_file_source_close(IsoFileSource *src);
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
* ISO_WRONG_ARG_VALUE -> if count == 0
|
||||
* ISO_FILE_IS_DIR
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -2965,7 +3393,7 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count);
|
||||
* Error codes:
|
||||
* ISO_FILE_ERROR
|
||||
* ISO_NULL_POINTER
|
||||
* ISO_FILE_NOT_OPENNED
|
||||
* ISO_FILE_NOT_OPENED
|
||||
* ISO_FILE_IS_NOT_DIR
|
||||
* 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
|
||||
|
||||
/** 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
|
||||
|
||||
/** 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
|
||||
|
||||
/** 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) */
|
||||
#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
|
||||
* (HINT,MEDIUM, -141)
|
||||
* (HINT,MEDIUM, -144)
|
||||
*/
|
||||
#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) */
|
||||
#define ISO_CHARSET_CONV_ERROR 0xE830FF00
|
||||
|
||||
|
@ -136,16 +136,16 @@ const char *iso_error_to_msg(int errcode)
|
||||
return "Trying to use an invalid file as boot image";
|
||||
case ISO_FILE_ERROR:
|
||||
return "Error on file operation";
|
||||
case ISO_FILE_ALREADY_OPENNED:
|
||||
return "Trying to open an already openned file";
|
||||
case ISO_FILE_ALREADY_OPENED:
|
||||
return "Trying to open an already opened file";
|
||||
case ISO_FILE_ACCESS_DENIED:
|
||||
return "Access to file is not allowed";
|
||||
case ISO_FILE_BAD_PATH:
|
||||
return "Incorrect path to file";
|
||||
case ISO_FILE_DOESNT_EXIST:
|
||||
return "The file does not exist in the filesystem";
|
||||
case ISO_FILE_NOT_OPENNED:
|
||||
return "Trying to read or close a file not openned";
|
||||
case ISO_FILE_NOT_OPENED:
|
||||
return "Trying to read or close a file not opened";
|
||||
case ISO_FILE_IS_DIR:
|
||||
return "Directory used where no dir is expected";
|
||||
case ISO_FILE_READ_ERROR:
|
||||
|
525
libisofs/node.c
525
libisofs/node.c
@ -15,6 +15,17 @@
|
||||
#include <time.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.
|
||||
*/
|
||||
@ -58,19 +69,144 @@ void iso_node_unref(IsoNode *node)
|
||||
/* other kind of nodes does not need to delete anything here */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
|
||||
if (node->xinfo) {
|
||||
/* free extended info */
|
||||
node->xinfo->process(node->xinfo->data, 1);
|
||||
free(node->xinfo);
|
||||
IsoExtendedInfo *info = node->xinfo;
|
||||
while (info != NULL) {
|
||||
IsoExtendedInfo *tmp = info->next;
|
||||
|
||||
/* free extended info */
|
||||
info->process(info->data, 1);
|
||||
free(info);
|
||||
info = tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(node->name);
|
||||
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.
|
||||
*/
|
||||
@ -354,42 +490,53 @@ int iso_dir_get_children_count(IsoDir *dir)
|
||||
return dir->nchildren;
|
||||
}
|
||||
|
||||
int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter)
|
||||
static
|
||||
int iter_next(IsoDirIter *iter, IsoNode **node)
|
||||
{
|
||||
IsoDirIter *it;
|
||||
|
||||
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;
|
||||
struct dir_iter_data *data;
|
||||
if (iter == NULL || node == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
n = iter->pos;
|
||||
if (n == NULL) {
|
||||
*node = NULL;
|
||||
return 0;
|
||||
|
||||
data = iter->data;
|
||||
|
||||
/* 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 */
|
||||
return ISO_ERROR;
|
||||
}
|
||||
*node = n;
|
||||
iter->pos = n->next;
|
||||
|
||||
/* ok, take a ref to the current position, to prevent internal errors
|
||||
* if deleted somewhere */
|
||||
iso_node_ref(data->pos);
|
||||
data->flag |= 0x01; /* set next flag */
|
||||
|
||||
/* return pointed node */
|
||||
*node = data->pos;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -401,17 +548,30 @@ int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
|
||||
* Possible errors:
|
||||
* 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) {
|
||||
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)
|
||||
@ -448,8 +608,12 @@ int iso_node_take(IsoNode *node)
|
||||
pos = iso_dir_find_node(dir, node);
|
||||
if (pos == NULL) {
|
||||
/* should never occur */
|
||||
return ISO_ERROR;
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
/* notify iterators just before remove */
|
||||
iso_notify_dir_iters(node, 0);
|
||||
|
||||
*pos = node->next;
|
||||
node->parent = NULL;
|
||||
node->next = NULL;
|
||||
@ -492,43 +656,167 @@ IsoDir *iso_node_get_parent(IsoNode *node)
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
data = iter->data;
|
||||
|
||||
if (!(data->flag & 0x01)) {
|
||||
return ISO_ERROR; /* next not called or end of dir */
|
||||
}
|
||||
|
||||
if (data->pos == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
/* clear next flag */
|
||||
data->flag &= ~0x01;
|
||||
|
||||
return iso_node_take(data->pos);
|
||||
}
|
||||
|
||||
pos = iter->dir->children;
|
||||
if (iter->pos == pos) {
|
||||
return ISO_ERROR;
|
||||
static
|
||||
int iter_remove(IsoDirIter *iter)
|
||||
{
|
||||
int ret;
|
||||
IsoNode *pos;
|
||||
struct dir_iter_data *data;
|
||||
|
||||
if (iter == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
while (pos != NULL && pos->next == iter->pos) {
|
||||
pos = pos->next;
|
||||
data = iter->data;
|
||||
pos = data->pos;
|
||||
|
||||
ret = iter_take(iter);
|
||||
if (ret == ISO_SUCCESS) {
|
||||
/* remove node */
|
||||
iso_node_unref(pos);
|
||||
}
|
||||
if (pos == NULL) {
|
||||
return ISO_ERROR;
|
||||
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 */
|
||||
}
|
||||
}
|
||||
return iso_node_take(pos);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
IsoNode *pos;
|
||||
if (iter == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
pos = iter->dir->children;
|
||||
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);
|
||||
return iter->class->remove(iter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -618,6 +906,58 @@ IsoStream *iso_file_get_stream(IsoFile *file)
|
||||
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.
|
||||
*
|
||||
@ -765,6 +1105,63 @@ int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
|
||||
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)
|
||||
{
|
||||
IsoDir *dir;
|
||||
|
@ -20,9 +20,6 @@
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* #define LIBISO_EXTENDED_INFORMATION */
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
|
||||
/**
|
||||
* The extended information is a way to attach additional information to each
|
||||
* IsoNode. External applications may want to use this extension system to
|
||||
@ -55,7 +52,7 @@ struct iso_extended_info {
|
||||
* @return
|
||||
* 1
|
||||
*/
|
||||
int (*process)(void *data, int flag);
|
||||
iso_node_xinfo_func process;
|
||||
|
||||
/**
|
||||
* Pointer to information specific data.
|
||||
@ -63,8 +60,6 @@ struct iso_extended_info {
|
||||
void *data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -102,12 +97,10 @@ struct Iso_Node
|
||||
*/
|
||||
IsoNode *next;
|
||||
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
/**
|
||||
* Extended information for the node.
|
||||
*/
|
||||
IsoExtendedInfo *xinfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Iso_Dir
|
||||
@ -148,13 +141,37 @@ struct Iso_Special
|
||||
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.
|
||||
*/
|
||||
struct Iso_Dir_Iter
|
||||
{
|
||||
const IsoDir *dir;
|
||||
IsoNode *pos;
|
||||
struct iso_dir_iter_iface *class;
|
||||
|
||||
/* the directory this iterator iterates over */
|
||||
IsoDir *dir;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
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,
|
||||
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_*/
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
ino_t serial_id = (ino_t)1;
|
||||
ino_t mem_serial_id = (ino_t)1;
|
||||
ino_t cut_out_serial_id = (ino_t)1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -175,7 +176,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(FSrcStreamData));
|
||||
if (str == NULL) {
|
||||
if (data == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
@ -212,6 +213,193 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
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
|
||||
@ -231,7 +419,7 @@ int mem_open(IsoStream *stream)
|
||||
}
|
||||
data = (MemStreamData*)stream->data;
|
||||
if (data->offset != -1) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
data->offset = 0;
|
||||
return ISO_SUCCESS;
|
||||
@ -246,7 +434,7 @@ int mem_close(IsoStream *stream)
|
||||
}
|
||||
data = (MemStreamData*)stream->data;
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
data->offset = -1;
|
||||
return ISO_SUCCESS;
|
||||
@ -275,7 +463,7 @@ int mem_read(IsoStream *stream, void *buf, size_t count)
|
||||
data = stream->data;
|
||||
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
if (data->offset >= data->size) {
|
||||
@ -400,7 +588,12 @@ off_t iso_stream_get_size(IsoStream *stream)
|
||||
inline
|
||||
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
|
||||
|
@ -33,6 +33,16 @@ void iso_stream_get_file_name(IsoStream *stream, char *name);
|
||||
*/
|
||||
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.
|
||||
* When the Stream refcount reach 0, the buffer is free(3).
|
||||
|
232
libisofs/tree.c
232
libisofs/tree.c
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to IsoImage.
|
||||
@ -475,6 +550,139 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
633
test/test_node.c
633
test/test_node.c
@ -410,6 +410,7 @@ void test_iso_dir_get_node()
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_dir_get_children()
|
||||
{
|
||||
int result;
|
||||
@ -419,11 +420,13 @@ void test_iso_dir_get_children()
|
||||
|
||||
/* 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);
|
||||
|
||||
/* item should have no items */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
@ -436,6 +439,7 @@ void test_iso_dir_get_children()
|
||||
/* 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);
|
||||
|
||||
@ -461,6 +465,7 @@ void test_iso_dir_get_children()
|
||||
/* add another node */
|
||||
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);
|
||||
|
||||
@ -490,6 +495,7 @@ void test_iso_dir_get_children()
|
||||
/* addition of a 3rd node, to be inserted last */
|
||||
node3 = calloc(1, sizeof(IsoNode));
|
||||
node3->name = "This node will be inserted last";
|
||||
node3->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node3, 0);
|
||||
CU_ASSERT_EQUAL(result, 3);
|
||||
|
||||
@ -520,13 +526,446 @@ void test_iso_dir_get_children()
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
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_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()
|
||||
{
|
||||
int result;
|
||||
@ -541,6 +980,7 @@ void test_iso_node_take()
|
||||
/* 1st node to be added */
|
||||
node1 = calloc(1, sizeof(IsoNode));
|
||||
node1->name = "Node1";
|
||||
node1->refcount = 1;
|
||||
|
||||
/* addition of node to an empty dir */
|
||||
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 */
|
||||
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);
|
||||
|
||||
@ -595,6 +1036,7 @@ void test_iso_node_take()
|
||||
/* ...and a 3rd child, to be inserted last */
|
||||
node3 = calloc(1, sizeof(IsoNode));
|
||||
node3->name = "This node will be inserted last";
|
||||
node3->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node3, 0);
|
||||
CU_ASSERT_EQUAL(result, 3);
|
||||
|
||||
@ -609,9 +1051,13 @@ void test_iso_node_take()
|
||||
CU_ASSERT_PTR_EQUAL(node3->parent, dir);
|
||||
CU_ASSERT_PTR_NULL(node1->next);
|
||||
CU_ASSERT_PTR_NULL(node1->parent);
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
@ -668,6 +1114,183 @@ void test_iso_node_set_name()
|
||||
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()
|
||||
{
|
||||
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_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_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() 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_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);
|
||||
}
|
||||
|
@ -43,13 +43,13 @@ void test_mem_open()
|
||||
|
||||
/* try to open an already opened 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);
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user