summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJerry Zhang2018-06-05 13:44:52 -0500
committerJerry Zhang2018-06-07 16:33:18 -0500
commit50e6029a4e4b9c9bd6065548ced523ec5b01e705 (patch)
tree16b6c5529b11af841a6ebbdbe4b8e9d362946526 /libsparse
parentf875aaa339e864410b7243d312d06020f86845f8 (diff)
downloadplatform-system-core-50e6029a4e4b9c9bd6065548ced523ec5b01e705.tar.gz
platform-system-core-50e6029a4e4b9c9bd6065548ced523ec5b01e705.tar.xz
platform-system-core-50e6029a4e4b9c9bd6065548ced523ec5b01e705.zip
libsparse: Add method to create sparse file from buffer
Refactor elements of sparse file parsing that depend on an fd into SparseFileSource class, then create implementations using both fd and buffer. Add sparse_file_read_buf which reads the given buffer into a sparse file cookie without copying. Test: flash system with sparse images Bug: 78793464 Change-Id: Ice6c8e1ff075d6867e070f80fcf5aa4f530a1b95
Diffstat (limited to 'libsparse')
-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;