From 44c81eeffe9c8820b1009a7a5c728782aa5ebf40 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Tue, 3 Mar 2020 19:43:54 +0100 Subject: Add a generic copying mechanism to sqfs_object_t This patch adds a deep-copy callback to sqfs_object_t and removes the copying mechanism from sqfs_compressor_t. This is also interesting for other types. Signed-off-by: David Oberhollenzer --- include/sqfs/block_processor.h | 2 ++ include/sqfs/block_writer.h | 2 ++ include/sqfs/compressor.h | 9 ------ include/sqfs/dir_writer.h | 2 ++ include/sqfs/io.h | 5 +++ include/sqfs/meta_writer.h | 2 ++ include/sqfs/predef.h | 20 ++++++++++++ lib/common/comp_lzo.c | 6 ++-- lib/sqfs/block_processor/winpthread.c | 2 +- lib/sqfs/comp/gzip.c | 6 ++-- lib/sqfs/comp/lz4.c | 6 ++-- lib/sqfs/comp/lzma.c | 6 ++-- lib/sqfs/comp/xz.c | 6 ++-- lib/sqfs/comp/zstd.c | 6 ++-- lib/sqfs/data_reader.c | 46 +++++++++++++++++++++++++++ lib/sqfs/dir_reader.c | 27 ++++++++++++++++ lib/sqfs/frag_table.c | 39 +++++++++++++++++++++++ lib/sqfs/id_table.c | 25 +++++++++++++++ lib/sqfs/meta_reader.c | 15 +++++++++ lib/sqfs/unix/io_file.c | 33 ++++++++++++++++++++ lib/sqfs/win32/io_file.c | 33 ++++++++++++++++++++ lib/sqfs/xattr_reader.c | 45 ++++++++++++++++++++++++++ lib/sqfs/xattr_writer.c | 59 +++++++++++++++++++++++++++++++++++ 23 files changed, 374 insertions(+), 28 deletions(-) diff --git a/include/sqfs/block_processor.h b/include/sqfs/block_processor.h index 2ad12c0..d3b6e12 100644 --- a/include/sqfs/block_processor.h +++ b/include/sqfs/block_processor.h @@ -43,6 +43,8 @@ * Internally it takes care of partitioning data in the correct block sizes, * adding tail-ens to fragment blocks, compressing the data, deduplicating data * and finally writing it to disk. + * + * This object is not copyable, i.e. @ref sqfs_copy will always return NULL. */ /** diff --git a/include/sqfs/block_writer.h b/include/sqfs/block_writer.h index bd1ddfc..674c0e7 100644 --- a/include/sqfs/block_writer.h +++ b/include/sqfs/block_writer.h @@ -34,6 +34,8 @@ * @implements sqfs_object_t * * @brief Abstracts writing and deduplicating of data and fragment blocks. + * + * This object is not copyable, i.e. @ref sqfs_copy will always return NULL. */ /** diff --git a/include/sqfs/compressor.h b/include/sqfs/compressor.h index 4292712..9a3508a 100644 --- a/include/sqfs/compressor.h +++ b/include/sqfs/compressor.h @@ -91,15 +91,6 @@ struct sqfs_compressor_t { */ sqfs_s32 (*do_block)(sqfs_compressor_t *cmp, const sqfs_u8 *in, sqfs_u32 size, sqfs_u8 *out, sqfs_u32 outsize); - - /** - * @brief Create an exact copt of agiven compressor - * - * @param cmp A pointer to a compressor object. - * - * @return A deep copy of the given compressor. - */ - sqfs_compressor_t *(*create_copy)(sqfs_compressor_t *cmp); }; /** diff --git a/include/sqfs/dir_writer.h b/include/sqfs/dir_writer.h index e4a26c7..dce5a79 100644 --- a/include/sqfs/dir_writer.h +++ b/include/sqfs/dir_writer.h @@ -58,6 +58,8 @@ * adding entries. Internally it fills data into a meta data writer and * generates an index that it can, on request, write to another meta data * writer used for inodes. + * + * This object is not copyable, i.e. @ref sqfs_copy will always return NULL. */ /** diff --git a/include/sqfs/io.h b/include/sqfs/io.h index 578c4fb..18c6810 100644 --- a/include/sqfs/io.h +++ b/include/sqfs/io.h @@ -63,6 +63,11 @@ typedef enum { * @extends sqfs_object_t * * @brief Abstracts file I/O to make it easy to embedd SquashFS. + * + * Files are only copyable if they are read only, i.e. if a file has been + * opened with write access, @ref sqfs_copy will always return NULL. The + * other data types inside libsquashfs assume this to hold for all + * implementations of this interface. */ struct sqfs_file_t { sqfs_object_t base; diff --git a/include/sqfs/meta_writer.h b/include/sqfs/meta_writer.h index be151cc..58968f5 100644 --- a/include/sqfs/meta_writer.h +++ b/include/sqfs/meta_writer.h @@ -46,6 +46,8 @@ * The main task of the meta data writer is to provide a simple append * function that transparently takes care of chopping data up into blocks, * compressing the blocks and pre-pending a header. + * + * This object is not copyable, i.e. @ref sqfs_copy will always return NULL. */ /** diff --git a/include/sqfs/predef.h b/include/sqfs/predef.h index 6ca3503..0e81933 100644 --- a/include/sqfs/predef.h +++ b/include/sqfs/predef.h @@ -121,6 +121,8 @@ typedef struct sqfs_xattr_id_table_t sqfs_xattr_id_table_t; */ typedef struct sqfs_object_t { void (*destroy)(struct sqfs_object_t *instance); + + struct sqfs_object_t *(*copy)(const struct sqfs_object_t *orig); } sqfs_object_t; /** @@ -135,4 +137,22 @@ static SQFS_INLINE void sqfs_destroy(void *obj) ((sqfs_object_t *)obj)->destroy(obj); } +/** + * @brief Create a deep copy of an object if possible. + * + * @memberof sqfs_object_t + * + * @param obj A pointer to an object + * + * @return A pointer to a new object, instantiated from the old on success, + * NULL on failure. + */ +static SQFS_INLINE void *sqfs_copy(const void *obj) +{ + if (((sqfs_object_t *)obj)->copy != NULL) + return ((sqfs_object_t *)obj)->copy(obj); + + return NULL; +} + #endif /* SQFS_PREDEF_H */ diff --git a/lib/common/comp_lzo.c b/lib/common/comp_lzo.c index 8d0335e..24f4009 100644 --- a/lib/common/comp_lzo.c +++ b/lib/common/comp_lzo.c @@ -199,7 +199,7 @@ static void lzo_get_configuration(const sqfs_compressor_t *base, cfg->flags |= SQFS_COMP_FLAG_UNCOMPRESS; } -static sqfs_compressor_t *lzo_create_copy(sqfs_compressor_t *cmp) +static sqfs_object_t *lzo_create_copy(const sqfs_object_t *cmp) { lzo_compressor_t *other = (lzo_compressor_t *)cmp; lzo_compressor_t *lzo; @@ -209,7 +209,7 @@ static sqfs_compressor_t *lzo_create_copy(sqfs_compressor_t *cmp) return NULL; memcpy(lzo, other, sizeof(*lzo)); - return (sqfs_compressor_t *)lzo; + return (sqfs_object_t *)lzo; } static void lzo_destroy(sqfs_object_t *base) @@ -270,7 +270,7 @@ sqfs_compressor_t *lzo_compressor_create(const sqfs_compressor_config_t *cfg) lzo_uncomp_block : lzo_comp_block; base->write_options = lzo_write_options; base->read_options = lzo_read_options; - base->create_copy = lzo_create_copy; + ((sqfs_object_t *)base)->copy = lzo_create_copy; ((sqfs_object_t *)base)->destroy = lzo_destroy; return base; } 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 #include #include +#include #include #include @@ -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(), ©->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(©->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; @@ -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: -- cgit v1.2.3