static int sparse_file_read_normal(struct sparse_file *s, int fd) { 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 to_read; unsigned int i; bool sparse_block; if (!buf) { return -ENOMEM; } while (remain > 0) { to_read = std::min(remain, (int64_t)(s->block_size)); ret = read_all(fd, buf, to_read); if (ret < 0) { error("failed to read sparse file"); free(buf); return ret; } if (to_read == s->block_size) { sparse_block = true; for (i = 1; i < s->block_size / sizeof(uint32_t); i++) { if (buf[0] != buf[i]) { sparse_block = false; break; } } } else { sparse_block = false; } if (sparse_block) { /* TODO: add flag to use skip instead of fill for buf[0] == 0 */ sparse_file_add_fill(s, buf[0], to_read, block); } else { sparse_file_add_fd(s, fd, offset, to_read, block); } remain -= to_read; offset += to_read; block++; } free(buf); return 0; }
static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size, int fd, unsigned int blocks, unsigned int block, uint32_t *crc32) { int ret; int chunk; int64_t len = (int64_t)blocks * s->block_size; uint32_t fill_val; uint32_t *fillbuf; unsigned int i; if (chunk_size != sizeof(fill_val)) { return -EINVAL; } ret = read_all(fd, &fill_val, sizeof(fill_val)); if (ret < 0) { return ret; } ret = sparse_file_add_fill(s, fill_val, len, block); if (ret < 0) { return ret; } if (crc32) { /* Fill copy_buf with the fill value */ fillbuf = (uint32_t *)copybuf; for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) { fillbuf[i] = fill_val; } while (len) { chunk = min(len, COPY_BUF_SIZE); *crc32 = sparse_crc32(*crc32, copybuf, chunk); len -= chunk; } } return 0; }