diff options
author | Colin Cross <ccross@android.com> | 2012-04-25 18:31:39 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2012-07-09 22:09:37 -0700 |
commit | 9e1f17e926fa20255c5f4b4d2f68aa98a964253a (patch) | |
tree | 142907cdec91851c3e162bdfc23638df9a0d675b /libsparse | |
parent | b55dceea986ab24f8b836b5116b389ed619c816e (diff) | |
download | system_core-9e1f17e926fa20255c5f4b4d2f68aa98a964253a.zip system_core-9e1f17e926fa20255c5f4b4d2f68aa98a964253a.tar.gz system_core-9e1f17e926fa20255c5f4b4d2f68aa98a964253a.tar.bz2 |
libsparse: add support for including fds
Add sparse_file_add_fd to include all or part of the contents
of an fd in the output file. Will be useful for re-sparsing files
where fd will point to the input sparse file.
Change-Id: I5d4ab07fb37231e8e9c1912f62a2968c8b0a00ef
Diffstat (limited to 'libsparse')
-rw-r--r-- | libsparse/backed_block.c | 37 | ||||
-rw-r--r-- | libsparse/backed_block.h | 4 | ||||
-rw-r--r-- | libsparse/include/sparse/sparse.h | 26 | ||||
-rw-r--r-- | libsparse/output_file.c | 37 | ||||
-rw-r--r-- | libsparse/output_file.h | 2 | ||||
-rw-r--r-- | libsparse/sparse.c | 10 |
6 files changed, 99 insertions, 17 deletions
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c index b259190..8c3fab0 100644 --- a/libsparse/backed_block.c +++ b/libsparse/backed_block.c @@ -35,6 +35,10 @@ struct backed_block { int64_t offset; } file; struct { + int fd; + int64_t offset; + } fd; + struct { uint32_t val; } fill; }; @@ -78,10 +82,20 @@ const char *backed_block_filename(struct backed_block *bb) return bb->file.filename; } +int backed_block_fd(struct backed_block *bb) +{ + assert(bb->type == BACKED_BLOCK_FD); + return bb->fd.fd; +} + int64_t backed_block_file_offset(struct backed_block *bb) { - assert(bb->type == BACKED_BLOCK_FILE); - return bb->file.offset; + assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD); + if (bb->type == BACKED_BLOCK_FILE) { + return bb->file.offset; + } else { /* bb->type == BACKED_BLOCK_FD */ + return bb->fd.offset; + } } uint32_t backed_block_fill_val(struct backed_block *bb) @@ -211,3 +225,22 @@ int backed_block_add_file(struct backed_block_list *bbl, const char *filename, return queue_bb(bbl, bb); } + +/* Queues a chunk of a fd to be written to the specified data blocks */ +int backed_block_add_fd(struct backed_block_list *bbl, int fd, int64_t offset, + unsigned int len, unsigned int block) +{ + struct backed_block *bb = calloc(1, sizeof(struct backed_block)); + if (bb == NULL) { + return -ENOMEM; + } + + bb->block = block; + bb->len = len; + bb->type = BACKED_BLOCK_FD; + bb->fd.fd = fd; + bb->fd.offset = offset; + bb->next = NULL; + + return queue_bb(bbl, bb); +} diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h index 3166505..ca2ad1d 100644 --- a/libsparse/backed_block.h +++ b/libsparse/backed_block.h @@ -25,6 +25,7 @@ struct backed_block; enum backed_block_type { BACKED_BLOCK_DATA, BACKED_BLOCK_FILE, + BACKED_BLOCK_FD, BACKED_BLOCK_FILL, }; @@ -34,6 +35,8 @@ int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val, unsigned int len, unsigned int block); int backed_block_add_file(struct backed_block_list *bbl, const char *filename, int64_t offset, unsigned int len, unsigned int block); +int backed_block_add_fd(struct backed_block_list *bbl, int fd, + int64_t offset, unsigned int len, unsigned int block); struct backed_block *backed_block_iter_new(struct backed_block_list *bbl); struct backed_block *backed_block_iter_next(struct backed_block *bb); @@ -41,6 +44,7 @@ unsigned int backed_block_len(struct backed_block *bb); unsigned int backed_block_block(struct backed_block *bb); void *backed_block_data(struct backed_block *bb); const char *backed_block_filename(struct backed_block *bb); +int backed_block_fd(struct backed_block *bb); int64_t backed_block_file_offset(struct backed_block *bb); uint32_t backed_block_fill_val(struct backed_block *bb); enum backed_block_type backed_block_type(struct backed_block *bb); diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h index db06884..6484333 100644 --- a/libsparse/include/sparse/sparse.h +++ b/libsparse/include/sparse/sparse.h @@ -111,6 +111,32 @@ int sparse_file_add_file(struct sparse_file *s, unsigned int block); /** + * sparse_file_add_file - associate a chunk of a file with a sparse file + * + * @s - sparse file cookie + * @filename - filename of the file to be copied + * @file_offset - offset into the copied file + * @len - length of the copied block + * @block - offset in blocks into the sparse file to place the file chunk + * + * Associates a chunk of an existing fd with a sparse file cookie. + * The region [block * block_size : block * block_size + len) must not already + * be used in the sparse file. If len is not a multiple of the block size the + * data will be padded with zeros. + * + * Allows adding large amounts of data to a sparse file without needing to keep + * it all mapped. File size is limited by available virtual address space, + * exceptionally large files may need to be added in multiple chunks. + * + * The fd must remain open until the sparse file is closed or the fd block is + * removed from the sparse file. + * + * Returns 0 on success, negative errno on error. + */ +int sparse_file_add_fd(struct sparse_file *s, + int fd, int64_t file_offset, unsigned int len, unsigned int block); + +/** * sparse_file_write - write a sparse file to a file * * @s - sparse file cookie diff --git a/libsparse/output_file.c b/libsparse/output_file.c index f911f8c..4193fd1 100644 --- a/libsparse/output_file.c +++ b/libsparse/output_file.c @@ -511,38 +511,28 @@ int write_fill_chunk(struct output_file *out, unsigned int len, return out->sparse_ops->write_fill_chunk(out, len, fill_val); } -/* Write a contiguous region of data blocks from a file */ -int write_file_chunk(struct output_file *out, unsigned int len, - const char *file, int64_t offset) +int write_fd_chunk(struct output_file *out, unsigned int len, + int fd, int64_t offset) { int ret; int64_t aligned_offset; int aligned_diff; int buffer_size; - int file_fd = open(file, O_RDONLY | O_BINARY); - if (file_fd < 0) { - return -errno; - } - aligned_offset = offset & ~(4096 - 1); aligned_diff = offset - aligned_offset; buffer_size = len + aligned_diff; #ifndef USE_MINGW - char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, file_fd, + char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset); if (data == MAP_FAILED) { - ret = -errno; - close(file_fd); - return ret; + return -errno; } #else char *data = malloc(buffer_size); if (!data) { - ret = -errno; - close(file_fd); - return ret; + return -errno; } memset(data, 0, buffer_size); #endif @@ -554,6 +544,23 @@ int write_file_chunk(struct output_file *out, unsigned int len, #else free(data); #endif + + return ret; +} + +/* Write a contiguous region of data blocks from a file */ +int write_file_chunk(struct output_file *out, unsigned int len, + const char *file, int64_t offset) +{ + int ret; + + int file_fd = open(file, O_RDONLY | O_BINARY); + if (file_fd < 0) { + return -errno; + } + + ret = write_fd_chunk(out, len, file_fd, offset); + close(file_fd); return ret; diff --git a/libsparse/output_file.h b/libsparse/output_file.h index cb2feb7..d23abf3 100644 --- a/libsparse/output_file.h +++ b/libsparse/output_file.h @@ -31,6 +31,8 @@ int write_fill_chunk(struct output_file *out, unsigned int len, uint32_t fill_val); int write_file_chunk(struct output_file *out, unsigned int len, const char *file, int64_t offset); +int write_fd_chunk(struct output_file *out, unsigned int len, + int fd, int64_t offset); int write_skip_chunk(struct output_file *out, int64_t len); void close_output_file(struct output_file *out); diff --git a/libsparse/sparse.c b/libsparse/sparse.c index fce9dbb..4ebcf0f 100644 --- a/libsparse/sparse.c +++ b/libsparse/sparse.c @@ -70,6 +70,12 @@ int sparse_file_add_file(struct sparse_file *s, len, block); } +int sparse_file_add_fd(struct sparse_file *s, + int fd, int64_t file_offset, unsigned int len, unsigned int block) +{ + return backed_block_add_fd(s->backed_block_list, fd, file_offset, + len, block); +} unsigned int sparse_count_chunks(struct sparse_file *s) { struct backed_block *bb; @@ -122,6 +128,10 @@ int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, write_file_chunk(out, backed_block_len(bb), backed_block_filename(bb), backed_block_file_offset(bb)); break; + case BACKED_BLOCK_FD: + write_fd_chunk(out, backed_block_len(bb), + backed_block_fd(bb), backed_block_file_offset(bb)); + break; case BACKED_BLOCK_FILL: write_fill_chunk(out, backed_block_len(bb), backed_block_fill_val(bb)); |