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
|
@ -93,7 +93,7 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sparse_file_verbose(s);
|
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) {
|
if (ret) {
|
||||||
fprintf(stderr, "Failed to read file\n");
|
fprintf(stderr, "Failed to read file\n");
|
||||||
exit(-1);
|
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,
|
int (*write)(void *priv, const void *data, size_t len, unsigned int block,
|
||||||
unsigned int nr_blocks),
|
unsigned int nr_blocks),
|
||||||
void *priv);
|
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
|
* sparse_file_read - read a file into a sparse file cookie
|
||||||
*
|
*
|
||||||
* @s - sparse file cookie
|
* @s - sparse file cookie
|
||||||
* @fd - file descriptor to read from
|
* @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
|
* @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
|
* Reads a file into a sparse file cookie. If @mode is
|
||||||
* assumed to be in the Android sparse file format. If sparse is false, the
|
* %SPARSE_READ_MODE_SPARSE, the file is assumed to be in the Android sparse
|
||||||
* file will be sparsed by looking for block aligned chunks of all zeros or
|
* file format. If @mode is %SPARSE_READ_MODE_NORMAL, the file will be sparsed
|
||||||
* another 32 bit value. If crc is true, the crc of the sparse file will be
|
* by looking for block aligned chunks of all zeros or another 32 bit value. If
|
||||||
* verified.
|
* @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.
|
* 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
|
* 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;
|
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;
|
int ret;
|
||||||
uint32_t* buf = (uint32_t*)malloc(s->block_size);
|
unsigned int block = offset / s->block_size;
|
||||||
unsigned int block = 0;
|
|
||||||
int64_t remain = s->len;
|
|
||||||
int64_t offset = 0;
|
|
||||||
unsigned int to_read;
|
unsigned int to_read;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool sparse_block;
|
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);
|
ret = read_all(fd, buf, to_read);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error("failed to read sparse file");
|
error("failed to read sparse file");
|
||||||
free(buf);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,20 +501,93 @@ static int sparse_file_read_normal(struct sparse_file* s, int fd) {
|
||||||
block++;
|
block++;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sparse_file_read(struct sparse_file* s, int fd, bool sparse, bool crc) {
|
static int sparse_file_read_normal(struct sparse_file* s, int fd) {
|
||||||
if (crc && !sparse) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sparse) {
|
switch (mode) {
|
||||||
SparseFileFdSource source(fd);
|
case SPARSE_READ_MODE_SPARSE: {
|
||||||
return sparse_file_read_sparse(s, &source, crc);
|
SparseFileFdSource source(fd);
|
||||||
} else {
|
return sparse_file_read_sparse(s, &source, crc);
|
||||||
return sparse_file_read_normal(s, fd);
|
}
|
||||||
|
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 New Issue