summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsparse/include/sparse/sparse.h32
-rw-r--r--libsparse/sparse_read.cpp192
2 files changed, 185 insertions, 39 deletions
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 1b91ead5c..3d5fb0c53 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -246,9 +246,24 @@ int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
246int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc); 246int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
247 247
248/** 248/**
249 * sparse_file_import - import an existing sparse file 249 * sparse_file_read_buf - read a buffer into a sparse file cookie
250 * 250 *
251 * @s - sparse file cookie 251 * @s - sparse file cookie
252 * @buf - buffer to read from
253 * @crc - verify the crc of a file in the Android sparse file format
254 *
255 * Reads a buffer into a sparse file cookie. The buffer must remain
256 * valid until the sparse file cookie is freed. If crc is true, the
257 * crc of the sparse file will be verified.
258 *
259 * Returns 0 on success, negative errno on error.
260 */
261int sparse_file_read_buf(struct sparse_file *s, char *buf, bool crc);
262
263/**
264 * sparse_file_import - import an existing sparse file
265 *
266 * @fd - file descriptor to read from
252 * @verbose - print verbose errors while reading the sparse file 267 * @verbose - print verbose errors while reading the sparse file
253 * @crc - verify the crc of a file in the Android sparse file format 268 * @crc - verify the crc of a file in the Android sparse file format
254 * 269 *
@@ -261,6 +276,21 @@ int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
261struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc); 276struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc);
262 277
263/** 278/**
279 * sparse_file_import_buf - import an existing sparse file from a buffer
280 *
281 * @buf - buffer to read from
282 * @verbose - print verbose errors while reading the sparse file
283 * @crc - verify the crc of a file in the Android sparse file format
284 *
285 * Reads existing sparse file data into a sparse file cookie, recreating the same
286 * sparse cookie that was used to write it. If verbose is true, prints verbose
287 * errors when the sparse file is formatted incorrectly.
288 *
289 * Returns a new sparse file cookie on success, NULL on error.
290 */
291struct sparse_file *sparse_file_import_buf(char* buf, bool verbose, bool crc);
292
293/**
264 * sparse_file_import_auto - import an existing sparse or normal file 294 * sparse_file_import_auto - import an existing sparse or normal file
265 * 295 *
266 * @fd - file descriptor to read from 296 * @fd - file descriptor to read from
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 437963527..d6a68b3c7 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -58,6 +58,114 @@ static std::string ErrorString(int err)
58 return android::base::StringPrintf("Unknown error %d", err); 58 return android::base::StringPrintf("Unknown error %d", err);
59} 59}
60 60
61class SparseFileSource {
62public:
63 /* Seeks the source ahead by the given offset. */
64 virtual void Seek(int64_t offset) = 0;
65
66 /* Return the current offset. */
67 virtual int64_t GetOffset() = 0;
68
69 /* Set the current offset. Return 0 if successful. */
70 virtual int SetOffset(int64_t offset) = 0;
71
72 /* Adds the given length from the current offset of the source to the file at the given
73 * block. Return 0 if successful. */
74 virtual int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) = 0;
75
76 /* Get data of fixed size from the current offset and seek len bytes.
77 * Return 0 if successful. */
78 virtual int ReadValue(void *ptr, int len) = 0;
79
80 /* Find the crc32 of the next len bytes and seek ahead len bytes. Return 0 if successful. */
81 virtual int GetCrc32(uint32_t *crc32, int64_t len) = 0;
82
83 virtual ~SparseFileSource() {};
84};
85
86class SparseFileFdSource : public SparseFileSource {
87private:
88 int fd;
89public:
90 SparseFileFdSource(int fd) : fd(fd) {}
91 ~SparseFileFdSource() override {}
92
93 void Seek(int64_t off) override {
94 lseek64(fd, off, SEEK_CUR);
95 }
96
97 int64_t GetOffset() override {
98 return lseek64(fd, 0, SEEK_CUR);
99 }
100
101 int SetOffset(int64_t offset) override {
102 return lseek64(fd, offset, SEEK_SET) == offset ? 0 : -errno;
103 }
104
105 int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) override {
106 return sparse_file_add_fd(s, fd, GetOffset(), len, block);
107 }
108
109 int ReadValue(void *ptr, int len) override {
110 return read_all(fd, ptr, len);
111 }
112
113 int GetCrc32(uint32_t *crc32, int64_t len) override {
114 int chunk;
115 int ret;
116 while (len) {
117 chunk = std::min(len, COPY_BUF_SIZE);
118 ret = read_all(fd, copybuf, chunk);
119 if (ret < 0) {
120 return ret;
121 }
122 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
123 len -= chunk;
124 }
125 return 0;
126 }
127};
128
129class SparseFileBufSource : public SparseFileSource {
130private:
131 char *buf;
132 int64_t offset;
133public:
134 SparseFileBufSource(char *buf) : buf(buf), offset(0) {}
135 ~SparseFileBufSource() override {}
136
137 void Seek(int64_t off) override {
138 buf += off;
139 offset += off;
140 }
141
142 int64_t GetOffset() override {
143 return offset;
144 }
145
146 int SetOffset(int64_t off) override {
147 buf += off - offset;
148 offset = off;
149 return 0;
150 }
151
152 int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) override {
153 return sparse_file_add_data(s, buf, len, block);
154 }
155
156 int ReadValue(void *ptr, int len) override {
157 memcpy(ptr, buf, len);
158 Seek(len);
159 return 0;
160 }
161
162 int GetCrc32(uint32_t *crc32, int64_t len) override {
163 *crc32 = sparse_crc32(*crc32, buf, len);
164 Seek(len);
165 return 0;
166 }
167};
168
61static void verbose_error(bool verbose, int err, const char *fmt, ...) 169static void verbose_error(bool verbose, int err, const char *fmt, ...)
62{ 170{
63 if (!verbose) return; 171 if (!verbose) return;
@@ -74,11 +182,10 @@ static void verbose_error(bool verbose, int err, const char *fmt, ...)
74} 182}
75 183
76static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size, 184static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size,
77 int fd, int64_t offset, unsigned int blocks, unsigned int block, 185 SparseFileSource *source, unsigned int blocks, unsigned int block,
78 uint32_t *crc32) 186 uint32_t *crc32)
79{ 187{
80 int ret; 188 int ret;
81 int chunk;
82 int64_t len = blocks * s->block_size; 189 int64_t len = blocks * s->block_size;
83 190
84 if (chunk_size % s->block_size != 0) { 191 if (chunk_size % s->block_size != 0) {
@@ -89,30 +196,25 @@ static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size,
89 return -EINVAL; 196 return -EINVAL;
90 } 197 }
91 198
92 ret = sparse_file_add_fd(s, fd, offset, len, block); 199 ret = source->AddToSparseFile(s, len, block);
93 if (ret < 0) { 200 if (ret < 0) {
94 return ret; 201 return ret;
95 } 202 }
96 203
97 if (crc32) { 204 if (crc32) {
98 while (len) { 205 ret = source->GetCrc32(crc32, len);
99 chunk = std::min(len, COPY_BUF_SIZE); 206 if (ret < 0) {
100 ret = read_all(fd, copybuf, chunk); 207 return ret;
101 if (ret < 0) {
102 return ret;
103 }
104 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
105 len -= chunk;
106 } 208 }
107 } else { 209 } else {
108 lseek64(fd, len, SEEK_CUR); 210 source->Seek(len);
109 } 211 }
110 212
111 return 0; 213 return 0;
112} 214}
113 215
114static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size, 216static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size,
115 int fd, unsigned int blocks, unsigned int block, uint32_t *crc32) 217 SparseFileSource *source, unsigned int blocks, unsigned int block, uint32_t *crc32)
116{ 218{
117 int ret; 219 int ret;
118 int chunk; 220 int chunk;
@@ -125,7 +227,7 @@ static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size,
125 return -EINVAL; 227 return -EINVAL;
126 } 228 }
127 229
128 ret = read_all(fd, &fill_val, sizeof(fill_val)); 230 ret = source->ReadValue(&fill_val, sizeof(fill_val));
129 if (ret < 0) { 231 if (ret < 0) {
130 return ret; 232 return ret;
131 } 233 }
@@ -153,7 +255,7 @@ static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size,
153} 255}
154 256
155static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size, 257static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
156 int fd __unused, unsigned int blocks, 258 SparseFileSource *source __unused, unsigned int blocks,
157 unsigned int block __unused, uint32_t *crc32) 259 unsigned int block __unused, uint32_t *crc32)
158{ 260{
159 if (chunk_size != 0) { 261 if (chunk_size != 0) {
@@ -161,7 +263,7 @@ static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
161 } 263 }
162 264
163 if (crc32) { 265 if (crc32) {
164 int64_t len = (int64_t)blocks * s->block_size; 266 int64_t len = (int64_t)blocks * s->block_size;
165 memset(copybuf, 0, COPY_BUF_SIZE); 267 memset(copybuf, 0, COPY_BUF_SIZE);
166 268
167 while (len) { 269 while (len) {
@@ -174,16 +276,15 @@ static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
174 return 0; 276 return 0;
175} 277}
176 278
177static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t *crc32) 279static int process_crc32_chunk(SparseFileSource *source, unsigned int chunk_size, uint32_t *crc32)
178{ 280{
179 uint32_t file_crc32; 281 uint32_t file_crc32;
180 int ret;
181 282
182 if (chunk_size != sizeof(file_crc32)) { 283 if (chunk_size != sizeof(file_crc32)) {
183 return -EINVAL; 284 return -EINVAL;
184 } 285 }
185 286
186 ret = read_all(fd, &file_crc32, sizeof(file_crc32)); 287 int ret = source->ReadValue(&file_crc32, sizeof(file_crc32));
187 if (ret < 0) { 288 if (ret < 0) {
188 return ret; 289 return ret;
189 } 290 }
@@ -195,18 +296,19 @@ static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t *crc32)
195 return 0; 296 return 0;
196} 297}
197 298
198static int process_chunk(struct sparse_file *s, int fd, off64_t offset, 299static int process_chunk(struct sparse_file *s, SparseFileSource *source,
199 unsigned int chunk_hdr_sz, chunk_header_t *chunk_header, 300 unsigned int chunk_hdr_sz, chunk_header_t *chunk_header,
200 unsigned int cur_block, uint32_t *crc_ptr) 301 unsigned int cur_block, uint32_t *crc_ptr)
201{ 302{
202 int ret; 303 int ret;
203 unsigned int chunk_data_size; 304 unsigned int chunk_data_size;
305 int64_t offset = source->GetOffset();
204 306
205 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz; 307 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
206 308
207 switch (chunk_header->chunk_type) { 309 switch (chunk_header->chunk_type) {
208 case CHUNK_TYPE_RAW: 310 case CHUNK_TYPE_RAW:
209 ret = process_raw_chunk(s, chunk_data_size, fd, offset, 311 ret = process_raw_chunk(s, chunk_data_size, source,
210 chunk_header->chunk_sz, cur_block, crc_ptr); 312 chunk_header->chunk_sz, cur_block, crc_ptr);
211 if (ret < 0) { 313 if (ret < 0) {
212 verbose_error(s->verbose, ret, "data block at %" PRId64, offset); 314 verbose_error(s->verbose, ret, "data block at %" PRId64, offset);
@@ -214,7 +316,7 @@ static int process_chunk(struct sparse_file *s, int fd, off64_t offset,
214 } 316 }
215 return chunk_header->chunk_sz; 317 return chunk_header->chunk_sz;
216 case CHUNK_TYPE_FILL: 318 case CHUNK_TYPE_FILL:
217 ret = process_fill_chunk(s, chunk_data_size, fd, 319 ret = process_fill_chunk(s, chunk_data_size, source,
218 chunk_header->chunk_sz, cur_block, crc_ptr); 320 chunk_header->chunk_sz, cur_block, crc_ptr);
219 if (ret < 0) { 321 if (ret < 0) {
220 verbose_error(s->verbose, ret, "fill block at %" PRId64, offset); 322 verbose_error(s->verbose, ret, "fill block at %" PRId64, offset);
@@ -222,7 +324,7 @@ static int process_chunk(struct sparse_file *s, int fd, off64_t offset,
222 } 324 }
223 return chunk_header->chunk_sz; 325 return chunk_header->chunk_sz;
224 case CHUNK_TYPE_DONT_CARE: 326 case CHUNK_TYPE_DONT_CARE:
225 ret = process_skip_chunk(s, chunk_data_size, fd, 327 ret = process_skip_chunk(s, chunk_data_size, source,
226 chunk_header->chunk_sz, cur_block, crc_ptr); 328 chunk_header->chunk_sz, cur_block, crc_ptr);
227 if (chunk_data_size != 0) { 329 if (chunk_data_size != 0) {
228 if (ret < 0) { 330 if (ret < 0) {
@@ -232,7 +334,7 @@ static int process_chunk(struct sparse_file *s, int fd, off64_t offset,
232 } 334 }
233 return chunk_header->chunk_sz; 335 return chunk_header->chunk_sz;
234 case CHUNK_TYPE_CRC32: 336 case CHUNK_TYPE_CRC32:
235 ret = process_crc32_chunk(fd, chunk_data_size, crc_ptr); 337 ret = process_crc32_chunk(source, chunk_data_size, crc_ptr);
236 if (ret < 0) { 338 if (ret < 0) {
237 verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64, 339 verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64,
238 offset); 340 offset);
@@ -247,7 +349,7 @@ static int process_chunk(struct sparse_file *s, int fd, off64_t offset,
247 return 0; 349 return 0;
248} 350}
249 351
250static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc) 352static int sparse_file_read_sparse(struct sparse_file *s, SparseFileSource *source, bool crc)
251{ 353{
252 int ret; 354 int ret;
253 unsigned int i; 355 unsigned int i;
@@ -256,7 +358,6 @@ static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
256 uint32_t crc32 = 0; 358 uint32_t crc32 = 0;
257 uint32_t *crc_ptr = 0; 359 uint32_t *crc_ptr = 0;
258 unsigned int cur_block = 0; 360 unsigned int cur_block = 0;
259 off64_t offset;
260 361
261 if (!copybuf) { 362 if (!copybuf) {
262 copybuf = (char *)malloc(COPY_BUF_SIZE); 363 copybuf = (char *)malloc(COPY_BUF_SIZE);
@@ -270,7 +371,7 @@ static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
270 crc_ptr = &crc32; 371 crc_ptr = &crc32;
271 } 372 }
272 373
273 ret = read_all(fd, &sparse_header, sizeof(sparse_header)); 374 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
274 if (ret < 0) { 375 if (ret < 0) {
275 return ret; 376 return ret;
276 } 377 }
@@ -295,11 +396,11 @@ static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
295 /* Skip the remaining bytes in a header that is longer than 396 /* Skip the remaining bytes in a header that is longer than
296 * we expected. 397 * we expected.
297 */ 398 */
298 lseek64(fd, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR); 399 source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
299 } 400 }
300 401
301 for (i = 0; i < sparse_header.total_chunks; i++) { 402 for (i = 0; i < sparse_header.total_chunks; i++) {
302 ret = read_all(fd, &chunk_header, sizeof(chunk_header)); 403 ret = source->ReadValue(&chunk_header, sizeof(chunk_header));
303 if (ret < 0) { 404 if (ret < 0) {
304 return ret; 405 return ret;
305 } 406 }
@@ -308,12 +409,10 @@ static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
308 /* Skip the remaining bytes in a header that is longer than 409 /* Skip the remaining bytes in a header that is longer than
309 * we expected. 410 * we expected.
310 */ 411 */
311 lseek64(fd, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR); 412 source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
312 } 413 }
313 414
314 offset = lseek64(fd, 0, SEEK_CUR); 415 ret = process_chunk(s, source, sparse_header.chunk_hdr_sz, &chunk_header,
315
316 ret = process_chunk(s, fd, offset, sparse_header.chunk_hdr_sz, &chunk_header,
317 cur_block, crc_ptr); 416 cur_block, crc_ptr);
318 if (ret < 0) { 417 if (ret < 0) {
319 return ret; 418 return ret;
@@ -388,20 +487,27 @@ int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc)
388 } 487 }
389 488
390 if (sparse) { 489 if (sparse) {
391 return sparse_file_read_sparse(s, fd, crc); 490 SparseFileFdSource source(fd);
491 return sparse_file_read_sparse(s, &source, crc);
392 } else { 492 } else {
393 return sparse_file_read_normal(s, fd); 493 return sparse_file_read_normal(s, fd);
394 } 494 }
395} 495}
396 496
397struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc) 497int sparse_file_read_buf(struct sparse_file *s, char *buf, bool crc)
498{
499 SparseFileBufSource source(buf);
500 return sparse_file_read_sparse(s, &source, crc);
501}
502
503static struct sparse_file *sparse_file_import_source(SparseFileSource *source, bool verbose, bool crc)
398{ 504{
399 int ret; 505 int ret;
400 sparse_header_t sparse_header; 506 sparse_header_t sparse_header;
401 int64_t len; 507 int64_t len;
402 struct sparse_file *s; 508 struct sparse_file *s;
403 509
404 ret = read_all(fd, &sparse_header, sizeof(sparse_header)); 510 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
405 if (ret < 0) { 511 if (ret < 0) {
406 verbose_error(verbose, ret, "header"); 512 verbose_error(verbose, ret, "header");
407 return NULL; 513 return NULL;
@@ -432,7 +538,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
432 return NULL; 538 return NULL;
433 } 539 }
434 540
435 ret = lseek64(fd, 0, SEEK_SET); 541 ret = source->SetOffset(0);
436 if (ret < 0) { 542 if (ret < 0) {
437 verbose_error(verbose, ret, "seeking"); 543 verbose_error(verbose, ret, "seeking");
438 sparse_file_destroy(s); 544 sparse_file_destroy(s);
@@ -441,7 +547,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
441 547
442 s->verbose = verbose; 548 s->verbose = verbose;
443 549
444 ret = sparse_file_read(s, fd, true, crc); 550 ret = sparse_file_read_sparse(s, source, crc);
445 if (ret < 0) { 551 if (ret < 0) {
446 sparse_file_destroy(s); 552 sparse_file_destroy(s);
447 return NULL; 553 return NULL;
@@ -450,6 +556,16 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
450 return s; 556 return s;
451} 557}
452 558
559struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc) {
560 SparseFileFdSource source(fd);
561 return sparse_file_import_source(&source, verbose, crc);
562}
563
564struct sparse_file *sparse_file_import_buf(char* buf, bool verbose, bool crc) {
565 SparseFileBufSource source(buf);
566 return sparse_file_import_source(&source, verbose, crc);
567}
568
453struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose) 569struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose)
454{ 570{
455 struct sparse_file *s; 571 struct sparse_file *s;