Merge changes from topic "sparse-file-read-enum"
* changes: libsparse: Add "hole" mode to sparse_file_read libsparse: Split off most of sparse_file_read_normal into a helper function
This commit is contained in:
commit
f401dcdf5a
3 changed files with 111 additions and 22 deletions
|
@ -93,7 +93,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
sparse_file_verbose(s);
|
||||
ret = sparse_file_read(s, in, false, false);
|
||||
ret = sparse_file_read(s, in, SPARSE_READ_MODE_NORMAL, false);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Failed to read file\n");
|
||||
exit(-1);
|
||||
|
|
|
@ -225,23 +225,42 @@ int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
|
|||
int (*write)(void *priv, const void *data, size_t len, unsigned int block,
|
||||
unsigned int nr_blocks),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* enum sparse_read_mode - The method to use when reading in files
|
||||
* @SPARSE_READ_MODE_NORMAL: The input is a regular file. Constant chunks of
|
||||
* data (including holes) will be be converted to
|
||||
* fill chunks.
|
||||
* @SPARSE_READ_MODE_SPARSE: The input is an Android sparse file.
|
||||
* @SPARSE_READ_MODE_HOLE: The input is a regular file. Holes will be converted
|
||||
* to "don't care" chunks. Other constant chunks will
|
||||
* be converted to fill chunks.
|
||||
*/
|
||||
enum sparse_read_mode {
|
||||
SPARSE_READ_MODE_NORMAL = false,
|
||||
SPARSE_READ_MODE_SPARSE = true,
|
||||
SPARSE_READ_MODE_HOLE,
|
||||
};
|
||||
|
||||
/**
|
||||
* sparse_file_read - read a file into a sparse file cookie
|
||||
*
|
||||
* @s - sparse file cookie
|
||||
* @fd - file descriptor to read from
|
||||
* @sparse - read a file in the Android sparse file format
|
||||
* @mode - mode to use when reading the input file
|
||||
* @crc - verify the crc of a file in the Android sparse file format
|
||||
*
|
||||
* Reads a file into a sparse file cookie. If sparse is true, the file is
|
||||
* assumed to be in the Android sparse file format. If sparse is false, the
|
||||
* file will be sparsed by looking for block aligned chunks of all zeros or
|
||||
* another 32 bit value. If crc is true, the crc of the sparse file will be
|
||||
* verified.
|
||||
* Reads a file into a sparse file cookie. If @mode is
|
||||
* %SPARSE_READ_MODE_SPARSE, the file is assumed to be in the Android sparse
|
||||
* file format. If @mode is %SPARSE_READ_MODE_NORMAL, the file will be sparsed
|
||||
* by looking for block aligned chunks of all zeros or another 32 bit value. If
|
||||
* @mode is %SPARSE_READ_MODE_HOLE, the file will be sparsed like
|
||||
* %SPARSE_READ_MODE_NORMAL, but holes in the file will be converted to "don't
|
||||
* care" chunks. If crc is true, the crc of the sparse file will be verified.
|
||||
*
|
||||
* Returns 0 on success, negative errno on error.
|
||||
*/
|
||||
int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
|
||||
int sparse_file_read(struct sparse_file *s, int fd, enum sparse_read_mode mode, bool crc);
|
||||
|
||||
/**
|
||||
* sparse_file_import - import an existing sparse file
|
||||
|
|
|
@ -457,12 +457,10 @@ static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* sour
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sparse_file_read_normal(struct sparse_file* s, int fd) {
|
||||
static int do_sparse_file_read_normal(struct sparse_file* s, int fd, uint32_t* buf, int64_t offset,
|
||||
int64_t remain) {
|
||||
int ret;
|
||||
uint32_t* buf = (uint32_t*)malloc(s->block_size);
|
||||
unsigned int block = 0;
|
||||
int64_t remain = s->len;
|
||||
int64_t offset = 0;
|
||||
unsigned int block = offset / s->block_size;
|
||||
unsigned int to_read;
|
||||
unsigned int i;
|
||||
bool sparse_block;
|
||||
|
@ -476,7 +474,6 @@ static int sparse_file_read_normal(struct sparse_file* s, int fd) {
|
|||
ret = read_all(fd, buf, to_read);
|
||||
if (ret < 0) {
|
||||
error("failed to read sparse file");
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -504,20 +501,93 @@ static int sparse_file_read_normal(struct sparse_file* s, int fd) {
|
|||
block++;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sparse_file_read(struct sparse_file* s, int fd, bool sparse, bool crc) {
|
||||
if (crc && !sparse) {
|
||||
static int sparse_file_read_normal(struct sparse_file* s, int fd) {
|
||||
int ret;
|
||||
uint32_t* buf = (uint32_t*)malloc(s->block_size);
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = do_sparse_file_read_normal(s, fd, buf, 0, s->len);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static int sparse_file_read_hole(struct sparse_file* s, int fd) {
|
||||
int ret;
|
||||
uint32_t* buf = (uint32_t*)malloc(s->block_size);
|
||||
int64_t end = 0;
|
||||
int64_t start = 0;
|
||||
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
do {
|
||||
start = lseek(fd, end, SEEK_DATA);
|
||||
if (start < 0) {
|
||||
if (errno == ENXIO)
|
||||
/* The rest of the file is a hole */
|
||||
break;
|
||||
|
||||
error("could not seek to data");
|
||||
free(buf);
|
||||
return -errno;
|
||||
} else if (start > s->len) {
|
||||
break;
|
||||
}
|
||||
|
||||
end = lseek(fd, start, SEEK_HOLE);
|
||||
if (end < 0) {
|
||||
error("could not seek to end");
|
||||
free(buf);
|
||||
return -errno;
|
||||
}
|
||||
end = std::min(end, s->len);
|
||||
|
||||
start = ALIGN_DOWN(start, s->block_size);
|
||||
end = ALIGN(end, s->block_size);
|
||||
if (lseek(fd, start, SEEK_SET) < 0) {
|
||||
free(buf);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ret = do_sparse_file_read_normal(s, fd, buf, start, end - start);
|
||||
if (ret) {
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
} while (end < s->len);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int sparse_file_read_hole(struct sparse_file* s __unused, int fd __unused) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sparse_file_read(struct sparse_file* s, int fd, enum sparse_read_mode mode, bool crc) {
|
||||
if (crc && mode != SPARSE_READ_MODE_SPARSE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sparse) {
|
||||
SparseFileFdSource source(fd);
|
||||
return sparse_file_read_sparse(s, &source, crc);
|
||||
} else {
|
||||
return sparse_file_read_normal(s, fd);
|
||||
switch (mode) {
|
||||
case SPARSE_READ_MODE_SPARSE: {
|
||||
SparseFileFdSource source(fd);
|
||||
return sparse_file_read_sparse(s, &source, crc);
|
||||
}
|
||||
case SPARSE_READ_MODE_NORMAL:
|
||||
return sparse_file_read_normal(s, fd);
|
||||
case SPARSE_READ_MODE_HOLE:
|
||||
return sparse_file_read_hole(s, fd);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue