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:
Treehugger Robot 2022-01-28 05:28:04 +00:00 committed by Gerrit Code Review
commit f401dcdf5a
3 changed files with 111 additions and 22 deletions

View file

@ -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);

View file

@ -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

View 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;
}
}