output_file.c revision b4cd267db30c152245e6308598e0066d87c5c55d
128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/*
228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Copyright (C) 2010 The Android Open Source Project
328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross *
428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Licensed under the Apache License, Version 2.0 (the "License");
528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * you may not use this file except in compliance with the License.
628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * You may obtain a copy of the License at
728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross *
828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross *      http://www.apache.org/licenses/LICENSE-2.0
928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross *
1028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Unless required by applicable law or agreed to in writing, software
1128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * distributed under the License is distributed on an "AS IS" BASIS,
1228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * See the License for the specific language governing permissions and
1428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * limitations under the License.
1528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross */
1628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
1728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define _FILE_OFFSET_BITS 64
1828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define _LARGEFILE64_SOURCE 1
1928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
2028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <fcntl.h>
2128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdbool.h>
22b4cd267db30c152245e6308598e0066d87c5c55dColin Cross#include <stddef.h>
2328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdlib.h>
2428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <string.h>
2528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/stat.h>
2628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/types.h>
2728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <unistd.h>
2828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <zlib.h>
2928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
3028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "output_file.h"
3128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_format.h"
3228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_crc32.h"
3328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
3428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW
3528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/mman.h>
3628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define O_BINARY 0
37b4cd267db30c152245e6308598e0066d87c5c55dColin Cross#else
38b4cd267db30c152245e6308598e0066d87c5c55dColin Cross#define ftruncate64 ftruncate
3928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif
4028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
4128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#if defined(__APPLE__) && defined(__MACH__)
4228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define lseek64 lseek
4328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define ftruncate64 ftruncate
4428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define mmap64 mmap
4528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define off64_t off_t
4628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif
4728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
4828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifdef __BIONIC__
4928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossextern void*  __mmap2(void *, size_t, int, int, int, off_t);
5028fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic inline void *mmap64(void *addr, size_t length, int prot, int flags,
5128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross        int fd, off64_t offset)
5228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
5328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross    return __mmap2(addr, length, prot, flags, fd, offset >> 12);
5428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
5528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif
5628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
57b55dceea986ab24f8b836b5116b389ed619c816eColin Cross#define min(a, b) \
58b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
59b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
6028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_MAJOR_VER 1
6128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_MINOR_VER 0
6228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
6328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
6428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
65b4cd267db30c152245e6308598e0066d87c5c55dColin Cross#define container_of(inner, outer_t, elem) \
66b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	((outer_t *)((char *)inner - offsetof(outer_t, elem)))
67b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
6828fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file_ops {
69b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	int (*open)(struct output_file *, int fd);
70b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int (*skip)(struct output_file *, int64_t);
71b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	int (*pad)(struct output_file *, int64_t);
72b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int (*write)(struct output_file *, void *, int);
7328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	void (*close)(struct output_file *);
7428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross};
7528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
76b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstruct sparse_file_ops {
77b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int (*write_data_chunk)(struct output_file *out, unsigned int len,
78b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			void *data);
79b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int (*write_fill_chunk)(struct output_file *out, unsigned int len,
80b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			uint32_t fill_val);
81b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int (*write_skip_chunk)(struct output_file *out, int64_t len);
82b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int (*write_end_chunk)(struct output_file *out);
83b55dceea986ab24f8b836b5116b389ed619c816eColin Cross};
84b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
8528fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file {
8628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int64_t cur_out_ptr;
87b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	unsigned int chunk_cnt;
88b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	uint32_t crc32;
8928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	struct output_file_ops *ops;
90b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	struct sparse_file_ops *sparse_ops;
9128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int use_crc;
9228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	unsigned int block_size;
9328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int64_t len;
94b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	char *zero_buf;
95b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	uint32_t *fill_buf;
96b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	char *buf;
97b4cd267db30c152245e6308598e0066d87c5c55dColin Cross};
98b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
99b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstruct output_file_gz {
100b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file out;
101b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	gzFile gz_fd;
102b4cd267db30c152245e6308598e0066d87c5c55dColin Cross};
103b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
104b4cd267db30c152245e6308598e0066d87c5c55dColin Cross#define to_output_file_gz(_o) \
105b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	container_of((_o), struct output_file_gz, out)
106b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
107b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstruct output_file_normal {
108b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file out;
109b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	int fd;
11028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross};
11128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
112b4cd267db30c152245e6308598e0066d87c5c55dColin Cross#define to_output_file_normal(_o) \
113b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	container_of((_o), struct output_file_normal, out)
114b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
115b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic int file_open(struct output_file *out, int fd)
116b4cd267db30c152245e6308598e0066d87c5c55dColin Cross{
117b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_normal *outn = to_output_file_normal(out);
118b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
119b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	outn->fd = fd;
120b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return 0;
121b4cd267db30c152245e6308598e0066d87c5c55dColin Cross}
122b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
123b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int file_skip(struct output_file *out, int64_t cnt)
12428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
12528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	off64_t ret;
126b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_normal *outn = to_output_file_normal(out);
12728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
128b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = lseek64(outn->fd, cnt, SEEK_CUR);
12928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0) {
13028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error_errno("lseek64");
13128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
13228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
13328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
13428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
13528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
136b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic int file_pad(struct output_file *out, int64_t len)
137b4cd267db30c152245e6308598e0066d87c5c55dColin Cross{
138b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	int ret;
139b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_normal *outn = to_output_file_normal(out);
140b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
141b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = ftruncate64(outn->fd, len);
142b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (ret < 0) {
143b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return -errno;
144b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
145b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
146b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return 0;
147b4cd267db30c152245e6308598e0066d87c5c55dColin Cross}
148b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
149b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int file_write(struct output_file *out, void *data, int len)
15028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
15128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret;
152b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_normal *outn = to_output_file_normal(out);
153b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
154b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = write(outn->fd, data, len);
15528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0) {
15628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error_errno("write");
15728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
15828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	} else if (ret < len) {
15928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error("incomplete write");
16028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
16128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
16228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
16328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
16428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
16528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
16628fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void file_close(struct output_file *out)
16728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
168b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_normal *outn = to_output_file_normal(out);
169b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
170b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	free(outn);
17128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
17228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
17328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic struct output_file_ops file_ops = {
174b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	.open = file_open,
175b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	.skip = file_skip,
176b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	.pad = file_pad,
17728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	.write = file_write,
17828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	.close = file_close,
17928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross};
18028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
181b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic int gz_file_open(struct output_file *out, int fd)
182b4cd267db30c152245e6308598e0066d87c5c55dColin Cross{
183b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_gz *outgz = to_output_file_gz(out);
184b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
185b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	outgz->gz_fd = gzdopen(fd, "wb9");
186b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (!outgz->gz_fd) {
187b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		error_errno("gzopen");
188b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return -errno;
189b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
190b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
191b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return 0;
192b4cd267db30c152245e6308598e0066d87c5c55dColin Cross}
193b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
194b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
195b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int gz_file_skip(struct output_file *out, int64_t cnt)
19628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
19728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	off64_t ret;
198b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_gz *outgz = to_output_file_gz(out);
19928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
200b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
20128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0) {
20228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error_errno("gzseek");
20328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
20428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
20528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
20628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
20728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
208b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic int gz_file_pad(struct output_file *out, int64_t len)
209b4cd267db30c152245e6308598e0066d87c5c55dColin Cross{
210b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	off64_t ret;
211b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_gz *outgz = to_output_file_gz(out);
212b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
213b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = gztell(outgz->gz_fd);
214b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (ret < 0) {
215b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return -1;
216b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
217b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
218b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (ret >= len) {
219b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return 0;
220b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
221b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
222b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
223b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (ret < 0) {
224b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return -1;
225b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
226b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
227b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	gzwrite(outgz->gz_fd, "", 1);
228b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
229b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return 0;
230b4cd267db30c152245e6308598e0066d87c5c55dColin Cross}
231b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
232b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int gz_file_write(struct output_file *out, void *data, int len)
23328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
23428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret;
235b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_gz *outgz = to_output_file_gz(out);
236b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
237b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = gzwrite(outgz->gz_fd, data, len);
23828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0) {
23928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error_errno("gzwrite");
24028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
24128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	} else if (ret < len) {
24228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error("incomplete gzwrite");
24328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
24428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
24528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
24628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
24728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
24828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
24928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void gz_file_close(struct output_file *out)
25028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
251b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_gz *outgz = to_output_file_gz(out);
252b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
253b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	gzclose(outgz->gz_fd);
254b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	free(outgz);
25528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
25628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
25728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic struct output_file_ops gz_file_ops = {
258b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	.open = gz_file_open,
259b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	.skip = gz_file_skip,
260b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	.pad = gz_file_pad,
26128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	.write = gz_file_write,
26228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	.close = gz_file_close,
26328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross};
26428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
26513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Crossint read_all(int fd, void *buf, size_t len)
26613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross{
26713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	size_t total = 0;
26813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	int ret;
26913a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	char *ptr = buf;
27013a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross
27113a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	while (total < len) {
27213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		ret = read(fd, ptr, len - total);
27313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross
27413a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		if (ret < 0)
27513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross			return -errno;
27613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross
27713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		if (ret == 0)
27813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross			return -EINVAL;
27913a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross
28013a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		ptr += ret;
28113a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		total += ret;
28213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	}
28313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross
28413a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	return 0;
28513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross}
28613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross
287b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len)
28828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
28928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header_t chunk_header;
29028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret, chunk;
29128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
29228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (skip_len % out->block_size) {
29328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error("don't care size %llu is not a multiple of the block size %u",
29428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross				skip_len, out->block_size);
29528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
29628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
29728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
29828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	/* We are skipping data, so emit a don't care chunk. */
29928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE;
30028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.reserved1 = 0;
30128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.chunk_sz = skip_len / out->block_size;
30228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.total_sz = CHUNK_HEADER_LEN;
303b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
30428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0)
30528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
30628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
30728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->cur_out_ptr += skip_len;
30828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->chunk_cnt++;
30928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
31028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
31128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
31228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
313b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_sparse_fill_chunk(struct output_file *out, unsigned int len,
314b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		uint32_t fill_val)
31528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
31628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header_t chunk_header;
31728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int rnd_up_len, zero_len, count;
31828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret;
31928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	unsigned int i;
32028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
321b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	/* Round up the fill length to a multiple of the block size */
322b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	rnd_up_len = ALIGN(len, out->block_size);
32328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
32428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	/* Finally we can safely emit a chunk of data */
32528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.chunk_type = CHUNK_TYPE_FILL;
32628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.reserved1 = 0;
32728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.chunk_sz = rnd_up_len / out->block_size;
32828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val);
329b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
33028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
33128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0)
33228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
333b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	ret = out->ops->write(out, &fill_val, sizeof(fill_val));
33428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0)
33528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
33628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
33728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (out->use_crc) {
338b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		count = out->block_size / sizeof(uint32_t);
339b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		while (count--)
340b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t));
34128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
34228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
34328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->cur_out_ptr += rnd_up_len;
34428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->chunk_cnt++;
34528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
34628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
34728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
34828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
349b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_sparse_data_chunk(struct output_file *out, unsigned int len,
350b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		void *data)
35128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
35228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header_t chunk_header;
35328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int rnd_up_len, zero_len;
35428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret;
35528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
356b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	/* Round up the data length to a multiple of the block size */
357b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	rnd_up_len = ALIGN(len, out->block_size);
35828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	zero_len = rnd_up_len - len;
35928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
36028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	/* Finally we can safely emit a chunk of data */
36128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.chunk_type = CHUNK_TYPE_RAW;
36228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.reserved1 = 0;
36328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.chunk_sz = rnd_up_len / out->block_size;
36428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
365b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
36628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
36728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0)
36828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
36928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	ret = out->ops->write(out, data, len);
37028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (ret < 0)
37128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -1;
37228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (zero_len) {
373b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		ret = out->ops->write(out, out->zero_buf, zero_len);
37428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		if (ret < 0)
37528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross			return -1;
37628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
37728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
37828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (out->use_crc) {
37928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		out->crc32 = sparse_crc32(out->crc32, data, len);
38028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		if (zero_len)
381b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
38228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
38328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
38428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->cur_out_ptr += rnd_up_len;
38528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->chunk_cnt++;
38628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
38728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
38828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
38928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
390b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_sparse_end_chunk(struct output_file *out)
39128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
39228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	chunk_header_t chunk_header;
393b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int ret;
39428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
395b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (out->use_crc) {
396b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		chunk_header.chunk_type = CHUNK_TYPE_CRC32;
397b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		chunk_header.reserved1 = 0;
398b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		chunk_header.chunk_sz = 0;
399b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
400b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
401b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
402b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		if (ret < 0) {
403b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			return ret;
404b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		}
405b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		out->ops->write(out, &out->crc32, 4);
406b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		if (ret < 0) {
407b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			return ret;
408b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		}
409b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
410b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		out->chunk_cnt++;
411b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
412b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
413b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return 0;
414b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}
415b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
416b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic struct sparse_file_ops sparse_file_ops = {
417b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_data_chunk = write_sparse_data_chunk,
418b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_fill_chunk = write_sparse_fill_chunk,
419b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_skip_chunk = write_sparse_skip_chunk,
420b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_end_chunk = write_sparse_end_chunk,
421b55dceea986ab24f8b836b5116b389ed619c816eColin Cross};
422b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
423b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_normal_data_chunk(struct output_file *out, unsigned int len,
424b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		void *data)
425b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{
426b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int ret;
427b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	unsigned int rnd_up_len = ALIGN(len, out->block_size);
428b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
429b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	ret = out->ops->write(out, data, len);
430b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (ret < 0) {
431b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		return ret;
432b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
433b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
434b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (rnd_up_len > len) {
435b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		ret = out->ops->skip(out, rnd_up_len - len);
436b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
43728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
438b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return ret;
439b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}
440b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
441b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_normal_fill_chunk(struct output_file *out, unsigned int len,
442b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		uint32_t fill_val)
443b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{
444b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int ret;
445b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	unsigned int i;
446b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	unsigned int write_len;
44728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
448b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	/* Initialize fill_buf with the fill_val */
449b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
450b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		out->fill_buf[i] = fill_val;
451b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
452b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
453b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	while (len) {
454b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		write_len = min(len, out->block_size);
455b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		ret = out->ops->write(out, out->fill_buf, write_len);
456b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		if (ret < 0) {
457b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			return ret;
45828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		}
45928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
460b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		len -= write_len;
461b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
462b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
463b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return 0;
464b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}
465b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
466b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_normal_skip_chunk(struct output_file *out, int64_t len)
467b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{
468b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return out->ops->skip(out, len);
469b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}
470b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
471b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_normal_end_chunk(struct output_file *out)
472b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{
473b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return out->ops->pad(out, out->len);
474b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}
475b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
476b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic struct sparse_file_ops normal_file_ops = {
477b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_data_chunk = write_normal_data_chunk,
478b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_fill_chunk = write_normal_fill_chunk,
479b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_skip_chunk = write_normal_skip_chunk,
480b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		.write_end_chunk = write_normal_end_chunk,
481b55dceea986ab24f8b836b5116b389ed619c816eColin Cross};
482b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
483b55dceea986ab24f8b836b5116b389ed619c816eColin Crossvoid close_output_file(struct output_file *out)
484b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{
485b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int ret;
486b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
487b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	out->sparse_ops->write_end_chunk(out);
48828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	out->ops->close(out);
48928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
49028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
491b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic int output_file_init(struct output_file *out, int block_size,
492b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		int64_t len, bool sparse, int chunks, bool crc)
49328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
49428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret;
495b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
496b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->len = len;
497b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->block_size = block_size;
498b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->cur_out_ptr = 0ll;
499b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->chunk_cnt = 0;
500b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->crc32 = 0;
501b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->use_crc = crc;
502b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
503b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	out->zero_buf = calloc(block_size, 1);
504b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (!out->zero_buf) {
50528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		error_errno("malloc zero_buf");
506b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return -ENOMEM;
507b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
508b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
509b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	out->fill_buf = calloc(block_size, 1);
510b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (!out->fill_buf) {
511b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		error_errno("malloc fill_buf");
512b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		ret = -ENOMEM;
513b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		goto err_fill_buf;
51428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
51528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
516b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (sparse) {
517b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		out->sparse_ops = &sparse_file_ops;
518b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	} else {
519b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		out->sparse_ops = &normal_file_ops;
520b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
521b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
522b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (sparse) {
523b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		sparse_header_t sparse_header = {
524b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.magic = SPARSE_HEADER_MAGIC,
525b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.major_version = SPARSE_HEADER_MAJOR_VER,
526b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.minor_version = SPARSE_HEADER_MINOR_VER,
527b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.file_hdr_sz = SPARSE_HEADER_LEN,
528b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.chunk_hdr_sz = CHUNK_HEADER_LEN,
529b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.blk_sz = out->block_size,
530b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.total_blks = out->len / out->block_size,
531b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.total_chunks = chunks,
532b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				.image_checksum = 0
533b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		};
534b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
535b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		if (out->use_crc) {
53628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross			sparse_header.total_chunks++;
537b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		}
53828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
539b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		ret = out->ops->write(out, &sparse_header, sizeof(sparse_header));
540b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		if (ret < 0) {
541b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			goto err_write;
542b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		}
54328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
54428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
545b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return 0;
546b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
547b55dceea986ab24f8b836b5116b389ed619c816eColin Crosserr_write:
548b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	free(out->fill_buf);
549b55dceea986ab24f8b836b5116b389ed619c816eColin Crosserr_fill_buf:
550b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	free(out->zero_buf);
551b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return ret;
552b4cd267db30c152245e6308598e0066d87c5c55dColin Cross}
553b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
554b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic struct output_file *output_file_new_gz(void)
555b4cd267db30c152245e6308598e0066d87c5c55dColin Cross{
556b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_gz *outgz = calloc(1, sizeof(struct output_file_gz));
557b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (!outgz) {
558b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		error_errno("malloc struct outgz");
559b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return NULL;
560b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
561b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
562b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	outgz->out.ops = &gz_file_ops;
563b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
564b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return &outgz->out;
565b4cd267db30c152245e6308598e0066d87c5c55dColin Cross}
566b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
567b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstatic struct output_file *output_file_new_normal(void)
568b4cd267db30c152245e6308598e0066d87c5c55dColin Cross{
569b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file_normal *outn = calloc(1, sizeof(struct output_file_normal));
570b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (!outn) {
571b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		error_errno("malloc struct outn");
572b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		return NULL;
573b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	}
574b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
575b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	outn->out.ops = &file_ops;
576b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
577b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return &outn->out;
57828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
57928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
580b4cd267db30c152245e6308598e0066d87c5c55dColin Crossstruct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
58128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		int gz, int sparse, int chunks, int crc)
58228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
583b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	int ret;
584b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	struct output_file *out;
58528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
586b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (gz) {
587b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		out = output_file_new_gz();
58828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	} else {
589b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		out = output_file_new_normal();
59028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
59128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
592b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	out->ops->open(out, fd);
593b4cd267db30c152245e6308598e0066d87c5c55dColin Cross
594b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	ret = output_file_init(out, block_size, len, sparse, chunks, crc);
595b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	if (ret < 0) {
596b4cd267db30c152245e6308598e0066d87c5c55dColin Cross		free(out);
59728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return NULL;
59828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
59928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
600b4cd267db30c152245e6308598e0066d87c5c55dColin Cross	return out;
60128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
60228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
60328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks from a memory buffer */
604b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_data_chunk(struct output_file *out, unsigned int len, void *data)
60528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
606b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return out->sparse_ops->write_data_chunk(out, len, data);
60728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
60828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
60928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks with a fill value */
610b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_fill_chunk(struct output_file *out, unsigned int len,
611b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		uint32_t fill_val)
61228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
613b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return out->sparse_ops->write_fill_chunk(out, len, fill_val);
61428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
61528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
6169e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Crossint write_fd_chunk(struct output_file *out, unsigned int len,
6179e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross		int fd, int64_t offset)
61828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
61928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int ret;
62028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int64_t aligned_offset;
62128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int aligned_diff;
62228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	int buffer_size;
62313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	char *ptr;
62428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
62528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	aligned_offset = offset & ~(4096 - 1);
62628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	aligned_diff = offset - aligned_offset;
62728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	buffer_size = len + aligned_diff;
62828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
62928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW
6309e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd,
63128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross			aligned_offset);
63228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (data == MAP_FAILED) {
6339e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross		return -errno;
63428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
63513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	ptr = data + aligned_diff;
63628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else
63713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	off64_t pos;
63813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	char *data = malloc(len);
63928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (!data) {
6409e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross		return -errno;
64128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	}
64213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	pos = lseek64(fd, offset, SEEK_SET);
64313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	if (pos < 0) {
64413a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		return -errno;
64513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	}
64613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	ret = read_all(fd, data, len);
64713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	if (ret < 0) {
64813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross		return ret;
64913a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	}
65013a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	ptr = data;
65128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif
65228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
65313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross	ret = out->sparse_ops->write_data_chunk(out, len, ptr);
65428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
65528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW
65628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	munmap(data, buffer_size);
65728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else
65828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	free(data);
65928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif
6609e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross
6619e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	return ret;
6629e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross}
6639e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross
6649e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross/* Write a contiguous region of data blocks from a file */
6659e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Crossint write_file_chunk(struct output_file *out, unsigned int len,
6669e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross		const char *file, int64_t offset)
6679e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross{
6689e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	int ret;
6699e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross
6709e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	int file_fd = open(file, O_RDONLY | O_BINARY);
6719e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	if (file_fd < 0) {
6729e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross		return -errno;
6739e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	}
6749e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross
6759e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross	ret = write_fd_chunk(out, len, file_fd, offset);
6769e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross
67728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	close(file_fd);
678b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
679b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return ret;
680b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}
681b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
682b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_skip_chunk(struct output_file *out, int64_t len)
683b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{
684b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	return out->sparse_ops->write_skip_chunk(out, len);
68528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
686