a581c457cc001b40edd71cb99318e1a530a4f53a
[project/make_ext4fs.git] / libsparse / output_file.c
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define _FILE_OFFSET_BITS 64
18 #define _LARGEFILE64_SOURCE 1
19
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <limits.h>
23 #include <stdbool.h>
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/mman.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <zlib.h>
32
33 #include "defs.h"
34 #include "output_file.h"
35 #include "sparse_crc32.h"
36 #include "sparse_format.h"
37
38 #if defined(__APPLE__) && defined(__MACH__)
39 #define lseek64 lseek
40 #define ftruncate64 ftruncate
41 #define mmap64 mmap
42 #define off64_t off_t
43 #endif
44
45 #define min(a, b) \
46         ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
47
48 #define SPARSE_HEADER_MAJOR_VER 1
49 #define SPARSE_HEADER_MINOR_VER 0
50 #define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
51 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
52
53 #define container_of(inner, outer_t, elem) \
54         ((outer_t *)((char *)inner - offsetof(outer_t, elem)))
55
56 struct output_file_ops {
57         int (*open)(struct output_file *, int fd);
58         int (*skip)(struct output_file *, int64_t);
59         int (*pad)(struct output_file *, int64_t);
60         int (*write)(struct output_file *, void *, int);
61         void (*close)(struct output_file *);
62 };
63
64 struct sparse_file_ops {
65         int (*write_data_chunk)(struct output_file *out, unsigned int len,
66                         void *data);
67         int (*write_fill_chunk)(struct output_file *out, unsigned int len,
68                         uint32_t fill_val);
69         int (*write_skip_chunk)(struct output_file *out, int64_t len);
70         int (*write_end_chunk)(struct output_file *out);
71 };
72
73 struct output_file {
74         int64_t cur_out_ptr;
75         unsigned int chunk_cnt;
76         uint32_t crc32;
77         struct output_file_ops *ops;
78         struct sparse_file_ops *sparse_ops;
79         int use_crc;
80         unsigned int block_size;
81         int64_t len;
82         char *zero_buf;
83         uint32_t *fill_buf;
84         char *buf;
85 };
86
87 struct output_file_gz {
88         struct output_file out;
89         gzFile gz_fd;
90 };
91
92 #define to_output_file_gz(_o) \
93         container_of((_o), struct output_file_gz, out)
94
95 struct output_file_normal {
96         struct output_file out;
97         int fd;
98 };
99
100 #define to_output_file_normal(_o) \
101         container_of((_o), struct output_file_normal, out)
102
103 struct output_file_callback {
104         struct output_file out;
105         void *priv;
106         int (*write)(void *priv, const void *buf, int len);
107 };
108
109 #define to_output_file_callback(_o) \
110         container_of((_o), struct output_file_callback, out)
111
112 static int file_open(struct output_file *out, int fd)
113 {
114         struct output_file_normal *outn = to_output_file_normal(out);
115
116         outn->fd = fd;
117         return 0;
118 }
119
120 static int file_skip(struct output_file *out, int64_t cnt)
121 {
122         off64_t ret;
123         struct output_file_normal *outn = to_output_file_normal(out);
124
125         ret = lseek64(outn->fd, cnt, SEEK_CUR);
126         if (ret < 0) {
127                 error_errno("lseek64");
128                 return -1;
129         }
130         return 0;
131 }
132
133 static int file_pad(struct output_file *out, int64_t len)
134 {
135         int ret;
136         struct output_file_normal *outn = to_output_file_normal(out);
137
138         ret = ftruncate64(outn->fd, len);
139         if (ret < 0) {
140                 return -errno;
141         }
142
143         return 0;
144 }
145
146 static int file_write(struct output_file *out, void *data, int len)
147 {
148         int ret;
149         struct output_file_normal *outn = to_output_file_normal(out);
150
151         ret = write(outn->fd, data, len);
152         if (ret < 0) {
153                 error_errno("write");
154                 return -1;
155         } else if (ret < len) {
156                 error("incomplete write");
157                 return -1;
158         }
159
160         return 0;
161 }
162
163 static void file_close(struct output_file *out)
164 {
165         struct output_file_normal *outn = to_output_file_normal(out);
166
167         free(outn);
168 }
169
170 static struct output_file_ops file_ops = {
171         .open = file_open,
172         .skip = file_skip,
173         .pad = file_pad,
174         .write = file_write,
175         .close = file_close,
176 };
177
178 static int gz_file_open(struct output_file *out, int fd)
179 {
180         struct output_file_gz *outgz = to_output_file_gz(out);
181
182         outgz->gz_fd = gzdopen(fd, "wb9");
183         if (!outgz->gz_fd) {
184                 error_errno("gzopen");
185                 return -errno;
186         }
187
188         return 0;
189 }
190
191
192 static int gz_file_skip(struct output_file *out, int64_t cnt)
193 {
194         off64_t ret;
195         struct output_file_gz *outgz = to_output_file_gz(out);
196
197         ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
198         if (ret < 0) {
199                 error_errno("gzseek");
200                 return -1;
201         }
202         return 0;
203 }
204
205 static int gz_file_pad(struct output_file *out, int64_t len)
206 {
207         off64_t ret;
208         struct output_file_gz *outgz = to_output_file_gz(out);
209
210         ret = gztell(outgz->gz_fd);
211         if (ret < 0) {
212                 return -1;
213         }
214
215         if (ret >= len) {
216                 return 0;
217         }
218
219         ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
220         if (ret < 0) {
221                 return -1;
222         }
223
224         gzwrite(outgz->gz_fd, "", 1);
225
226         return 0;
227 }
228
229 static int gz_file_write(struct output_file *out, void *data, int len)
230 {
231         int ret;
232         struct output_file_gz *outgz = to_output_file_gz(out);
233
234         ret = gzwrite(outgz->gz_fd, data, len);
235         if (ret < 0) {
236                 error_errno("gzwrite");
237                 return -1;
238         } else if (ret < len) {
239                 error("incomplete gzwrite");
240                 return -1;
241         }
242
243         return 0;
244 }
245
246 static void gz_file_close(struct output_file *out)
247 {
248         struct output_file_gz *outgz = to_output_file_gz(out);
249
250         gzclose(outgz->gz_fd);
251         free(outgz);
252 }
253
254 static struct output_file_ops gz_file_ops = {
255         .open = gz_file_open,
256         .skip = gz_file_skip,
257         .pad = gz_file_pad,
258         .write = gz_file_write,
259         .close = gz_file_close,
260 };
261
262 static int callback_file_open(struct output_file *out __unused, int fd __unused)
263 {
264         return 0;
265 }
266
267 static int callback_file_skip(struct output_file *out, int64_t off)
268 {
269         struct output_file_callback *outc = to_output_file_callback(out);
270         int to_write;
271         int ret;
272
273         while (off > 0) {
274                 to_write = min(off, (int64_t)INT_MAX);
275                 ret = outc->write(outc->priv, NULL, to_write);
276                 if (ret < 0) {
277                         return ret;
278                 }
279                 off -= to_write;
280         }
281
282         return 0;
283 }
284
285 static int callback_file_pad(struct output_file *out __unused, int64_t len __unused)
286 {
287         return -1;
288 }
289
290 static int callback_file_write(struct output_file *out, void *data, int len)
291 {
292         struct output_file_callback *outc = to_output_file_callback(out);
293
294         return outc->write(outc->priv, data, len);
295 }
296
297 static void callback_file_close(struct output_file *out)
298 {
299         struct output_file_callback *outc = to_output_file_callback(out);
300
301         free(outc);
302 }
303
304 static struct output_file_ops callback_file_ops = {
305         .open = callback_file_open,
306         .skip = callback_file_skip,
307         .pad = callback_file_pad,
308         .write = callback_file_write,
309         .close = callback_file_close,
310 };
311
312 int read_all(int fd, void *buf, size_t len)
313 {
314         size_t total = 0;
315         int ret;
316         char *ptr = buf;
317
318         while (total < len) {
319                 ret = read(fd, ptr, len - total);
320
321                 if (ret < 0)
322                         return -errno;
323
324                 if (ret == 0)
325                         return -EINVAL;
326
327                 ptr += ret;
328                 total += ret;
329         }
330
331         return 0;
332 }
333
334 static int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len)
335 {
336         chunk_header_t chunk_header;
337         int ret;
338
339         if (skip_len % out->block_size) {
340                 error("don't care size %"PRIi64" is not a multiple of the block size %u",
341                                 skip_len, out->block_size);
342                 return -1;
343         }
344
345         /* We are skipping data, so emit a don't care chunk. */
346         chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE;
347         chunk_header.reserved1 = 0;
348         chunk_header.chunk_sz = skip_len / out->block_size;
349         chunk_header.total_sz = CHUNK_HEADER_LEN;
350         ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
351         if (ret < 0)
352                 return -1;
353
354         out->cur_out_ptr += skip_len;
355         out->chunk_cnt++;
356
357         return 0;
358 }
359
360 static int write_sparse_fill_chunk(struct output_file *out, unsigned int len,
361                 uint32_t fill_val)
362 {
363         chunk_header_t chunk_header;
364         int rnd_up_len, count;
365         int ret;
366
367         /* Round up the fill length to a multiple of the block size */
368         rnd_up_len = ALIGN(len, out->block_size);
369
370         /* Finally we can safely emit a chunk of data */
371         chunk_header.chunk_type = CHUNK_TYPE_FILL;
372         chunk_header.reserved1 = 0;
373         chunk_header.chunk_sz = rnd_up_len / out->block_size;
374         chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val);
375         ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
376
377         if (ret < 0)
378                 return -1;
379         ret = out->ops->write(out, &fill_val, sizeof(fill_val));
380         if (ret < 0)
381                 return -1;
382
383         if (out->use_crc) {
384                 count = out->block_size / sizeof(uint32_t);
385                 while (count--)
386                         out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t));
387         }
388
389         out->cur_out_ptr += rnd_up_len;
390         out->chunk_cnt++;
391
392         return 0;
393 }
394
395 static int write_sparse_data_chunk(struct output_file *out, unsigned int len,
396                 void *data)
397 {
398         chunk_header_t chunk_header;
399         int rnd_up_len, zero_len;
400         int ret;
401
402         /* Round up the data length to a multiple of the block size */
403         rnd_up_len = ALIGN(len, out->block_size);
404         zero_len = rnd_up_len - len;
405
406         /* Finally we can safely emit a chunk of data */
407         chunk_header.chunk_type = CHUNK_TYPE_RAW;
408         chunk_header.reserved1 = 0;
409         chunk_header.chunk_sz = rnd_up_len / out->block_size;
410         chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
411         ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
412
413         if (ret < 0)
414                 return -1;
415         ret = out->ops->write(out, data, len);
416         if (ret < 0)
417                 return -1;
418         if (zero_len) {
419                 ret = out->ops->write(out, out->zero_buf, zero_len);
420                 if (ret < 0)
421                         return -1;
422         }
423
424         if (out->use_crc) {
425                 out->crc32 = sparse_crc32(out->crc32, data, len);
426                 if (zero_len)
427                         out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
428         }
429
430         out->cur_out_ptr += rnd_up_len;
431         out->chunk_cnt++;
432
433         return 0;
434 }
435
436 int write_sparse_end_chunk(struct output_file *out)
437 {
438         chunk_header_t chunk_header;
439         int ret;
440
441         if (out->use_crc) {
442                 chunk_header.chunk_type = CHUNK_TYPE_CRC32;
443                 chunk_header.reserved1 = 0;
444                 chunk_header.chunk_sz = 0;
445                 chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
446
447                 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
448                 if (ret < 0) {
449                         return ret;
450                 }
451                 out->ops->write(out, &out->crc32, 4);
452                 if (ret < 0) {
453                         return ret;
454                 }
455
456                 out->chunk_cnt++;
457         }
458
459         return 0;
460 }
461
462 static struct sparse_file_ops sparse_file_ops = {
463                 .write_data_chunk = write_sparse_data_chunk,
464                 .write_fill_chunk = write_sparse_fill_chunk,
465                 .write_skip_chunk = write_sparse_skip_chunk,
466                 .write_end_chunk = write_sparse_end_chunk,
467 };
468
469 static int write_normal_data_chunk(struct output_file *out, unsigned int len,
470                 void *data)
471 {
472         int ret;
473         unsigned int rnd_up_len = ALIGN(len, out->block_size);
474
475         ret = out->ops->write(out, data, len);
476         if (ret < 0) {
477                 return ret;
478         }
479
480         if (rnd_up_len > len) {
481                 ret = out->ops->skip(out, rnd_up_len - len);
482         }
483
484         return ret;
485 }
486
487 static int write_normal_fill_chunk(struct output_file *out, unsigned int len,
488                 uint32_t fill_val)
489 {
490         int ret;
491         unsigned int i;
492         unsigned int write_len;
493
494         /* Initialize fill_buf with the fill_val */
495         for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
496                 out->fill_buf[i] = fill_val;
497         }
498
499         while (len) {
500                 write_len = min(len, out->block_size);
501                 ret = out->ops->write(out, out->fill_buf, write_len);
502                 if (ret < 0) {
503                         return ret;
504                 }
505
506                 len -= write_len;
507         }
508
509         return 0;
510 }
511
512 static int write_normal_skip_chunk(struct output_file *out, int64_t len)
513 {
514         return out->ops->skip(out, len);
515 }
516
517 int write_normal_end_chunk(struct output_file *out)
518 {
519         return out->ops->pad(out, out->len);
520 }
521
522 static struct sparse_file_ops normal_file_ops = {
523                 .write_data_chunk = write_normal_data_chunk,
524                 .write_fill_chunk = write_normal_fill_chunk,
525                 .write_skip_chunk = write_normal_skip_chunk,
526                 .write_end_chunk = write_normal_end_chunk,
527 };
528
529 void output_file_close(struct output_file *out)
530 {
531         out->sparse_ops->write_end_chunk(out);
532         out->ops->close(out);
533 }
534
535 static int output_file_init(struct output_file *out, int block_size,
536                 int64_t len, bool sparse, int chunks, bool crc)
537 {
538         int ret;
539
540         out->len = len;
541         out->block_size = block_size;
542         out->cur_out_ptr = 0ll;
543         out->chunk_cnt = 0;
544         out->crc32 = 0;
545         out->use_crc = crc;
546
547         out->zero_buf = calloc(block_size, 1);
548         if (!out->zero_buf) {
549                 error_errno("malloc zero_buf");
550                 return -ENOMEM;
551         }
552
553         out->fill_buf = calloc(block_size, 1);
554         if (!out->fill_buf) {
555                 error_errno("malloc fill_buf");
556                 ret = -ENOMEM;
557                 goto err_fill_buf;
558         }
559
560         if (sparse) {
561                 out->sparse_ops = &sparse_file_ops;
562         } else {
563                 out->sparse_ops = &normal_file_ops;
564         }
565
566         if (sparse) {
567                 sparse_header_t sparse_header = {
568                                 .magic = SPARSE_HEADER_MAGIC,
569                                 .major_version = SPARSE_HEADER_MAJOR_VER,
570                                 .minor_version = SPARSE_HEADER_MINOR_VER,
571                                 .file_hdr_sz = SPARSE_HEADER_LEN,
572                                 .chunk_hdr_sz = CHUNK_HEADER_LEN,
573                                 .blk_sz = out->block_size,
574                                 .total_blks = out->len / out->block_size,
575                                 .total_chunks = chunks,
576                                 .image_checksum = 0
577                 };
578
579                 if (out->use_crc) {
580                         sparse_header.total_chunks++;
581                 }
582
583                 ret = out->ops->write(out, &sparse_header, sizeof(sparse_header));
584                 if (ret < 0) {
585                         goto err_write;
586                 }
587         }
588
589         return 0;
590
591 err_write:
592         free(out->fill_buf);
593 err_fill_buf:
594         free(out->zero_buf);
595         return ret;
596 }
597
598 static struct output_file *output_file_new_gz(void)
599 {
600         struct output_file_gz *outgz = calloc(1, sizeof(struct output_file_gz));
601         if (!outgz) {
602                 error_errno("malloc struct outgz");
603                 return NULL;
604         }
605
606         outgz->out.ops = &gz_file_ops;
607
608         return &outgz->out;
609 }
610
611 static struct output_file *output_file_new_normal(void)
612 {
613         struct output_file_normal *outn = calloc(1, sizeof(struct output_file_normal));
614         if (!outn) {
615                 error_errno("malloc struct outn");
616                 return NULL;
617         }
618
619         outn->out.ops = &file_ops;
620
621         return &outn->out;
622 }
623
624 struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
625                 void *priv, unsigned int block_size, int64_t len,
626                 int gz __unused, int sparse, int chunks, int crc)
627 {
628         int ret;
629         struct output_file_callback *outc;
630
631         outc = calloc(1, sizeof(struct output_file_callback));
632         if (!outc) {
633                 error_errno("malloc struct outc");
634                 return NULL;
635         }
636
637         outc->out.ops = &callback_file_ops;
638         outc->priv = priv;
639         outc->write = write;
640
641         ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
642         if (ret < 0) {
643                 free(outc);
644                 return NULL;
645         }
646
647         return &outc->out;
648 }
649
650 struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len,
651                 int gz, int sparse, int chunks, int crc)
652 {
653         int ret;
654         struct output_file *out;
655
656         if (gz) {
657                 out = output_file_new_gz();
658         } else {
659                 out = output_file_new_normal();
660         }
661         if (!out) {
662                 return NULL;
663         }
664
665         out->ops->open(out, fd);
666
667         ret = output_file_init(out, block_size, len, sparse, chunks, crc);
668         if (ret < 0) {
669                 free(out);
670                 return NULL;
671         }
672
673         return out;
674 }
675
676 /* Write a contiguous region of data blocks from a memory buffer */
677 int write_data_chunk(struct output_file *out, unsigned int len, void *data)
678 {
679         return out->sparse_ops->write_data_chunk(out, len, data);
680 }
681
682 /* Write a contiguous region of data blocks with a fill value */
683 int write_fill_chunk(struct output_file *out, unsigned int len,
684                 uint32_t fill_val)
685 {
686         return out->sparse_ops->write_fill_chunk(out, len, fill_val);
687 }
688
689 int write_fd_chunk(struct output_file *out, unsigned int len,
690                 int fd, int64_t offset)
691 {
692         int ret;
693         int64_t aligned_offset;
694         int aligned_diff;
695         int buffer_size;
696         char *ptr;
697
698         aligned_offset = offset & ~(4096 - 1);
699         aligned_diff = offset - aligned_offset;
700         buffer_size = len + aligned_diff;
701
702         char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd,
703                         aligned_offset);
704         if (data == MAP_FAILED) {
705                 return -errno;
706         }
707         ptr = data + aligned_diff;
708
709         ret = out->sparse_ops->write_data_chunk(out, len, ptr);
710
711         munmap(data, buffer_size);
712
713         return ret;
714 }
715
716 /* Write a contiguous region of data blocks from a file */
717 int write_file_chunk(struct output_file *out, unsigned int len,
718                 const char *file, int64_t offset)
719 {
720         int ret;
721
722         int file_fd = open(file, O_RDONLY);
723         if (file_fd < 0) {
724                 return -errno;
725         }
726
727         ret = write_fd_chunk(out, len, file_fd, offset);
728
729         close(file_fd);
730
731         return ret;
732 }
733
734 int write_skip_chunk(struct output_file *out, int64_t len)
735 {
736         return out->sparse_ops->write_skip_chunk(out, len);
737 }