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
This commit is contained in:
parent
b55dceea98
commit
9e1f17e926
|
@ -34,6 +34,10 @@ struct backed_block {
|
|||
char *filename;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -110,6 +110,32 @@ int sparse_file_add_file(struct sparse_file *s,
|
|||
const char *filename, int64_t file_offset, unsigned int len,
|
||||
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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue