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