summaryrefslogtreecommitdiff
path: root/lib/sqfs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqfs')
-rw-r--r--lib/sqfs/block_processor/winpthread.c2
-rw-r--r--lib/sqfs/comp/gzip.c6
-rw-r--r--lib/sqfs/comp/lz4.c6
-rw-r--r--lib/sqfs/comp/lzma.c6
-rw-r--r--lib/sqfs/comp/xz.c6
-rw-r--r--lib/sqfs/comp/zstd.c6
-rw-r--r--lib/sqfs/data_reader.c46
-rw-r--r--lib/sqfs/dir_reader.c27
-rw-r--r--lib/sqfs/frag_table.c39
-rw-r--r--lib/sqfs/id_table.c25
-rw-r--r--lib/sqfs/meta_reader.c15
-rw-r--r--lib/sqfs/unix/io_file.c33
-rw-r--r--lib/sqfs/win32/io_file.c33
-rw-r--r--lib/sqfs/xattr_reader.c45
-rw-r--r--lib/sqfs/xattr_writer.c59
15 files changed, 338 insertions, 16 deletions
diff --git a/lib/sqfs/block_processor/winpthread.c b/lib/sqfs/block_processor/winpthread.c
index 47f4e35..1aa77e7 100644
--- a/lib/sqfs/block_processor/winpthread.c
+++ b/lib/sqfs/block_processor/winpthread.c
@@ -232,7 +232,7 @@ static thread_pool_processor_t *block_processor_create(size_t max_block_size,
goto fail;
proc->workers[i]->shared = proc;
- proc->workers[i]->cmp = cmp->create_copy(cmp);
+ proc->workers[i]->cmp = sqfs_copy(cmp);
if (proc->workers[i]->cmp == NULL)
goto fail;
diff --git a/lib/sqfs/comp/gzip.c b/lib/sqfs/comp/gzip.c
index 34164a6..351d733 100644
--- a/lib/sqfs/comp/gzip.c
+++ b/lib/sqfs/comp/gzip.c
@@ -221,7 +221,7 @@ static sqfs_s32 gzip_do_block(sqfs_compressor_t *base, const sqfs_u8 *in,
return 0;
}
-static sqfs_compressor_t *gzip_create_copy(sqfs_compressor_t *cmp)
+static sqfs_object_t *gzip_create_copy(const sqfs_object_t *cmp)
{
gzip_compressor_t *gzip = malloc(sizeof(*gzip));
int ret;
@@ -244,7 +244,7 @@ static sqfs_compressor_t *gzip_create_copy(sqfs_compressor_t *cmp)
return NULL;
}
- return (sqfs_compressor_t *)gzip;
+ return (sqfs_object_t *)gzip;
}
sqfs_compressor_t *gzip_compressor_create(const sqfs_compressor_config_t *cfg)
@@ -283,7 +283,7 @@ sqfs_compressor_t *gzip_compressor_create(const sqfs_compressor_config_t *cfg)
base->do_block = gzip_do_block;
base->write_options = gzip_write_options;
base->read_options = gzip_read_options;
- base->create_copy = gzip_create_copy;
+ ((sqfs_object_t *)base)->copy = gzip_create_copy;
((sqfs_object_t *)base)->destroy = gzip_destroy;
if (gzip->compress) {
diff --git a/lib/sqfs/comp/lz4.c b/lib/sqfs/comp/lz4.c
index f298c67..460ac44 100644
--- a/lib/sqfs/comp/lz4.c
+++ b/lib/sqfs/comp/lz4.c
@@ -116,7 +116,7 @@ static void lz4_get_configuration(const sqfs_compressor_t *base,
cfg->flags |= SQFS_COMP_FLAG_UNCOMPRESS;
}
-static sqfs_compressor_t *lz4_create_copy(sqfs_compressor_t *cmp)
+static sqfs_object_t *lz4_create_copy(const sqfs_object_t *cmp)
{
lz4_compressor_t *lz4 = malloc(sizeof(*lz4));
@@ -124,7 +124,7 @@ static sqfs_compressor_t *lz4_create_copy(sqfs_compressor_t *cmp)
return NULL;
memcpy(lz4, cmp, sizeof(*lz4));
- return (sqfs_compressor_t *)lz4;
+ return (sqfs_object_t *)lz4;
}
static void lz4_destroy(sqfs_object_t *base)
@@ -155,7 +155,7 @@ sqfs_compressor_t *lz4_compressor_create(const sqfs_compressor_config_t *cfg)
lz4_uncomp_block : lz4_comp_block;
base->write_options = lz4_write_options;
base->read_options = lz4_read_options;
- base->create_copy = lz4_create_copy;
+ ((sqfs_object_t *)base)->copy = lz4_create_copy;
((sqfs_object_t *)base)->destroy = lz4_destroy;
return base;
}
diff --git a/lib/sqfs/comp/lzma.c b/lib/sqfs/comp/lzma.c
index 451a6ca..51afe65 100644
--- a/lib/sqfs/comp/lzma.c
+++ b/lib/sqfs/comp/lzma.c
@@ -156,14 +156,14 @@ static void lzma_get_configuration(const sqfs_compressor_t *base,
cfg->flags |= SQFS_COMP_FLAG_UNCOMPRESS;
}
-static sqfs_compressor_t *lzma_create_copy(sqfs_compressor_t *cmp)
+static sqfs_object_t *lzma_create_copy(const sqfs_object_t *cmp)
{
lzma_compressor_t *copy = malloc(sizeof(*copy));
if (copy != NULL)
memcpy(copy, cmp, sizeof(*copy));
- return (sqfs_compressor_t *)copy;
+ return (sqfs_object_t *)copy;
}
static void lzma_destroy(sqfs_object_t *base)
@@ -194,7 +194,7 @@ sqfs_compressor_t *lzma_compressor_create(const sqfs_compressor_config_t *cfg)
lzma_uncomp_block : lzma_comp_block;
base->write_options = lzma_write_options;
base->read_options = lzma_read_options;
- base->create_copy = lzma_create_copy;
+ ((sqfs_object_t *)base)->copy = lzma_create_copy;
((sqfs_object_t *)base)->destroy = lzma_destroy;
return base;
}
diff --git a/lib/sqfs/comp/xz.c b/lib/sqfs/comp/xz.c
index a600956..423604b 100644
--- a/lib/sqfs/comp/xz.c
+++ b/lib/sqfs/comp/xz.c
@@ -211,7 +211,7 @@ static void xz_get_configuration(const sqfs_compressor_t *base,
cfg->flags |= SQFS_COMP_FLAG_UNCOMPRESS;
}
-static sqfs_compressor_t *xz_create_copy(sqfs_compressor_t *cmp)
+static sqfs_object_t *xz_create_copy(const sqfs_object_t *cmp)
{
xz_compressor_t *xz = malloc(sizeof(*xz));
@@ -219,7 +219,7 @@ static sqfs_compressor_t *xz_create_copy(sqfs_compressor_t *cmp)
return NULL;
memcpy(xz, cmp, sizeof(*xz));
- return (sqfs_compressor_t *)xz;
+ return (sqfs_object_t *)xz;
}
static void xz_destroy(sqfs_object_t *base)
@@ -253,7 +253,7 @@ sqfs_compressor_t *xz_compressor_create(const sqfs_compressor_config_t *cfg)
xz_uncomp_block : xz_comp_block;
base->write_options = xz_write_options;
base->read_options = xz_read_options;
- base->create_copy = xz_create_copy;
+ ((sqfs_object_t *)base)->copy = xz_create_copy;
((sqfs_object_t *)base)->destroy = xz_destroy;
return base;
}
diff --git a/lib/sqfs/comp/zstd.c b/lib/sqfs/comp/zstd.c
index e01f87d..12ddfdb 100644
--- a/lib/sqfs/comp/zstd.c
+++ b/lib/sqfs/comp/zstd.c
@@ -107,7 +107,7 @@ static void zstd_get_configuration(const sqfs_compressor_t *base,
cfg->flags |= SQFS_COMP_FLAG_UNCOMPRESS;
}
-static sqfs_compressor_t *zstd_create_copy(sqfs_compressor_t *cmp)
+static sqfs_object_t *zstd_create_copy(const sqfs_object_t *cmp)
{
zstd_compressor_t *zstd = malloc(sizeof(*zstd));
@@ -123,7 +123,7 @@ static sqfs_compressor_t *zstd_create_copy(sqfs_compressor_t *cmp)
return NULL;
}
- return (sqfs_compressor_t *)zstd;
+ return (sqfs_object_t *)zstd;
}
static void zstd_destroy(sqfs_object_t *base)
@@ -164,7 +164,7 @@ sqfs_compressor_t *zstd_compressor_create(const sqfs_compressor_config_t *cfg)
zstd_uncomp_block : zstd_comp_block;
base->write_options = zstd_write_options;
base->read_options = zstd_read_options;
- base->create_copy = zstd_create_copy;
+ ((sqfs_object_t *)base)->copy = zstd_create_copy;
((sqfs_object_t *)base)->destroy = zstd_destroy;
return base;
}
diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c
index 5e985e0..cd9ad68 100644
--- a/lib/sqfs/data_reader.c
+++ b/lib/sqfs/data_reader.c
@@ -137,6 +137,51 @@ static void data_reader_destroy(sqfs_object_t *obj)
free(data);
}
+static sqfs_object_t *data_reader_copy(const sqfs_object_t *obj)
+{
+ const sqfs_data_reader_t *data = (const sqfs_data_reader_t *)obj;
+ sqfs_data_reader_t *copy;
+
+ copy = alloc_flex(sizeof(*data), 1, data->block_size);
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, data, sizeof(*data) + data->block_size);
+
+ copy->frag_tbl = sqfs_copy(data->frag_tbl);
+ if (copy->frag_tbl == NULL)
+ goto fail_ftbl;
+
+ if (data->data_block != NULL) {
+ copy->data_block = malloc(data->data_blk_size);
+ if (copy->data_block == NULL)
+ goto fail_dblk;
+
+ memcpy(copy->data_block, data->data_block,
+ data->data_blk_size);
+ }
+
+ if (copy->frag_block != NULL) {
+ copy->frag_block = malloc(copy->frag_blk_size);
+ if (copy->frag_block == NULL)
+ goto fail_fblk;
+
+ memcpy(copy->frag_block, data->frag_block,
+ data->frag_blk_size);
+ }
+
+ /* XXX: file and cmp aren't deep-copied becaues data
+ doesn't own them either. */
+ return (sqfs_object_t *)copy;
+fail_fblk:
+ free(copy->data_block);
+fail_dblk:
+ sqfs_destroy(copy->frag_tbl);
+fail_ftbl:
+ free(copy);
+ return NULL;
+}
+
sqfs_data_reader_t *sqfs_data_reader_create(sqfs_file_t *file,
size_t block_size,
sqfs_compressor_t *cmp)
@@ -153,6 +198,7 @@ sqfs_data_reader_t *sqfs_data_reader_create(sqfs_file_t *file,
}
((sqfs_object_t *)data)->destroy = data_reader_destroy;
+ ((sqfs_object_t *)data)->copy = data_reader_copy;
data->file = file;
data->block_size = block_size;
data->cmp = cmp;
diff --git a/lib/sqfs/dir_reader.c b/lib/sqfs/dir_reader.c
index 4e2a5b8..8e23ddb 100644
--- a/lib/sqfs/dir_reader.c
+++ b/lib/sqfs/dir_reader.c
@@ -45,6 +45,32 @@ static void dir_reader_destroy(sqfs_object_t *obj)
free(rd);
}
+static sqfs_object_t *dir_reader_copy(const sqfs_object_t *obj)
+{
+ const sqfs_dir_reader_t *rd = (const sqfs_dir_reader_t *)obj;
+ sqfs_dir_reader_t *copy = malloc(sizeof(*copy));
+
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, rd, sizeof(*copy));
+
+ copy->meta_inode = sqfs_copy(rd->meta_inode);
+ if (copy->meta_inode == NULL)
+ goto fail_mino;
+
+ copy->meta_dir = sqfs_copy(rd->meta_dir);
+ if (copy->meta_dir == NULL)
+ goto fail_mdir;
+
+ return (sqfs_object_t *)copy;
+fail_mdir:
+ sqfs_destroy(copy->meta_inode);
+fail_mino:
+ free(copy);
+ return NULL;
+}
+
sqfs_dir_reader_t *sqfs_dir_reader_create(const sqfs_super_t *super,
sqfs_compressor_t *cmp,
sqfs_file_t *file)
@@ -83,6 +109,7 @@ sqfs_dir_reader_t *sqfs_dir_reader_create(const sqfs_super_t *super,
}
((sqfs_object_t *)rd)->destroy = dir_reader_destroy;
+ ((sqfs_object_t *)rd)->copy = dir_reader_copy;
rd->super = super;
return rd;
}
diff --git a/lib/sqfs/frag_table.c b/lib/sqfs/frag_table.c
index bf1c109..51164e6 100644
--- a/lib/sqfs/frag_table.c
+++ b/lib/sqfs/frag_table.c
@@ -58,6 +58,44 @@ static void frag_table_destroy(sqfs_object_t *obj)
free(tbl);
}
+static sqfs_object_t *frag_table_copy(const sqfs_object_t *obj)
+{
+ const sqfs_frag_table_t *tbl = (const sqfs_frag_table_t *)obj;
+ sqfs_frag_table_t *copy;
+ const chunk_info_t *it;
+ chunk_info_t *last;
+ size_t i;
+
+ copy = malloc(sizeof(*copy));
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, tbl, sizeof(*tbl));
+ for (i = 0; i < NUM_BUCKETS; ++i)
+ copy->chunks[i].next = NULL;
+
+ for (i = 0; i < NUM_BUCKETS; ++i) {
+ last = &(copy->chunks[i]);
+ it = tbl->chunks[i].next;
+
+ while (it != NULL) {
+ last->next = malloc(sizeof(*it));
+ if (last->next == NULL)
+ goto fail;
+
+ memcpy(last->next, it, sizeof(*it));
+ last = last->next;
+ last->next = NULL;
+ it = it->next;
+ }
+ }
+
+ return (sqfs_object_t *)copy;
+fail:
+ frag_table_destroy((sqfs_object_t *)copy);
+ return NULL;
+}
+
sqfs_frag_table_t *sqfs_frag_table_create(sqfs_u32 flags)
{
sqfs_frag_table_t *tbl;
@@ -69,6 +107,7 @@ sqfs_frag_table_t *sqfs_frag_table_create(sqfs_u32 flags)
if (tbl == NULL)
return NULL;
+ ((sqfs_object_t *)tbl)->copy = frag_table_copy;
((sqfs_object_t *)tbl)->destroy = frag_table_destroy;
return tbl;
}
diff --git a/lib/sqfs/id_table.c b/lib/sqfs/id_table.c
index 86f2809..e3d386e 100644
--- a/lib/sqfs/id_table.c
+++ b/lib/sqfs/id_table.c
@@ -32,6 +32,30 @@ static void id_table_destroy(sqfs_object_t *obj)
free(tbl);
}
+static sqfs_object_t *id_table_copy(const sqfs_object_t *obj)
+{
+ const sqfs_id_table_t *tbl = (const sqfs_id_table_t *)obj;
+ sqfs_id_table_t *copy;
+
+ copy = malloc(sizeof(*copy));
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, tbl, sizeof(*tbl));
+
+ copy->num_ids = tbl->num_ids;
+ copy->max_ids = tbl->num_ids;
+ copy->ids = malloc(tbl->num_ids * sizeof(tbl->ids[0]));
+
+ if (copy->ids == NULL) {
+ free(copy);
+ return NULL;
+ }
+
+ memcpy(copy->ids, tbl->ids, tbl->num_ids * sizeof(tbl->ids[0]));
+ return (sqfs_object_t *)copy;
+}
+
sqfs_id_table_t *sqfs_id_table_create(sqfs_u32 flags)
{
sqfs_id_table_t *tbl;
@@ -43,6 +67,7 @@ sqfs_id_table_t *sqfs_id_table_create(sqfs_u32 flags)
if (tbl != NULL) {
((sqfs_object_t *)tbl)->destroy = id_table_destroy;
+ ((sqfs_object_t *)tbl)->copy = id_table_copy;
}
return tbl;
diff --git a/lib/sqfs/meta_reader.c b/lib/sqfs/meta_reader.c
index 8fd7f21..b16b115 100644
--- a/lib/sqfs/meta_reader.c
+++ b/lib/sqfs/meta_reader.c
@@ -51,6 +51,20 @@ static void meta_reader_destroy(sqfs_object_t *m)
free(m);
}
+static sqfs_object_t *meta_reader_copy(const sqfs_object_t *obj)
+{
+ const sqfs_meta_reader_t *m = (const sqfs_meta_reader_t *)obj;
+ sqfs_meta_reader_t *copy = malloc(sizeof(*copy));
+
+ if (copy != NULL) {
+ memcpy(copy, m, sizeof(*m));
+ }
+
+ /* XXX: cmp and file aren't deep-copied because m
+ doesn't own them either. */
+ return (sqfs_object_t *)copy;
+}
+
sqfs_meta_reader_t *sqfs_meta_reader_create(sqfs_file_t *file,
sqfs_compressor_t *cmp,
sqfs_u64 start, sqfs_u64 limit)
@@ -60,6 +74,7 @@ sqfs_meta_reader_t *sqfs_meta_reader_create(sqfs_file_t *file,
if (m == NULL)
return NULL;
+ ((sqfs_object_t *)m)->copy = meta_reader_copy;
((sqfs_object_t *)m)->destroy = meta_reader_destroy;
m->start = start;
m->limit = limit;
diff --git a/lib/sqfs/unix/io_file.c b/lib/sqfs/unix/io_file.c
index 1c181ab..52fc94b 100644
--- a/lib/sqfs/unix/io_file.c
+++ b/lib/sqfs/unix/io_file.c
@@ -13,6 +13,7 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <errno.h>
#include <fcntl.h>
@@ -20,6 +21,7 @@
typedef struct {
sqfs_file_t base;
+ bool readonly;
sqfs_u64 size;
int fd;
} sqfs_file_stdio_t;
@@ -33,6 +35,34 @@ static void stdio_destroy(sqfs_object_t *base)
free(file);
}
+static sqfs_object_t *stdio_copy(const sqfs_object_t *base)
+{
+ const sqfs_file_stdio_t *file = (const sqfs_file_stdio_t *)base;
+ sqfs_file_stdio_t *copy;
+ int err;
+
+ if (!file->readonly) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+
+ copy = calloc(1, sizeof(*copy));
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, file, sizeof(*file));
+
+ copy->fd = dup(file->fd);
+ if (copy->fd < 0) {
+ err = errno;
+ free(copy);
+ copy = NULL;
+ errno = err;
+ }
+
+ return (sqfs_object_t *)copy;
+}
+
static int stdio_read_at(sqfs_file_t *base, sqfs_u64 offset,
void *buffer, size_t size)
{
@@ -125,8 +155,10 @@ sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags)
return NULL;
if (flags & SQFS_FILE_OPEN_READ_ONLY) {
+ file->readonly = true;
open_mode = O_RDONLY;
} else {
+ file->readonly = false;
open_mode = O_CREAT | O_RDWR;
if (flags & SQFS_FILE_OPEN_OVERWRITE) {
@@ -158,6 +190,7 @@ sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags)
base->write_at = stdio_write_at;
base->get_size = stdio_get_size;
base->truncate = stdio_truncate;
+ ((sqfs_object_t *)base)->copy = stdio_copy;
((sqfs_object_t *)base)->destroy = stdio_destroy;
return base;
}
diff --git a/lib/sqfs/win32/io_file.c b/lib/sqfs/win32/io_file.c
index c1849a8..836aa37 100644
--- a/lib/sqfs/win32/io_file.c
+++ b/lib/sqfs/win32/io_file.c
@@ -19,6 +19,7 @@
typedef struct {
sqfs_file_t base;
+ bool readonly;
sqfs_u64 size;
HANDLE fd;
} sqfs_file_stdio_t;
@@ -32,6 +33,35 @@ static void stdio_destroy(sqfs_object_t *base)
free(file);
}
+static sqfs_object_t *stdio_copy(const sqfs_object_t *base)
+{
+ const sqfs_file_stdio_t *file = (const sqfs_file_stdio_t *)base;
+ sqfs_file_stdio_t *copy;
+ BOOL ret;
+
+ if (!file->readonly) {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return NULL;
+ }
+
+ copy = calloc(1, sizeof(*copy));
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, file, sizeof(*file));
+
+ ret = DuplicateHandle(GetCurrentProcess(), file->fd,
+ GetCurrentProcess(), &copy->fd,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+
+ if (!ret) {
+ free(copy);
+ return NULL;
+ }
+
+ return (sqfs_object_t *)copy;
+}
+
static int stdio_read_at(sqfs_file_t *base, sqfs_u64 offset,
void *buffer, size_t size)
{
@@ -135,9 +165,11 @@ sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags)
return NULL;
if (flags & SQFS_FILE_OPEN_READ_ONLY) {
+ file->readonly = true;
access_flags = GENERIC_READ;
creation_mode = OPEN_EXISTING;
} else {
+ file->readonly = false;
access_flags = GENERIC_READ | GENERIC_WRITE;
if (flags & SQFS_FILE_OPEN_OVERWRITE) {
@@ -166,5 +198,6 @@ sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags)
base->get_size = stdio_get_size;
base->truncate = stdio_truncate;
((sqfs_object_t *)base)->destroy = stdio_destroy;
+ ((sqfs_object_t *)base)->copy = stdio_copy;
return base;
}
diff --git a/lib/sqfs/xattr_reader.c b/lib/sqfs/xattr_reader.c
index 97cf821..1469a90 100644
--- a/lib/sqfs/xattr_reader.c
+++ b/lib/sqfs/xattr_reader.c
@@ -36,6 +36,50 @@ struct sqfs_xattr_reader_t {
sqfs_file_t *file;
};
+static sqfs_object_t *xattr_reader_copy(const sqfs_object_t *obj)
+{
+ const sqfs_xattr_reader_t *xr = (const sqfs_xattr_reader_t *)obj;
+ sqfs_xattr_reader_t *copy = malloc(sizeof(*copy));
+
+ if (copy == NULL)
+ return NULL;
+
+ memcpy(copy, xr, sizeof(*xr));
+
+ if (xr->kvrd != NULL) {
+ copy->kvrd = sqfs_copy(xr->kvrd);
+ if (copy->kvrd == NULL)
+ goto fail_kvrd;
+ }
+
+ if (xr->idrd != NULL) {
+ copy->idrd = sqfs_copy(xr->idrd);
+ if (copy->idrd == NULL)
+ goto fail_idrd;
+ }
+
+ if (xr->id_block_starts != NULL) {
+ copy->id_block_starts = alloc_array(sizeof(sqfs_u64),
+ xr->num_id_blocks);
+ if (copy->id_block_starts == NULL)
+ goto fail_idblk;
+
+ memcpy(copy->id_block_starts, xr->id_block_starts,
+ sizeof(sqfs_u64) * xr->num_id_blocks);
+ }
+
+ return (sqfs_object_t *)copy;
+fail_idblk:
+ if (copy->idrd != NULL)
+ sqfs_destroy(copy->idrd);
+fail_idrd:
+ if (copy->kvrd != NULL)
+ sqfs_destroy(copy->kvrd);
+fail_kvrd:
+ free(copy);
+ return NULL;
+}
+
static void xattr_reader_destroy(sqfs_object_t *obj)
{
sqfs_xattr_reader_t *xr = (sqfs_xattr_reader_t *)obj;
@@ -267,6 +311,7 @@ sqfs_xattr_reader_t *sqfs_xattr_reader_create(sqfs_file_t *file,
if (xr == NULL)
return NULL;
+ ((sqfs_object_t *)xr)->copy = xattr_reader_copy;
((sqfs_object_t *)xr)->destroy = xattr_reader_destroy;
xr->file = file;
xr->super = super;
diff --git a/lib/sqfs/xattr_writer.c b/lib/sqfs/xattr_writer.c
index 827d0c5..488fd43 100644
--- a/lib/sqfs/xattr_writer.c
+++ b/lib/sqfs/xattr_writer.c
@@ -115,6 +115,64 @@ struct sqfs_xattr_writer_t {
};
+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(&copy->keys, &xwr->keys))
+ goto fail_keys;
+
+ if (str_table_copy(&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(&copy->values);
+fail_values:
+ str_table_cleanup(&copy->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;
@@ -148,6 +206,7 @@ sqfs_xattr_writer_t *sqfs_xattr_writer_create(void)
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: