From fa85a17045e56479c0ec69a40a177c013f487291 Mon Sep 17 00:00:00 2001 From: Richard Maw Date: Mon, 17 Oct 2011 11:48:51 +0100 Subject: Added xattr support Fixed inconsequential memory leak in tbdiff_create.c Lost memory would be cleaned up by OS at exit, but valgrind complains --- Makefile | 6 ++-- libtbd_apply.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ libtbd_create.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- tbdiff.h | 3 ++ tbdiff_create.c | 5 ++- tests/test_lib.sh | 11 +++++-- 6 files changed, 206 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 5386d93..41b99c5 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ CFLAGS ?= CFLAGS += -g CFLAGS += -Wall -Wextra -Werror -Wno-unused-result $(OPT) -SHARED_SRC := libtbd_stat.c +SHARED_SRC := libtbd_stat.c libtbd_xattrs.c DEPLOY_SRC := tbdiff_deploy.c libtbd_create.c CREATE_SRC := tbdiff_create.c libtbd_apply.c @@ -20,10 +20,10 @@ CREATE_OBJ := $(patsubst %.c,%.o,$(SHARED_SRC) $(CREATE_SRC)) all: $(DEPLOY) $(CREATE) -$(DEPLOY): tbdiff_deploy.o libtbd_apply.o libtbd_stat.o +$(DEPLOY): tbdiff_deploy.o libtbd_apply.o libtbd_stat.o libtbd_xattrs.o $(CC) $(LDFLAGS) -o $@ $^ -$(CREATE): tbdiff_create.o libtbd_create.o libtbd_stat.o +$(CREATE): tbdiff_create.o libtbd_create.o libtbd_stat.o libtbd_xattrs.o $(CC) $(LDFLAGS) -o $@ $^ %.o: %.c diff --git a/libtbd_apply.c b/libtbd_apply.c index 858af18..4a7b473 100644 --- a/libtbd_apply.c +++ b/libtbd_apply.c @@ -32,6 +32,9 @@ #include #include +#include +#include "libtbd_xattrs.h" + char* tbd_apply_fread_string(FILE *stream) { @@ -46,6 +49,39 @@ tbd_apply_fread_string(FILE *stream) return strdup(dname); } +/* reads a block of data into memory + * using the address in *data which is assumed to be able to contain *size + * if it needs more than *size bytes to store the data, *data is reallocated + * providing initial values of *data = NULL and *size = 0 will force it to + * allocate the required memory itself + * do not supply a statically or dynamically allocated buffer unless: + * - you can guarantee it is not smaller than the data + * - or realloc doesn't free old memory (though this will be a memory leak) + * - or your allocator does nothing when asked to free non-allocated memory + */ +int tbd_apply_fread_block(FILE *stream, void **data, unsigned int *size) +{ + { + unsigned int _size; + if (fread(&_size, sizeof(_size), 1, stream) != 1) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_READ_STREAM); + } + if (_size > *size) { + void *allocres = realloc(*data, _size); + if (allocres == NULL) { + return TBD_ERROR(TBD_ERROR_OUT_OF_MEMORY); + } + *data = allocres; + *size = _size; + } + } + + if (fread(*data, 1, *size, stream) != *size) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_READ_STREAM); + } + return TBD_ERROR_SUCCESS; +} + static int tbd_apply_identify(FILE *stream) { @@ -572,6 +608,58 @@ tbd_apply_cmd_file_mdata_update(FILE *stream) return TBD_ERROR_SUCCESS; } +static int tbd_apply_cmd_xattrs_update(FILE *stream) +{ + int err = TBD_ERROR_SUCCESS; + char *fname; + int count; + void *data = NULL; + size_t dsize = 0; + /* read the name of the file to operate on */ + if ((fname = tbd_apply_fread_string(stream)) == NULL) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_READ_STREAM); + } + + /* remove all attributes in preparation for adding new ones */ + if ((err = tbd_xattrs_removeall(fname)) != TBD_ERROR_SUCCESS) { + goto cleanup; + } + + /* read how many attributes to process */ + if (fread(&count, sizeof(count), 1, stream) != 1) { + err = TBD_ERROR(TBD_ERROR_UNABLE_TO_READ_STREAM); + goto cleanup; + } + + /* operate on each attribute */ + while (count > 0) { + char *aname = tbd_apply_fread_string(stream); + if (aname == NULL) { + err=TBD_ERROR(TBD_ERROR_UNABLE_TO_READ_STREAM); + goto cleanup; + } + + /* read a block of data, reallocating if needed */ + if ((err = tbd_apply_fread_block(stream, &data, &dsize)) + != TBD_ERROR_SUCCESS) { + free(aname); + goto cleanup; + } + + if (lsetxattr(fname, aname, data, dsize, 0) == -1) { + free(aname); + goto cleanup; + } + + count--; + free(aname); + } +cleanup: + free(data); + free(fname); + return err; +} + int tbd_apply(FILE *stream) { @@ -625,6 +713,12 @@ tbd_apply(FILE *stream) if((err = tbd_apply_cmd_file_mdata_update(stream)) != 0) return err; break; + case TBD_CMD_XATTRS_UPDATE: + if ((err = tbd_apply_cmd_xattrs_update(stream)) != + TBD_ERROR_SUCCESS) { + return err; + } + break; case TBD_CMD_ENTITY_MOVE: case TBD_CMD_ENTITY_COPY: return TBD_ERROR(TBD_ERROR_FEATURE_NOT_IMPLEMENTED); // TODO - Implement. diff --git a/libtbd_create.c b/libtbd_create.c index d6ef029..f1d886d 100644 --- a/libtbd_create.c +++ b/libtbd_create.c @@ -18,6 +18,7 @@ #include "tbdiff.h" #include "tbdiff-private.h" +#include "libtbd_xattrs.h" #include #include @@ -51,6 +52,19 @@ tbd_create_fwrite_string(FILE *stream, return 0; } +static int +tbd_create_fwrite_block(FILE *stream, void const *data, size_t size) +{ + if (fwrite(&size, sizeof(size), 1, stream) != 1) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_WRITE_STREAM); + } + + if (fwrite(data, size, 1, stream) != 1) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_WRITE_STREAM); + } + return TBD_ERROR_SUCCESS; +} + static int tbd_create_fwrite_mdata_mask(FILE *stream, uint16_t mask) @@ -123,6 +137,82 @@ tbd_create_cmd_update(FILE *stream) return tbd_create_fwrite_cmd(stream, TBD_CMD_UPDATE); } +/* callback function to pass to tbx_xattrs_pairs + * this will write the attribute name, then the data representing that block + */ +static int +_write_pair(char const *name, void const *data, size_t size, void *ud) +{ + FILE *stream = ud; + int err; + + if ((err = tbd_create_fwrite_string(stream, name)) != + TBD_ERROR_SUCCESS) { + return err; + } + + if ((err = tbd_create_fwrite_block(stream, data, size)) != + TBD_ERROR_SUCCESS) { + return err; + } + + return TBD_ERROR_SUCCESS; +} + +static int +tbd_create_cmd_fwrite_xattrs(FILE *stream, tbd_stat_t *f) +{ + int err = TBD_ERROR_SUCCESS; + tbd_xattrs_names_t names; + char *path = tbd_stat_path(f); + if (path == NULL) { + return TBD_ERROR(TBD_ERROR_OUT_OF_MEMORY); + } + + switch (err = tbd_xattrs_names(path, &names)) { + /* separated as ignore XATTR unspported may be added */ + case TBD_ERROR_XATTRS_NOT_SUPPORTED: + default: + goto cleanup_path; + case TBD_ERROR_SUCCESS: + break; + } + + { /* write the header */ + int count; + /* if failed to count or there are no xattrs */ + if ((err = tbd_xattrs_names_count(&names, &count)) != + TBD_ERROR_SUCCESS || count == 0) { + goto cleanup_names; + } + + if ((err = tbd_create_fwrite_cmd(stream, + TBD_CMD_XATTRS_UPDATE) + ) != TBD_ERROR_SUCCESS) { + goto cleanup_names; + } + + if ((err = tbd_create_fwrite_string(stream, f->name))!= + TBD_ERROR_SUCCESS) { + goto cleanup_names; + } + + if (fwrite(&count, sizeof(count), 1, stream) != 1) { + err = TBD_ERROR(TBD_ERROR_UNABLE_TO_WRITE_STREAM); + goto cleanup_names; + } + } + + /* write the name:data pairs */ + err = tbd_xattrs_pairs(&names, path, _write_pair, stream); + +cleanup_names: + tbd_xattrs_names_free(&names); +cleanup_path: + free(path); + return err; +} + static int tbd_create_cmd_file_create(FILE *stream, tbd_stat_t *f) @@ -155,7 +245,7 @@ tbd_create_cmd_file_create(FILE *stream, } fclose(fp); - return 0; + return tbd_create_cmd_fwrite_xattrs(stream, f); } static uint16_t @@ -297,10 +387,11 @@ tbd_create_cmd_file_delta(FILE *stream, uint32_t size = flenb - ((flena - end) + start); //(flenb - (o + start)); + /* Data is identical, only alter metadata */ if((end == start) && (size == 0)) { tbd_create_cmd_file_metadata_update(stream, a, b); fclose(fpb); - return 0; + return tbd_create_cmd_fwrite_xattrs(stream, b); } uint16_t metadata_mask = tbd_metadata_mask(a, b); @@ -341,7 +432,7 @@ tbd_create_cmd_file_delta(FILE *stream, } fclose(fpb); - return 0; + return tbd_create_cmd_fwrite_xattrs(stream, b); } static int diff --git a/tbdiff.h b/tbdiff.h index 2a4bcf6..893a0a5 100644 --- a/tbdiff.h +++ b/tbdiff.h @@ -38,6 +38,7 @@ typedef enum { TBD_CMD_ENTITY_DELETE = 0x32, TBD_CMD_SYMLINK_CREATE = 0x40, TBD_CMD_SPECIAL_CREATE = 0x50, + TBD_CMD_XATTRS_UPDATE = 0x60, } tbd_cmd_e; typedef enum { @@ -73,6 +74,8 @@ typedef enum { TBD_ERROR_UNABLE_TO_READ_SPECIAL_FILE = -20, TBD_ERROR_UNABLE_TO_CREATE_SPECIAL_FILE = -21, TBD_ERROR_UNABLE_TO_CREATE_SOCKET_FILE = -22, + TBD_ERROR_XATTRS_NOT_SUPPORTED = -23, + TBD_ERROR_XATTRS_MISSING_ATTR = -24, } tbd_error_e; #ifdef NDEBUG diff --git a/tbdiff_create.c b/tbdiff_create.c index 8bc68c7..88dd405 100644 --- a/tbdiff_create.c +++ b/tbdiff_create.c @@ -71,7 +71,10 @@ main(int argc, int err; if((err = tbd_create(fp, tstat[0], tstat[1])) != 0) { - fclose(fp); + fclose(fp); + tbd_stat_free(tstat[0]); + tbd_stat_free(tstat[1]); + remove(argv[1]); fprintf(stderr, "Error: Failed to create tbdiff image (err=%d).\n", err); switch (err) { diff --git a/tests/test_lib.sh b/tests/test_lib.sh index 85df52b..4185bed 100644 --- a/tests/test_lib.sh +++ b/tests/test_lib.sh @@ -41,6 +41,11 @@ check_group () { test $(stat -c %G $1) = $2 } +check_xattrs () { + test "`getfattr -d $1 2>/dev/null | tail -n +2`" = \ + "`getfattr -d $2 2>/dev/null | tail -n +2`" +} + # tests whether a command exists is_command () { type $1 >/dev/null 2>/dev/null @@ -88,13 +93,13 @@ start () { cleanup_and_exit fi - if [ ! -f $1 ] + if [ ! -f "$1" ] then echo "ERROR: $1 is an invalid tbdiff-create path" 1>&2 cleanup_and_exit fi - if [ ! -f $2 ] + if [ ! -f "$2" ] then echo "ERROR: $1 is an invalid tbdiff-deploy path" 1>&2 cleanup_and_exit @@ -109,7 +114,7 @@ command_succeeded () { test "$1" = "0" } main () { - start $@ + start "$@" echo -n "$TEST_ID Setting up $TEST_NAME test: " if [ ! -d $TESTDIR ] then -- cgit v1.2.1