diff --git a/libisofs/branches/thomas/libisofs/filter.c b/libisofs/branches/thomas/libisofs/filter.c new file mode 100644 index 00000000..a7f2be69 --- /dev/null +++ b/libisofs/branches/thomas/libisofs/filter.c @@ -0,0 +1,49 @@ +/* + * 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 "filter.h" +#include "node.h" + + +void iso_filter_ref(FilterContext *filter) +{ + ++filter->refcount; +} + +void iso_filter_unref(FilterContext *filter) +{ + if (--filter->refcount == 0) { + filter->free(filter); + free(filter); + } +} + +int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag) +{ + int ret; + IsoStream *original, *filtered; + if (file == NULL || filter == NULL) { + return ISO_NULL_POINTER; + } + + 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; + } + iso_stream_unref(original); + file->stream = filtered; + return ISO_SUCCESS; +} diff --git a/libisofs/branches/thomas/libisofs/filter.h b/libisofs/branches/thomas/libisofs/filter.h new file mode 100644 index 00000000..f711fe31 --- /dev/null +++ b/libisofs/branches/thomas/libisofs/filter.h @@ -0,0 +1,62 @@ +/* + * 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. + */ +#ifndef LIBISO_FILTER_H_ +#define LIBISO_FILTER_H_ + +/* + * Definitions of filters. + */ + +/* dev_id for stream identification */ +#define XOR_ENCRYPT_DEV_ID 1 + +typedef struct filter_context FilterContext; + +struct filter_context { + int version; /* reserved for future usage, set to 0 */ + int refcount; + + /** filter specific shared data */ + void *data; + + /** + * Factory method to create a filtered stream from another stream. + * + * @param original + * The original stream to be filtered. If the filter needs a ref to + * it (most cases), it should take a ref to it with iso_stream_ref(). + * @param filtered + * Will be filled with the filtered IsoStream (reference belongs to + * caller). + * @return + * 1 on success, < 0 on error + */ + int (*get_filter)(FilterContext *filter, IsoStream *original, + IsoStream **filtered); + + /** + * Free implementation specific data. Should never be called by user. + * Use iso_filter_unref() instead. + */ + void (*free)(FilterContext *filter); +}; + +/** + * + * @param flag + * Reserved for future usage, pass always 0 for now. + * TODO in a future a different value can mean filter caching, where + * the filter is applied once and the filtered file is stored in a temp + * dir. This prevent filter to be applied several times. + */ +int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag); + +void iso_filter_ref(FilterContext *filter); +void iso_filter_unref(FilterContext *filter); + +#endif /*LIBISO_FILTER_H_*/ diff --git a/libisofs/branches/thomas/libisofs/filters/xor_encrypt.c b/libisofs/branches/thomas/libisofs/filters/xor_encrypt.c new file mode 100644 index 00000000..be83f725 --- /dev/null +++ b/libisofs/branches/thomas/libisofs/filters/xor_encrypt.c @@ -0,0 +1,187 @@ +/* + * 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 "../filter.h" +#include "../fsource.h" + +/* + * A simple Filter implementation for example purposes. It encrypts a file + * by XORing each byte by a given key. + */ + +static ino_t xor_ino_id = 0; + +typedef struct +{ + IsoStream *orig; + uint8_t key; + ino_t id; +} XorEncryptStreamData; + +static +int xor_encrypt_stream_open(IsoStream *stream) +{ + XorEncryptStreamData *data; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + data = (XorEncryptStreamData*)stream->data; + return iso_stream_open(data->orig); +} + +static +int xor_encrypt_stream_close(IsoStream *stream) +{ + XorEncryptStreamData *data; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + data = stream->data; + return iso_stream_close(data->orig); +} + +static +off_t xor_encrypt_stream_get_size(IsoStream *stream) +{ + XorEncryptStreamData *data; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + data = stream->data; + return iso_stream_get_size(data->orig); +} + +static +int xor_encrypt_stream_read(IsoStream *stream, void *buf, size_t count) +{ + int ret, len; + XorEncryptStreamData *data; + uint8_t *buffer = buf; + + if (stream == NULL) { + return ISO_NULL_POINTER; + } + data = stream->data; + ret = iso_stream_read(data->orig, buf, count); + if (ret < 0) { + return ret; + } + + /* xor */ + for (len = 0; len < ret; ++len) { + buffer[len] = buffer[len] ^ data->key; + } + + return ret; +} + +static +int xor_encrypt_stream_is_repeatable(IsoStream *stream) +{ + /* the filter can't be created if underlying stream is not repeatable */ + return 1; +} + +static +void xor_encrypt_stream_get_id(IsoStream *stream, unsigned int *fs_id, + dev_t *dev_id, ino_t *ino_id) +{ + XorEncryptStreamData *data = stream->data; + *fs_id = ISO_FILTER_FS_ID; + *dev_id = XOR_ENCRYPT_DEV_ID; + *ino_id = data->id; +} + +static +void xor_encrypt_stream_free(IsoStream *stream) +{ + XorEncryptStreamData *data = stream->data; + iso_stream_unref(data->orig); + free(data); +} + +IsoStreamIface xor_encrypt_stream_class = { + 0, + "xorf", + xor_encrypt_stream_open, + xor_encrypt_stream_close, + xor_encrypt_stream_get_size, + xor_encrypt_stream_read, + xor_encrypt_stream_is_repeatable, + xor_encrypt_stream_get_id, + xor_encrypt_stream_free +}; + + +static +void xor_encrypt_filter_free(FilterContext *filter) +{ + free(filter->data); +} + +static +int xor_encrypt_filter_get_filter(FilterContext *filter, IsoStream *original, + IsoStream **filtered) +{ + IsoStream *str; + XorEncryptStreamData *data; + + if (filter == NULL || original == NULL || filtered == NULL) { + return ISO_NULL_POINTER; + } + + str = malloc(sizeof(IsoStream)); + if (str == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(XorEncryptStreamData)); + if (str == NULL) { + free(str); + return ISO_OUT_OF_MEM; + } + + /* fill data */ + data->key = *((uint8_t*)filter->data); + data->id = xor_ino_id++; + + /* get reference to the source */ + data->orig = original; + iso_stream_ref(original); + + str->refcount = 1; + str->data = data; + str->class = &xor_encrypt_stream_class; + + *filtered = str; + return ISO_SUCCESS; +} + +int create_xor_encrypt_filter(uint8_t key, FilterContext **filter) +{ + FilterContext *f; + uint8_t *data; + + f = calloc(1, sizeof(FilterContext)); + if (f == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(uint8_t)); + if (data == NULL) { + free(f); + return ISO_OUT_OF_MEM; + } + f->refcount = 1; + f->version = 0; + *data = key; + f->data = data; + f->free = xor_encrypt_filter_free; + f->get_filter = xor_encrypt_filter_get_filter; + + return ISO_SUCCESS; +} diff --git a/libisofs/branches/thomas/libisofs/find.c b/libisofs/branches/thomas/libisofs/find.c new file mode 100644 index 00000000..02881130 --- /dev/null +++ b/libisofs/branches/thomas/libisofs/find.c @@ -0,0 +1,617 @@ +/* + * 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 +#include + +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 +{ + IsoDirIter *iter; + IsoFindCondition *cond; +}; + +static +int find_iter_next(IsoDirIter *iter, IsoNode **node) +{ + int ret; + IsoNode *n; + struct find_iter_data *data = iter->data; + + while ((ret = iso_dir_iter_next(data->iter, &n)) == 1) { + if (data->cond->matches(data->cond, n)) { + *node = n; + break; + } + } + return ret; +} + +static +int find_iter_has_next(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + + /* + * FIXME wrong implementation!!!! the underlying iter may have more nodes, + * but they may not match find conditions + */ + return iso_dir_iter_has_next(data->iter); +} + +static +void find_iter_free(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + data->cond->free(data->cond); + free(data->cond); + iso_dir_iter_free(data->iter); + free(iter->data); +} + +static +int find_iter_take(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + return iso_dir_iter_take(data->iter); +} + +static +int find_iter_remove(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + return iso_dir_iter_remove(data->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 +}; + +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->cond = cond; + it->data = data; + + *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; +} +