diff options
-rw-r--r-- | libsparse/include/sparse/sparse.h | 32 | ||||
-rw-r--r-- | libsparse/sparse_read.cpp | 192 |
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, | |||
246 | int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc); | 246 | int 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 | */ | ||
261 | int 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); | |||
261 | struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc); | 276 | struct 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 | */ | ||
291 | struct 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 | ||
61 | class SparseFileSource { | ||
62 | public: | ||
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 | |||
86 | class SparseFileFdSource : public SparseFileSource { | ||
87 | private: | ||
88 | int fd; | ||
89 | public: | ||
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 | |||
129 | class SparseFileBufSource : public SparseFileSource { | ||
130 | private: | ||
131 | char *buf; | ||
132 | int64_t offset; | ||
133 | public: | ||
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 | |||
61 | static void verbose_error(bool verbose, int err, const char *fmt, ...) | 169 | static 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 | ||
76 | static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size, | 184 | static 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 | ||
114 | static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size, | 216 | static 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 | ||
155 | static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size, | 257 | static 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 | ||
177 | static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t *crc32) | 279 | static 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 | ||
198 | static int process_chunk(struct sparse_file *s, int fd, off64_t offset, | 299 | static 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 | ||
250 | static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc) | 352 | static 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 | ||
397 | struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc) | 497 | int 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 | |||
503 | static 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 | ||
559 | struct 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 | |||
564 | struct 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 | |||
453 | struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose) | 569 | struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose) |
454 | { | 570 | { |
455 | struct sparse_file *s; | 571 | struct sparse_file *s; |