summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2011-10-17 11:48:51 +0100
committerRichard Maw <richard.maw@codethink.co.uk>2011-10-17 11:48:51 +0100
commitfa85a17045e56479c0ec69a40a177c013f487291 (patch)
tree61aca0d795491059834f297d4901c372d5372426
parent30db9be89e11712d26bc46752d75c4cf86760bd7 (diff)
downloadtbdiff-fa85a17045e56479c0ec69a40a177c013f487291.tar.gz
Added xattr support
Fixed inconsequential memory leak in tbdiff_create.c Lost memory would be cleaned up by OS at exit, but valgrind complains
-rw-r--r--Makefile6
-rw-r--r--libtbd_apply.c94
-rw-r--r--libtbd_create.c97
-rw-r--r--tbdiff.h3
-rw-r--r--tbdiff_create.c5
-rw-r--r--tests/test_lib.sh11
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 <unistd.h>
#include <utime.h>
+#include <attr/xattr.h>
+#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 <stdlib.h>
#include <stdio.h>
@@ -52,6 +53,19 @@ tbd_create_fwrite_string(FILE *stream,
}
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