summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross2012-05-18 16:49:50 -0500
committerColin Cross2012-07-10 00:09:37 -0500
commitb4cd267db30c152245e6308598e0066d87c5c55d (patch)
treee888dfa52c033e91247daa5ad33c77696bfe6ff4 /libsparse
parent0c4c47f88dfc15cada154a1cf9b4db88b49890f0 (diff)
downloadplatform-system-core-b4cd267db30c152245e6308598e0066d87c5c55d.tar.gz
platform-system-core-b4cd267db30c152245e6308598e0066d87c5c55d.tar.xz
platform-system-core-b4cd267db30c152245e6308598e0066d87c5c55d.zip
libsparse: pseudo-subclass output_file for normal and gz files
Create two subclasses of output_file that can handle normal and gzipped files, and refactor open_output_fd. Will allow adding support for an output_file type that is not file backed. Change-Id: I26744c74d13f205cf17df1ea9caac1eea9c57357
Diffstat (limited to 'libsparse')
-rw-r--r--libsparse/output_file.c236
-rw-r--r--libsparse/output_file.h3
2 files changed, 158 insertions, 81 deletions
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5e8a68c54..14b057a9e 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -19,6 +19,7 @@
19 19
20#include <fcntl.h> 20#include <fcntl.h>
21#include <stdbool.h> 21#include <stdbool.h>
22#include <stddef.h>
22#include <stdlib.h> 23#include <stdlib.h>
23#include <string.h> 24#include <string.h>
24#include <sys/stat.h> 25#include <sys/stat.h>
@@ -33,6 +34,8 @@
33#ifndef USE_MINGW 34#ifndef USE_MINGW
34#include <sys/mman.h> 35#include <sys/mman.h>
35#define O_BINARY 0 36#define O_BINARY 0
37#else
38#define ftruncate64 ftruncate
36#endif 39#endif
37 40
38#if defined(__APPLE__) && defined(__MACH__) 41#if defined(__APPLE__) && defined(__MACH__)
@@ -59,8 +62,13 @@ static inline void *mmap64(void *addr, size_t length, int prot, int flags,
59#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 62#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
60#define CHUNK_HEADER_LEN (sizeof(chunk_header_t)) 63#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
61 64
65#define container_of(inner, outer_t, elem) \
66 ((outer_t *)((char *)inner - offsetof(outer_t, elem)))
67
62struct output_file_ops { 68struct output_file_ops {
69 int (*open)(struct output_file *, int fd);
63 int (*skip)(struct output_file *, int64_t); 70 int (*skip)(struct output_file *, int64_t);
71 int (*pad)(struct output_file *, int64_t);
64 int (*write)(struct output_file *, void *, int); 72 int (*write)(struct output_file *, void *, int);
65 void (*close)(struct output_file *); 73 void (*close)(struct output_file *);
66}; 74};
@@ -75,9 +83,6 @@ struct sparse_file_ops {
75}; 83};
76 84
77struct output_file { 85struct output_file {
78 int fd;
79 gzFile gz_fd;
80 bool close_fd;
81 int64_t cur_out_ptr; 86 int64_t cur_out_ptr;
82 unsigned int chunk_cnt; 87 unsigned int chunk_cnt;
83 uint32_t crc32; 88 uint32_t crc32;
@@ -88,13 +93,39 @@ struct output_file {
88 int64_t len; 93 int64_t len;
89 char *zero_buf; 94 char *zero_buf;
90 uint32_t *fill_buf; 95 uint32_t *fill_buf;
96 char *buf;
97};
98
99struct output_file_gz {
100 struct output_file out;
101 gzFile gz_fd;
91}; 102};
92 103
104#define to_output_file_gz(_o) \
105 container_of((_o), struct output_file_gz, out)
106
107struct output_file_normal {
108 struct output_file out;
109 int fd;
110};
111
112#define to_output_file_normal(_o) \
113 container_of((_o), struct output_file_normal, out)
114
115static int file_open(struct output_file *out, int fd)
116{
117 struct output_file_normal *outn = to_output_file_normal(out);
118
119 outn->fd = fd;
120 return 0;
121}
122
93static int file_skip(struct output_file *out, int64_t cnt) 123static int file_skip(struct output_file *out, int64_t cnt)
94{ 124{
95 off64_t ret; 125 off64_t ret;
126 struct output_file_normal *outn = to_output_file_normal(out);
96 127
97 ret = lseek64(out->fd, cnt, SEEK_CUR); 128 ret = lseek64(outn->fd, cnt, SEEK_CUR);
98 if (ret < 0) { 129 if (ret < 0) {
99 error_errno("lseek64"); 130 error_errno("lseek64");
100 return -1; 131 return -1;
@@ -102,10 +133,25 @@ static int file_skip(struct output_file *out, int64_t cnt)
102 return 0; 133 return 0;
103} 134}
104 135
136static int file_pad(struct output_file *out, int64_t len)
137{
138 int ret;
139 struct output_file_normal *outn = to_output_file_normal(out);
140
141 ret = ftruncate64(outn->fd, len);
142 if (ret < 0) {
143 return -errno;
144 }
145
146 return 0;
147}
148
105static int file_write(struct output_file *out, void *data, int len) 149static int file_write(struct output_file *out, void *data, int len)
106{ 150{
107 int ret; 151 int ret;
108 ret = write(out->fd, data, len); 152 struct output_file_normal *outn = to_output_file_normal(out);
153
154 ret = write(outn->fd, data, len);
109 if (ret < 0) { 155 if (ret < 0) {
110 error_errno("write"); 156 error_errno("write");
111 return -1; 157 return -1;
@@ -119,22 +165,39 @@ static int file_write(struct output_file *out, void *data, int len)
119 165
120static void file_close(struct output_file *out) 166static void file_close(struct output_file *out)
121{ 167{
122 if (out->close_fd) { 168 struct output_file_normal *outn = to_output_file_normal(out);
123 close(out->fd); 169
124 } 170 free(outn);
125} 171}
126 172
127static struct output_file_ops file_ops = { 173static struct output_file_ops file_ops = {
174 .open = file_open,
128 .skip = file_skip, 175 .skip = file_skip,
176 .pad = file_pad,
129 .write = file_write, 177 .write = file_write,
130 .close = file_close, 178 .close = file_close,
131}; 179};
132 180
181static int gz_file_open(struct output_file *out, int fd)
182{
183 struct output_file_gz *outgz = to_output_file_gz(out);
184
185 outgz->gz_fd = gzdopen(fd, "wb9");
186 if (!outgz->gz_fd) {
187 error_errno("gzopen");
188 return -errno;
189 }
190
191 return 0;
192}
193
194
133static int gz_file_skip(struct output_file *out, int64_t cnt) 195static int gz_file_skip(struct output_file *out, int64_t cnt)
134{ 196{
135 off64_t ret; 197 off64_t ret;
198 struct output_file_gz *outgz = to_output_file_gz(out);
136 199
137 ret = gzseek(out->gz_fd, cnt, SEEK_CUR); 200 ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
138 if (ret < 0) { 201 if (ret < 0) {
139 error_errno("gzseek"); 202 error_errno("gzseek");
140 return -1; 203 return -1;
@@ -142,10 +205,36 @@ static int gz_file_skip(struct output_file *out, int64_t cnt)
142 return 0; 205 return 0;
143} 206}
144 207
208static int gz_file_pad(struct output_file *out, int64_t len)
209{
210 off64_t ret;
211 struct output_file_gz *outgz = to_output_file_gz(out);
212
213 ret = gztell(outgz->gz_fd);
214 if (ret < 0) {
215 return -1;
216 }
217
218 if (ret >= len) {
219 return 0;
220 }
221
222 ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
223 if (ret < 0) {
224 return -1;
225 }
226
227 gzwrite(outgz->gz_fd, "", 1);
228
229 return 0;
230}
231
145static int gz_file_write(struct output_file *out, void *data, int len) 232static int gz_file_write(struct output_file *out, void *data, int len)
146{ 233{
147 int ret; 234 int ret;
148 ret = gzwrite(out->gz_fd, data, len); 235 struct output_file_gz *outgz = to_output_file_gz(out);
236
237 ret = gzwrite(outgz->gz_fd, data, len);
149 if (ret < 0) { 238 if (ret < 0) {
150 error_errno("gzwrite"); 239 error_errno("gzwrite");
151 return -1; 240 return -1;
@@ -159,11 +248,16 @@ static int gz_file_write(struct output_file *out, void *data, int len)
159 248
160static void gz_file_close(struct output_file *out) 249static void gz_file_close(struct output_file *out)
161{ 250{
162 gzclose(out->gz_fd); 251 struct output_file_gz *outgz = to_output_file_gz(out);
252
253 gzclose(outgz->gz_fd);
254 free(outgz);
163} 255}
164 256
165static struct output_file_ops gz_file_ops = { 257static struct output_file_ops gz_file_ops = {
258 .open = gz_file_open,
166 .skip = gz_file_skip, 259 .skip = gz_file_skip,
260 .pad = gz_file_pad,
167 .write = gz_file_write, 261 .write = gz_file_write,
168 .close = gz_file_close, 262 .close = gz_file_close,
169}; 263};
@@ -371,21 +465,12 @@ static int write_normal_fill_chunk(struct output_file *out, unsigned int len,
371 465
372static int write_normal_skip_chunk(struct output_file *out, int64_t len) 466static int write_normal_skip_chunk(struct output_file *out, int64_t len)
373{ 467{
374 int ret;
375
376 return out->ops->skip(out, len); 468 return out->ops->skip(out, len);
377} 469}
378 470
379int write_normal_end_chunk(struct output_file *out) 471int write_normal_end_chunk(struct output_file *out)
380{ 472{
381 int ret; 473 return out->ops->pad(out, out->len);
382
383 ret = ftruncate64(out->fd, out->len);
384 if (ret < 0) {
385 return -errno;
386 }
387
388 return 0;
389} 474}
390 475
391static struct sparse_file_ops normal_file_ops = { 476static struct sparse_file_ops normal_file_ops = {
@@ -401,59 +486,39 @@ void close_output_file(struct output_file *out)
401 486
402 out->sparse_ops->write_end_chunk(out); 487 out->sparse_ops->write_end_chunk(out);
403 out->ops->close(out); 488 out->ops->close(out);
404 free(out);
405} 489}
406 490
407struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, 491static int output_file_init(struct output_file *out, int block_size,
408 int gz, int sparse, int chunks, int crc) 492 int64_t len, bool sparse, int chunks, bool crc)
409{ 493{
410 int ret; 494 int ret;
411 struct output_file *out = malloc(sizeof(struct output_file)); 495
412 if (!out) { 496 out->len = len;
413 error_errno("malloc struct out"); 497 out->block_size = block_size;
414 return NULL; 498 out->cur_out_ptr = 0ll;
415 } 499 out->chunk_cnt = 0;
500 out->crc32 = 0;
501 out->use_crc = crc;
502
416 out->zero_buf = calloc(block_size, 1); 503 out->zero_buf = calloc(block_size, 1);
417 if (!out->zero_buf) { 504 if (!out->zero_buf) {
418 error_errno("malloc zero_buf"); 505 error_errno("malloc zero_buf");
419 goto err_zero_buf; 506 return -ENOMEM;
420 } 507 }
421 508
422 out->fill_buf = calloc(block_size, 1); 509 out->fill_buf = calloc(block_size, 1);
423 if (!out->fill_buf) { 510 if (!out->fill_buf) {
424 error_errno("malloc fill_buf"); 511 error_errno("malloc fill_buf");
512 ret = -ENOMEM;
425 goto err_fill_buf; 513 goto err_fill_buf;
426 } 514 }
427 515
428 if (gz) {
429 out->ops = &gz_file_ops;
430 out->gz_fd = gzdopen(fd, "wb9");
431 if (!out->gz_fd) {
432 error_errno("gzopen");
433 goto err_gzopen;
434 }
435 } else {
436 out->fd = fd;
437 out->ops = &file_ops;
438 }
439
440 if (sparse) { 516 if (sparse) {
441 out->sparse_ops = &sparse_file_ops; 517 out->sparse_ops = &sparse_file_ops;
442 } else { 518 } else {
443 out->sparse_ops = &normal_file_ops; 519 out->sparse_ops = &normal_file_ops;
444 } 520 }
445 521
446 out->close_fd = false;
447 out->cur_out_ptr = 0ll;
448 out->chunk_cnt = 0;
449
450 /* Initialize the crc32 value */
451 out->crc32 = 0;
452 out->use_crc = crc;
453
454 out->len = len;
455 out->block_size = block_size;
456
457 if (sparse) { 522 if (sparse) {
458 sparse_header_t sparse_header = { 523 sparse_header_t sparse_header = {
459 .magic = SPARSE_HEADER_MAGIC, 524 .magic = SPARSE_HEADER_MAGIC,
@@ -477,47 +542,62 @@ struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
477 } 542 }
478 } 543 }
479 544
480 return out; 545 return 0;
481 546
482err_write: 547err_write:
483 if (gz) {
484 gzclose(out->gz_fd);
485 }
486err_gzopen:
487 free(out->fill_buf); 548 free(out->fill_buf);
488err_fill_buf: 549err_fill_buf:
489 free(out->zero_buf); 550 free(out->zero_buf);
490err_zero_buf: 551 return ret;
491 free(out); 552}
492 return NULL; 553
554static struct output_file *output_file_new_gz(void)
555{
556 struct output_file_gz *outgz = calloc(1, sizeof(struct output_file_gz));
557 if (!outgz) {
558 error_errno("malloc struct outgz");
559 return NULL;
560 }
561
562 outgz->out.ops = &gz_file_ops;
563
564 return &outgz->out;
565}
566
567static struct output_file *output_file_new_normal(void)
568{
569 struct output_file_normal *outn = calloc(1, sizeof(struct output_file_normal));
570 if (!outn) {
571 error_errno("malloc struct outn");
572 return NULL;
573 }
574
575 outn->out.ops = &file_ops;
576
577 return &outn->out;
493} 578}
494 579
495struct output_file *open_output_file(const char *filename, 580struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
496 unsigned int block_size, int64_t len,
497 int gz, int sparse, int chunks, int crc) 581 int gz, int sparse, int chunks, int crc)
498{ 582{
499 int fd; 583 int ret;
500 struct output_file *file; 584 struct output_file *out;
501 585
502 if (strcmp(filename, "-")) { 586 if (gz) {
503 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); 587 out = output_file_new_gz();
504 if (fd < 0) {
505 error_errno("open");
506 return NULL;
507 }
508 } else { 588 } else {
509 fd = STDOUT_FILENO; 589 out = output_file_new_normal();
510 } 590 }
511 591
512 file = open_output_fd(fd, block_size, len, gz, sparse, chunks, crc); 592 out->ops->open(out, fd);
513 if (!file) { 593
514 close(fd); 594 ret = output_file_init(out, block_size, len, sparse, chunks, crc);
595 if (ret < 0) {
596 free(out);
515 return NULL; 597 return NULL;
516 } 598 }
517 599
518 file->close_fd = true; // we opened descriptor thus we responsible for closing it 600 return out;
519
520 return file;
521} 601}
522 602
523/* Write a contiguous region of data blocks from a memory buffer */ 603/* Write a contiguous region of data blocks from a memory buffer */
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index b86528b44..24496f7d4 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -21,9 +21,6 @@
21 21
22struct output_file; 22struct output_file;
23 23
24struct output_file *open_output_file(const char *filename,
25 unsigned int block_size, int64_t len,
26 int gz, int sparse, int chunks, int crc);
27struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, 24struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
28 int gz, int sparse, int chunks, int crc); 25 int gz, int sparse, int chunks, int crc);
29int write_data_chunk(struct output_file *out, unsigned int len, void *data); 26int write_data_chunk(struct output_file *out, unsigned int len, void *data);