diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-06-07 23:38:06 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-06-09 06:04:08 +0200 | 
| commit | 1f210bab667a540379243050b5ce3465086e1124 (patch) | |
| tree | 2f3aafe42326cc47a6f5952d3e4bb980ce41e4a1 /lib | |
| parent | 04be64583149515f774bf01f03b1be6121649668 (diff) | |
Cleanup: split libsquashfs xattr writer code
This commit moves the libsquashfs xattr related code into a sub
directory and splits the xattr writer code up into several files.
No actual code is changed.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqfs/Makemodule.am | 11 | ||||
| -rw-r--r-- | lib/sqfs/xattr/xattr.c (renamed from lib/sqfs/xattr.c) | 0 | ||||
| -rw-r--r-- | lib/sqfs/xattr/xattr_reader.c (renamed from lib/sqfs/xattr_reader.c) | 0 | ||||
| -rw-r--r-- | lib/sqfs/xattr/xattr_writer.c | 110 | ||||
| -rw-r--r-- | lib/sqfs/xattr/xattr_writer.h | 63 | ||||
| -rw-r--r-- | lib/sqfs/xattr/xattr_writer_flush.c (renamed from lib/sqfs/xattr_writer.c) | 333 | ||||
| -rw-r--r-- | lib/sqfs/xattr/xattr_writer_record.c | 179 | 
7 files changed, 361 insertions, 335 deletions
| diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index 61c9b09..85f4aad 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -11,15 +11,18 @@ LIBSQFS_HEARDS = include/sqfs/meta_writer.h \  		include/sqfs/frag_table.h include/sqfs/block_writer.h  libsquashfs_la_SOURCES = $(LIBSQFS_HEARDS) lib/sqfs/id_table.c lib/sqfs/super.c -libsquashfs_la_SOURCES += lib/sqfs/readdir.c lib/sqfs/xattr.c +libsquashfs_la_SOURCES += lib/sqfs/readdir.c lib/sqfs/xattr/xattr.c  libsquashfs_la_SOURCES += lib/sqfs/write_table.c lib/sqfs/meta_writer.c  libsquashfs_la_SOURCES += lib/sqfs/read_super.c lib/sqfs/meta_reader.c  libsquashfs_la_SOURCES += lib/sqfs/read_inode.c lib/sqfs/write_inode.c -libsquashfs_la_SOURCES += lib/sqfs/dir_writer.c lib/sqfs/xattr_reader.c +libsquashfs_la_SOURCES += lib/sqfs/dir_writer.c lib/sqfs/xattr/xattr_reader.c  libsquashfs_la_SOURCES += lib/sqfs/read_table.c lib/sqfs/comp/compressor.c -libsquashfs_la_SOURCES += lib/sqfs/comp/internal.h lib/sqfs/xattr_writer.c +libsquashfs_la_SOURCES += lib/sqfs/comp/internal.h  libsquashfs_la_SOURCES += lib/sqfs/dir_reader.c lib/sqfs/read_tree.c -libsquashfs_la_SOURCES += lib/sqfs/inode.c +libsquashfs_la_SOURCES += lib/sqfs/inode.c lib/sqfs/xattr/xattr_writer.c +libsquashfs_la_SOURCES += lib/sqfs/xattr/xattr_writer_flush.c +libsquashfs_la_SOURCES += lib/sqfs/xattr/xattr_writer_record.c +libsquashfs_la_SOURCES += lib/sqfs/xattr/xattr_writer.h  libsquashfs_la_SOURCES += lib/sqfs/write_super.c lib/sqfs/data_reader.c  libsquashfs_la_SOURCES += lib/sqfs/block_processor/internal.h  libsquashfs_la_SOURCES += lib/sqfs/block_processor/common.c diff --git a/lib/sqfs/xattr.c b/lib/sqfs/xattr/xattr.c index 29ecebf..29ecebf 100644 --- a/lib/sqfs/xattr.c +++ b/lib/sqfs/xattr/xattr.c diff --git a/lib/sqfs/xattr_reader.c b/lib/sqfs/xattr/xattr_reader.c index 37f222a..37f222a 100644 --- a/lib/sqfs/xattr_reader.c +++ b/lib/sqfs/xattr/xattr_reader.c diff --git a/lib/sqfs/xattr/xattr_writer.c b/lib/sqfs/xattr/xattr_writer.c new file mode 100644 index 0000000..9de3823 --- /dev/null +++ b/lib/sqfs/xattr/xattr_writer.c @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * xattr_writer.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "xattr_writer.h" + +static sqfs_object_t *xattr_writer_copy(const sqfs_object_t *obj) +{ +	const sqfs_xattr_writer_t *xwr = (const sqfs_xattr_writer_t *)obj; +	kv_block_desc_t *blk, *it, **next; +	sqfs_xattr_writer_t *copy; + +	copy = calloc(1, sizeof(*copy)); +	if (copy == NULL) +		return NULL; + +	memcpy(copy, xwr, sizeof(*xwr)); + +	if (str_table_copy(©->keys, &xwr->keys)) +		goto fail_keys; + +	if (str_table_copy(©->values, &xwr->values)) +		goto fail_values; + +	copy->max_pairs = xwr->num_pairs; +	copy->num_pairs = xwr->num_pairs; + +	copy->kv_pairs = malloc(sizeof(copy->kv_pairs[0]) * xwr->num_pairs); +	if (copy->kv_pairs == NULL) +		goto fail_pairs; + +	memcpy(copy->kv_pairs, xwr->kv_pairs, +	       sizeof(copy->kv_pairs[0]) * xwr->num_pairs); + +	next = &(copy->kv_blocks); + +	for (it = xwr->kv_blocks; it != NULL; it = it->next) { +		blk = malloc(sizeof(*blk)); +		if (blk == NULL) +			goto fail_blk; + +		memcpy(blk, it, sizeof(*it)); +		blk->next = NULL; + +		*next = blk; +		next = &(blk->next); +	} + +	return (sqfs_object_t *)copy; +fail_blk: +	while (copy->kv_blocks != NULL) { +		blk = copy->kv_blocks; +		copy->kv_blocks = copy->kv_blocks->next; +		free(blk); +	} +fail_pairs: +	str_table_cleanup(©->values); +fail_values: +	str_table_cleanup(©->keys); +fail_keys: +	free(copy); +	return NULL; +} + +static void xattr_writer_destroy(sqfs_object_t *obj) +{ +	sqfs_xattr_writer_t *xwr = (sqfs_xattr_writer_t *)obj; +	kv_block_desc_t *blk; + +	while (xwr->kv_blocks != NULL) { +		blk = xwr->kv_blocks; +		xwr->kv_blocks = xwr->kv_blocks->next; +		free(blk); +	} + +	free(xwr->kv_pairs); +	str_table_cleanup(&xwr->values); +	str_table_cleanup(&xwr->keys); +	free(xwr); +} + +sqfs_xattr_writer_t *sqfs_xattr_writer_create(void) +{ +	sqfs_xattr_writer_t *xwr = calloc(1, sizeof(*xwr)); + +	if (str_table_init(&xwr->keys, XATTR_KEY_BUCKETS)) +		goto fail_keys; + +	if (str_table_init(&xwr->values, XATTR_VALUE_BUCKETS)) +		goto fail_values; + +	xwr->max_pairs = XATTR_INITIAL_PAIR_CAP; +	xwr->kv_pairs = alloc_array(sizeof(xwr->kv_pairs[0]), xwr->max_pairs); + +	if (xwr->kv_pairs == NULL) +		goto fail_pairs; + +	((sqfs_object_t *)xwr)->copy = xattr_writer_copy; +	((sqfs_object_t *)xwr)->destroy = xattr_writer_destroy; +	return xwr; +fail_pairs: +	str_table_cleanup(&xwr->values); +fail_values: +	str_table_cleanup(&xwr->keys); +fail_keys: +	free(xwr); +	return NULL; +} diff --git a/lib/sqfs/xattr/xattr_writer.h b/lib/sqfs/xattr/xattr_writer.h new file mode 100644 index 0000000..826b6f6 --- /dev/null +++ b/lib/sqfs/xattr/xattr_writer.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * xattr_writer.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef XATTR_WRITER_H +#define XATTR_WRITER_H + +#define SQFS_BUILDING_DLL +#include "config.h" + +#include "sqfs/xattr_writer.h" +#include "sqfs/meta_writer.h" +#include "sqfs/super.h" +#include "sqfs/xattr.h" +#include "sqfs/error.h" +#include "sqfs/block.h" +#include "sqfs/io.h" + +#include "str_table.h" +#include "util.h" + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + + +#define XATTR_KEY_BUCKETS 31 +#define XATTR_VALUE_BUCKETS 511 +#define XATTR_INITIAL_PAIR_CAP 128 + +#define MK_PAIR(key, value) (((sqfs_u64)(key) << 32UL) | (sqfs_u64)(value)) +#define GET_KEY(pair) ((pair >> 32UL) & 0x0FFFFFFFFUL) +#define GET_VALUE(pair) (pair & 0x0FFFFFFFFUL) + + +typedef struct kv_block_desc_t { +	struct kv_block_desc_t *next; +	size_t start; +	size_t count; + +	sqfs_u64 start_ref; +	size_t size_bytes; +} kv_block_desc_t; + +struct sqfs_xattr_writer_t { +	sqfs_object_t base; + +	str_table_t keys; +	str_table_t values; + +	sqfs_u64 *kv_pairs; +	size_t max_pairs; +	size_t num_pairs; + +	size_t kv_start; + +	kv_block_desc_t *kv_blocks; +	size_t num_blocks; +}; + +#endif /* XATTR_WRITER_H */ diff --git a/lib/sqfs/xattr_writer.c b/lib/sqfs/xattr/xattr_writer_flush.c index 488fd43..9b3de30 100644 --- a/lib/sqfs/xattr_writer.c +++ b/lib/sqfs/xattr/xattr_writer_flush.c @@ -1,60 +1,13 @@  /* SPDX-License-Identifier: LGPL-3.0-or-later */  /* - * xattr_writer.c + * xattr_writer_flush.c   *   * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>   */ -#define SQFS_BUILDING_DLL -#include "config.h" - -#include "sqfs/xattr_writer.h" -#include "sqfs/meta_writer.h" -#include "sqfs/super.h" -#include "sqfs/xattr.h" -#include "sqfs/error.h" -#include "sqfs/block.h" -#include "sqfs/io.h" - -#include "str_table.h" -#include "util.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - - -#define XATTR_KEY_BUCKETS 31 -#define XATTR_VALUE_BUCKETS 511 -#define XATTR_INITIAL_PAIR_CAP 128 - -#define MK_PAIR(key, value) (((sqfs_u64)(key) << 32UL) | (sqfs_u64)(value)) -#define GET_KEY(pair) ((pair >> 32UL) & 0x0FFFFFFFFUL) -#define GET_VALUE(pair) (pair & 0x0FFFFFFFFUL) - +#include "xattr_writer.h"  static const char *hexmap = "0123456789ABCDEF"; -static char *to_base32(const void *input, size_t size) -{ -	const sqfs_u8 *in = input; -	char *out, *ptr; -	size_t i; - -	out = malloc(2 * size + 1); -	if (out == NULL) -		return NULL; - -	ptr = out; - -	for (i = 0; i < size; ++i) { -		*(ptr++) = hexmap[ in[i]       & 0x0F]; -		*(ptr++) = hexmap[(in[i] >> 4) & 0x0F]; -	} - -	*ptr = '\0'; -	return out; -} -  static void *from_base32(const char *input, size_t *size_out)  {  	sqfs_u8 lo, hi, *out, *ptr; @@ -79,288 +32,6 @@ static void *from_base32(const char *input, size_t *size_out)  	return out;  } -static int compare_u64(const void *a, const void *b) -{ -	sqfs_u64 lhs = *((const sqfs_u64 *)a); -	sqfs_u64 rhs = *((const sqfs_u64 *)b); - -	return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0)); -} - - - -typedef struct kv_block_desc_t { -	struct kv_block_desc_t *next; -	size_t start; -	size_t count; - -	sqfs_u64 start_ref; -	size_t size_bytes; -} kv_block_desc_t; - -struct sqfs_xattr_writer_t { -	sqfs_object_t base; - -	str_table_t keys; -	str_table_t values; - -	sqfs_u64 *kv_pairs; -	size_t max_pairs; -	size_t num_pairs; - -	size_t kv_start; - -	kv_block_desc_t *kv_blocks; -	size_t num_blocks; -}; - - -static sqfs_object_t *xattr_writer_copy(const sqfs_object_t *obj) -{ -	const sqfs_xattr_writer_t *xwr = (const sqfs_xattr_writer_t *)obj; -	kv_block_desc_t *blk, *it, **next; -	sqfs_xattr_writer_t *copy; - -	copy = calloc(1, sizeof(*copy)); -	if (copy == NULL) -		return NULL; - -	memcpy(copy, xwr, sizeof(*xwr)); - -	if (str_table_copy(©->keys, &xwr->keys)) -		goto fail_keys; - -	if (str_table_copy(©->values, &xwr->values)) -		goto fail_values; - -	copy->max_pairs = xwr->num_pairs; -	copy->num_pairs = xwr->num_pairs; - -	copy->kv_pairs = malloc(sizeof(copy->kv_pairs[0]) * xwr->num_pairs); -	if (copy->kv_pairs == NULL) -		goto fail_pairs; - -	memcpy(copy->kv_pairs, xwr->kv_pairs, -	       sizeof(copy->kv_pairs[0]) * xwr->num_pairs); - -	next = &(copy->kv_blocks); - -	for (it = xwr->kv_blocks; it != NULL; it = it->next) { -		blk = malloc(sizeof(*blk)); -		if (blk == NULL) -			goto fail_blk; - -		memcpy(blk, it, sizeof(*it)); -		blk->next = NULL; - -		*next = blk; -		next = &(blk->next); -	} - -	return (sqfs_object_t *)copy; -fail_blk: -	while (copy->kv_blocks != NULL) { -		blk = copy->kv_blocks; -		copy->kv_blocks = copy->kv_blocks->next; -		free(blk); -	} -fail_pairs: -	str_table_cleanup(©->values); -fail_values: -	str_table_cleanup(©->keys); -fail_keys: -	free(copy); -	return NULL; -} - -static void xattr_writer_destroy(sqfs_object_t *obj) -{ -	sqfs_xattr_writer_t *xwr = (sqfs_xattr_writer_t *)obj; -	kv_block_desc_t *blk; - -	while (xwr->kv_blocks != NULL) { -		blk = xwr->kv_blocks; -		xwr->kv_blocks = xwr->kv_blocks->next; -		free(blk); -	} - -	free(xwr->kv_pairs); -	str_table_cleanup(&xwr->values); -	str_table_cleanup(&xwr->keys); -	free(xwr); -} - -sqfs_xattr_writer_t *sqfs_xattr_writer_create(void) -{ -	sqfs_xattr_writer_t *xwr = calloc(1, sizeof(*xwr)); - -	if (str_table_init(&xwr->keys, XATTR_KEY_BUCKETS)) -		goto fail_keys; - -	if (str_table_init(&xwr->values, XATTR_VALUE_BUCKETS)) -		goto fail_values; - -	xwr->max_pairs = XATTR_INITIAL_PAIR_CAP; -	xwr->kv_pairs = alloc_array(sizeof(xwr->kv_pairs[0]), xwr->max_pairs); - -	if (xwr->kv_pairs == NULL) -		goto fail_pairs; - -	((sqfs_object_t *)xwr)->copy = xattr_writer_copy; -	((sqfs_object_t *)xwr)->destroy = xattr_writer_destroy; -	return xwr; -fail_pairs: -	str_table_cleanup(&xwr->values); -fail_values: -	str_table_cleanup(&xwr->keys); -fail_keys: -	free(xwr); -	return NULL; -} - -int sqfs_xattr_writer_begin(sqfs_xattr_writer_t *xwr) -{ -	xwr->kv_start = xwr->num_pairs; -	return 0; -} - -int sqfs_xattr_writer_add(sqfs_xattr_writer_t *xwr, const char *key, -			  const void *value, size_t size) -{ -	size_t i, key_index, old_value_index, value_index, new_count; -	sqfs_u64 kv_pair, *new; -	char *value_str; -	int err; - -	if (sqfs_get_xattr_prefix_id(key) < 0) -		return SQFS_ERROR_UNSUPPORTED; - -	/* resolve key and value into unique, incremental IDs */ -	err = str_table_get_index(&xwr->keys, key, &key_index); -	if (err) -		return err; - -	value_str = to_base32(value, size); -	if (value_str == NULL) -		return SQFS_ERROR_ALLOC; - -	err = str_table_get_index(&xwr->values, value_str, &value_index); -	free(value_str); -	if (err) -		return err; - -	str_table_add_ref(&xwr->values, value_index); - -	if (sizeof(size_t) > sizeof(sqfs_u32)) { -		if (key_index > 0x0FFFFFFFFUL || value_index > 0x0FFFFFFFFUL) -			return SQFS_ERROR_OVERFLOW; -	} - -	/* bail if already have the pair, overwrite if we have the key */ -	kv_pair = MK_PAIR(key_index, value_index); - -	for (i = xwr->kv_start; i < xwr->num_pairs; ++i) { -		if (xwr->kv_pairs[i] == kv_pair) -			return 0; - -		if (GET_KEY(xwr->kv_pairs[i]) == key_index) { -			old_value_index = GET_VALUE(xwr->kv_pairs[i]); - -			str_table_del_ref(&xwr->values, old_value_index); - -			xwr->kv_pairs[i] = kv_pair; -			return 0; -		} -	} - -	/* append it to the list */ -	if (xwr->max_pairs == xwr->num_pairs) { -		new_count = xwr->max_pairs * 2; -		new = realloc(xwr->kv_pairs, -			      sizeof(xwr->kv_pairs[0]) * new_count); - -		if (new == NULL) -			return SQFS_ERROR_ALLOC; - -		xwr->kv_pairs = new; -		xwr->max_pairs = new_count; -	} - -	xwr->kv_pairs[xwr->num_pairs++] = kv_pair; -	return 0; -} - -int sqfs_xattr_writer_end(sqfs_xattr_writer_t *xwr, sqfs_u32 *out) -{ -	kv_block_desc_t *blk, *blk_prev; -	size_t i, count, value_idx; -	sqfs_u32 index; -	int ret; - -	count = xwr->num_pairs - xwr->kv_start; -	if (count == 0) { -		*out = 0xFFFFFFFF; -		return 0; -	} - -	qsort(xwr->kv_pairs + xwr->kv_start, count, -	      sizeof(xwr->kv_pairs[0]), compare_u64); - -	blk_prev = NULL; -	blk = xwr->kv_blocks; -	index = 0; - -	while (blk != NULL) { -		if (blk->count == count) { -			ret = memcmp(xwr->kv_pairs + blk->start, -				     xwr->kv_pairs + xwr->kv_start, -				     sizeof(xwr->kv_pairs[0]) * count); - -			if (ret == 0) -				break; -		} - -		if (index == 0xFFFFFFFF) -			return SQFS_ERROR_OVERFLOW; - -		++index; -		blk_prev = blk; -		blk = blk->next; -	} - -	if (blk != NULL) { -		for (i = 0; i < count; ++i) { -			value_idx = GET_VALUE(xwr->kv_pairs[xwr->kv_start + i]); -			str_table_del_ref(&xwr->values, value_idx); - -			value_idx = GET_VALUE(xwr->kv_pairs[blk->start + i]); -			str_table_add_ref(&xwr->values, value_idx); -		} - -		xwr->num_pairs = xwr->kv_start; -	} else { -		blk = calloc(1, sizeof(*blk)); -		if (blk == NULL) -			return SQFS_ERROR_ALLOC; - -		blk->start = xwr->kv_start; -		blk->count = count; - -		if (blk_prev == NULL) { -			xwr->kv_blocks = blk; -		} else { -			blk_prev->next = blk; -		} - -		xwr->num_blocks += 1; -	} - -	*out = index; -	return 0; -} - -/*****************************************************************************/ -  static sqfs_s32 write_key(sqfs_meta_writer_t *mw, const char *key,  			  bool value_is_ool)  { diff --git a/lib/sqfs/xattr/xattr_writer_record.c b/lib/sqfs/xattr/xattr_writer_record.c new file mode 100644 index 0000000..5e97868 --- /dev/null +++ b/lib/sqfs/xattr/xattr_writer_record.c @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * xattr_writer_record.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "xattr_writer.h" + +static const char *hexmap = "0123456789ABCDEF"; + +static char *to_base32(const void *input, size_t size) +{ +	const sqfs_u8 *in = input; +	char *out, *ptr; +	size_t i; + +	out = malloc(2 * size + 1); +	if (out == NULL) +		return NULL; + +	ptr = out; + +	for (i = 0; i < size; ++i) { +		*(ptr++) = hexmap[ in[i]       & 0x0F]; +		*(ptr++) = hexmap[(in[i] >> 4) & 0x0F]; +	} + +	*ptr = '\0'; +	return out; +} + +static int compare_u64(const void *a, const void *b) +{ +	sqfs_u64 lhs = *((const sqfs_u64 *)a); +	sqfs_u64 rhs = *((const sqfs_u64 *)b); + +	return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0)); +} + +int sqfs_xattr_writer_begin(sqfs_xattr_writer_t *xwr) +{ +	xwr->kv_start = xwr->num_pairs; +	return 0; +} + +int sqfs_xattr_writer_add(sqfs_xattr_writer_t *xwr, const char *key, +			  const void *value, size_t size) +{ +	size_t i, key_index, old_value_index, value_index, new_count; +	sqfs_u64 kv_pair, *new; +	char *value_str; +	int err; + +	if (sqfs_get_xattr_prefix_id(key) < 0) +		return SQFS_ERROR_UNSUPPORTED; + +	/* resolve key and value into unique, incremental IDs */ +	err = str_table_get_index(&xwr->keys, key, &key_index); +	if (err) +		return err; + +	value_str = to_base32(value, size); +	if (value_str == NULL) +		return SQFS_ERROR_ALLOC; + +	err = str_table_get_index(&xwr->values, value_str, &value_index); +	free(value_str); +	if (err) +		return err; + +	str_table_add_ref(&xwr->values, value_index); + +	if (sizeof(size_t) > sizeof(sqfs_u32)) { +		if (key_index > 0x0FFFFFFFFUL || value_index > 0x0FFFFFFFFUL) +			return SQFS_ERROR_OVERFLOW; +	} + +	/* bail if already have the pair, overwrite if we have the key */ +	kv_pair = MK_PAIR(key_index, value_index); + +	for (i = xwr->kv_start; i < xwr->num_pairs; ++i) { +		if (xwr->kv_pairs[i] == kv_pair) +			return 0; + +		if (GET_KEY(xwr->kv_pairs[i]) == key_index) { +			old_value_index = GET_VALUE(xwr->kv_pairs[i]); + +			str_table_del_ref(&xwr->values, old_value_index); + +			xwr->kv_pairs[i] = kv_pair; +			return 0; +		} +	} + +	/* append it to the list */ +	if (xwr->max_pairs == xwr->num_pairs) { +		new_count = xwr->max_pairs * 2; +		new = realloc(xwr->kv_pairs, +			      sizeof(xwr->kv_pairs[0]) * new_count); + +		if (new == NULL) +			return SQFS_ERROR_ALLOC; + +		xwr->kv_pairs = new; +		xwr->max_pairs = new_count; +	} + +	xwr->kv_pairs[xwr->num_pairs++] = kv_pair; +	return 0; +} + +int sqfs_xattr_writer_end(sqfs_xattr_writer_t *xwr, sqfs_u32 *out) +{ +	kv_block_desc_t *blk, *blk_prev; +	size_t i, count, value_idx; +	sqfs_u32 index; +	int ret; + +	count = xwr->num_pairs - xwr->kv_start; +	if (count == 0) { +		*out = 0xFFFFFFFF; +		return 0; +	} + +	qsort(xwr->kv_pairs + xwr->kv_start, count, +	      sizeof(xwr->kv_pairs[0]), compare_u64); + +	blk_prev = NULL; +	blk = xwr->kv_blocks; +	index = 0; + +	while (blk != NULL) { +		if (blk->count == count) { +			ret = memcmp(xwr->kv_pairs + blk->start, +				     xwr->kv_pairs + xwr->kv_start, +				     sizeof(xwr->kv_pairs[0]) * count); + +			if (ret == 0) +				break; +		} + +		if (index == 0xFFFFFFFF) +			return SQFS_ERROR_OVERFLOW; + +		++index; +		blk_prev = blk; +		blk = blk->next; +	} + +	if (blk != NULL) { +		for (i = 0; i < count; ++i) { +			value_idx = GET_VALUE(xwr->kv_pairs[xwr->kv_start + i]); +			str_table_del_ref(&xwr->values, value_idx); + +			value_idx = GET_VALUE(xwr->kv_pairs[blk->start + i]); +			str_table_add_ref(&xwr->values, value_idx); +		} + +		xwr->num_pairs = xwr->kv_start; +	} else { +		blk = calloc(1, sizeof(*blk)); +		if (blk == NULL) +			return SQFS_ERROR_ALLOC; + +		blk->start = xwr->kv_start; +		blk->count = count; + +		if (blk_prev == NULL) { +			xwr->kv_blocks = blk; +		} else { +			blk_prev->next = blk; +		} + +		xwr->num_blocks += 1; +	} + +	*out = index; +	return 0; +} | 
