output_file.c revision 13a560659381b34ce3edbfa8dbe6c0aa6c076f20
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> 2228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdlib.h> 2328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <string.h> 2428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/stat.h> 2528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/types.h> 2628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <unistd.h> 2728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <zlib.h> 2828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "output_file.h" 3028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_format.h" 3128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_crc32.h" 3228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 3328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW 3428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/mman.h> 3528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define O_BINARY 0 3628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 3728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 3828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#if defined(__APPLE__) && defined(__MACH__) 3928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define lseek64 lseek 4028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define ftruncate64 ftruncate 4128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define mmap64 mmap 4228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define off64_t off_t 4328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 4428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 4528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifdef __BIONIC__ 4628fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossextern void* __mmap2(void *, size_t, int, int, int, off_t); 4728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic inline void *mmap64(void *addr, size_t length, int prot, int flags, 4828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int fd, off64_t offset) 4928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 5028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return __mmap2(addr, length, prot, flags, fd, offset >> 12); 5128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 5228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 5328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 54b55dceea986ab24f8b836b5116b389ed619c816eColin Cross#define min(a, b) \ 55b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) 56b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 5728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_MAJOR_VER 1 5828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_MINOR_VER 0 5928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 6028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define CHUNK_HEADER_LEN (sizeof(chunk_header_t)) 6128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file_ops { 63b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int (*skip)(struct output_file *, int64_t); 64b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int (*write)(struct output_file *, void *, int); 6528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross void (*close)(struct output_file *); 6628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 6728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 68b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstruct sparse_file_ops { 69b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int (*write_data_chunk)(struct output_file *out, unsigned int len, 70b55dceea986ab24f8b836b5116b389ed619c816eColin Cross void *data); 71b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int (*write_fill_chunk)(struct output_file *out, unsigned int len, 72b55dceea986ab24f8b836b5116b389ed619c816eColin Cross uint32_t fill_val); 73b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int (*write_skip_chunk)(struct output_file *out, int64_t len); 74b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int (*write_end_chunk)(struct output_file *out); 75b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}; 76b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 7728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file { 7828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int fd; 7928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross gzFile gz_fd; 8028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross bool close_fd; 8128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t cur_out_ptr; 82b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int chunk_cnt; 83b55dceea986ab24f8b836b5116b389ed619c816eColin Cross uint32_t crc32; 8428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file_ops *ops; 85b55dceea986ab24f8b836b5116b389ed619c816eColin Cross struct sparse_file_ops *sparse_ops; 8628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int use_crc; 8728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block_size; 8828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t len; 89b55dceea986ab24f8b836b5116b389ed619c816eColin Cross char *zero_buf; 90b55dceea986ab24f8b836b5116b389ed619c816eColin Cross uint32_t *fill_buf; 9128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 9228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 93b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int file_skip(struct output_file *out, int64_t cnt) 9428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 9528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off64_t ret; 9628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 97b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = lseek64(out->fd, cnt, SEEK_CUR); 9828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 9928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("lseek64"); 10028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 10128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 10228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 10328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 10428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 105b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int file_write(struct output_file *out, void *data, int len) 10628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 10728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 10828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = write(out->fd, data, len); 10928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 11028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("write"); 11128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 11228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else if (ret < len) { 11328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("incomplete write"); 11428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 11528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 11628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 11728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 11828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 11928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12028fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void file_close(struct output_file *out) 12128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 12228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->close_fd) { 12328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(out->fd); 12428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 12528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 12628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic struct output_file_ops file_ops = { 128b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .skip = file_skip, 12928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .write = file_write, 13028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .close = file_close, 13128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 13228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 133b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int gz_file_skip(struct output_file *out, int64_t cnt) 13428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 13528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off64_t ret; 13628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 137b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = gzseek(out->gz_fd, cnt, SEEK_CUR); 13828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 13928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("gzseek"); 14028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 14128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 14228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 14328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 14428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 145b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int gz_file_write(struct output_file *out, void *data, int len) 14628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 14728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 14828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = gzwrite(out->gz_fd, data, len); 14928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 15028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("gzwrite"); 15128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 15228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else if (ret < len) { 15328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("incomplete gzwrite"); 15428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 15528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 15628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 15728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 15828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 15928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 16028fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void gz_file_close(struct output_file *out) 16128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 16228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross gzclose(out->gz_fd); 16328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 16428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 16528fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic struct output_file_ops gz_file_ops = { 166b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .skip = gz_file_skip, 16728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .write = gz_file_write, 16828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .close = gz_file_close, 16928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 17028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17113a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Crossint read_all(int fd, void *buf, size_t len) 17213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross{ 17313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross size_t total = 0; 17413a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross int ret; 17513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross char *ptr = buf; 17613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross 17713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross while (total < len) { 17813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross ret = read(fd, ptr, len - total); 17913a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross 18013a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross if (ret < 0) 18113a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross return -errno; 18213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross 18313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross if (ret == 0) 18413a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross return -EINVAL; 18513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross 18613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross ptr += ret; 18713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross total += ret; 18813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross } 18913a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross 19013a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross return 0; 19113a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross} 19213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross 193b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len) 19428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 19528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 19628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret, chunk; 19728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 19828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (skip_len % out->block_size) { 19928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("don't care size %llu is not a multiple of the block size %u", 20028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross skip_len, out->block_size); 20128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 20228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 20328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 20428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* We are skipping data, so emit a don't care chunk. */ 20528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE; 20628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 20728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = skip_len / out->block_size; 20828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN; 209b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 21028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 21128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 21228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 21328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr += skip_len; 21428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 21528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 21628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 21728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 21828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 219b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_sparse_fill_chunk(struct output_file *out, unsigned int len, 220b55dceea986ab24f8b836b5116b389ed619c816eColin Cross uint32_t fill_val) 22128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 22228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 22328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int rnd_up_len, zero_len, count; 22428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 22528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int i; 22628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 227b55dceea986ab24f8b836b5116b389ed619c816eColin Cross /* Round up the fill length to a multiple of the block size */ 228b55dceea986ab24f8b836b5116b389ed619c816eColin Cross rnd_up_len = ALIGN(len, out->block_size); 22928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 23028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Finally we can safely emit a chunk of data */ 23128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_FILL; 23228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 23328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = rnd_up_len / out->block_size; 23428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val); 235b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 23628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 23728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 23828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 239b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, &fill_val, sizeof(fill_val)); 24028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 24128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 24228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 24328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->use_crc) { 244b55dceea986ab24f8b836b5116b389ed619c816eColin Cross count = out->block_size / sizeof(uint32_t); 245b55dceea986ab24f8b836b5116b389ed619c816eColin Cross while (count--) 246b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t)); 24728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 24828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 24928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr += rnd_up_len; 25028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 25128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 25228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 25328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 25428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 255b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_sparse_data_chunk(struct output_file *out, unsigned int len, 256b55dceea986ab24f8b836b5116b389ed619c816eColin Cross void *data) 25728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 25828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 25928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int rnd_up_len, zero_len; 26028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 26128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 262b55dceea986ab24f8b836b5116b389ed619c816eColin Cross /* Round up the data length to a multiple of the block size */ 263b55dceea986ab24f8b836b5116b389ed619c816eColin Cross rnd_up_len = ALIGN(len, out->block_size); 26428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross zero_len = rnd_up_len - len; 26528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 26628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Finally we can safely emit a chunk of data */ 26728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_RAW; 26828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 26928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = rnd_up_len / out->block_size; 27028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len; 271b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 27228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 27328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 27428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 27528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, data, len); 27628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 27728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 27828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (zero_len) { 279b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, out->zero_buf, zero_len); 28028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 28128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 28228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 28328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 28428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->use_crc) { 28528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->crc32 = sparse_crc32(out->crc32, data, len); 28628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (zero_len) 287b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len); 28828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 28928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 29028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr += rnd_up_len; 29128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 29228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 29328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 29428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 29528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 296b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_sparse_end_chunk(struct output_file *out) 29728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 29828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 299b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int ret; 30028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 301b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (out->use_crc) { 302b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunk_header.chunk_type = CHUNK_TYPE_CRC32; 303b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunk_header.reserved1 = 0; 304b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunk_header.chunk_sz = 0; 305b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN + 4; 306b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 307b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 308b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (ret < 0) { 309b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return ret; 310b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 311b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->ops->write(out, &out->crc32, 4); 312b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (ret < 0) { 313b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return ret; 314b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 315b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 316b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->chunk_cnt++; 317b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 318b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 319b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return 0; 320b55dceea986ab24f8b836b5116b389ed619c816eColin Cross} 321b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 322b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic struct sparse_file_ops sparse_file_ops = { 323b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_data_chunk = write_sparse_data_chunk, 324b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_fill_chunk = write_sparse_fill_chunk, 325b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_skip_chunk = write_sparse_skip_chunk, 326b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_end_chunk = write_sparse_end_chunk, 327b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}; 328b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 329b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_normal_data_chunk(struct output_file *out, unsigned int len, 330b55dceea986ab24f8b836b5116b389ed619c816eColin Cross void *data) 331b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{ 332b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int ret; 333b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int rnd_up_len = ALIGN(len, out->block_size); 334b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 335b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, data, len); 336b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (ret < 0) { 337b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return ret; 338b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 339b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 340b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (rnd_up_len > len) { 341b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->skip(out, rnd_up_len - len); 342b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 34328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 344b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return ret; 345b55dceea986ab24f8b836b5116b389ed619c816eColin Cross} 346b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 347b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_normal_fill_chunk(struct output_file *out, unsigned int len, 348b55dceea986ab24f8b836b5116b389ed619c816eColin Cross uint32_t fill_val) 349b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{ 350b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int ret; 351b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int i; 352b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int write_len; 35328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 354b55dceea986ab24f8b836b5116b389ed619c816eColin Cross /* Initialize fill_buf with the fill_val */ 355b55dceea986ab24f8b836b5116b389ed619c816eColin Cross for (i = 0; i < out->block_size / sizeof(uint32_t); i++) { 356b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->fill_buf[i] = fill_val; 357b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 358b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 359b55dceea986ab24f8b836b5116b389ed619c816eColin Cross while (len) { 360b55dceea986ab24f8b836b5116b389ed619c816eColin Cross write_len = min(len, out->block_size); 361b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, out->fill_buf, write_len); 362b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (ret < 0) { 363b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return ret; 36428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 36528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 366b55dceea986ab24f8b836b5116b389ed619c816eColin Cross len -= write_len; 367b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 368b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 369b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return 0; 370b55dceea986ab24f8b836b5116b389ed619c816eColin Cross} 371b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 372b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic int write_normal_skip_chunk(struct output_file *out, int64_t len) 373b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{ 374b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int ret; 375b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 376b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return out->ops->skip(out, len); 377b55dceea986ab24f8b836b5116b389ed619c816eColin Cross} 378b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 379b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_normal_end_chunk(struct output_file *out) 380b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{ 381b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int ret; 382b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 383b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = ftruncate64(out->fd, out->len); 384b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (ret < 0) { 385b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return -errno; 38628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 387b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 388b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return 0; 389b55dceea986ab24f8b836b5116b389ed619c816eColin Cross} 390b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 391b55dceea986ab24f8b836b5116b389ed619c816eColin Crossstatic struct sparse_file_ops normal_file_ops = { 392b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_data_chunk = write_normal_data_chunk, 393b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_fill_chunk = write_normal_fill_chunk, 394b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_skip_chunk = write_normal_skip_chunk, 395b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .write_end_chunk = write_normal_end_chunk, 396b55dceea986ab24f8b836b5116b389ed619c816eColin Cross}; 397b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 398b55dceea986ab24f8b836b5116b389ed619c816eColin Crossvoid close_output_file(struct output_file *out) 399b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{ 400b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int ret; 401b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 402b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->sparse_ops->write_end_chunk(out); 40328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops->close(out); 404b55dceea986ab24f8b836b5116b389ed619c816eColin Cross free(out); 40528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 40628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 40728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, 40828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int gz, int sparse, int chunks, int crc) 40928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 41028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 41128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file *out = malloc(sizeof(struct output_file)); 41228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!out) { 41328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("malloc struct out"); 41428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 41528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 416b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->zero_buf = calloc(block_size, 1); 417b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (!out->zero_buf) { 41828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("malloc zero_buf"); 419b55dceea986ab24f8b836b5116b389ed619c816eColin Cross goto err_zero_buf; 420b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 421b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 422b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->fill_buf = calloc(block_size, 1); 423b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (!out->fill_buf) { 424b55dceea986ab24f8b836b5116b389ed619c816eColin Cross error_errno("malloc fill_buf"); 425b55dceea986ab24f8b836b5116b389ed619c816eColin Cross goto err_fill_buf; 42628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 42728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 42828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (gz) { 42928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops = &gz_file_ops; 43028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->gz_fd = gzdopen(fd, "wb9"); 43128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!out->gz_fd) { 43228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("gzopen"); 433b55dceea986ab24f8b836b5116b389ed619c816eColin Cross goto err_gzopen; 43428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 43528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 43628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->fd = fd; 43728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops = &file_ops; 43828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 439b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 440b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (sparse) { 441b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->sparse_ops = &sparse_file_ops; 442b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } else { 443b55dceea986ab24f8b836b5116b389ed619c816eColin Cross out->sparse_ops = &normal_file_ops; 444b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 445b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 44628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->close_fd = false; 44728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr = 0ll; 44828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt = 0; 44928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 45028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Initialize the crc32 value */ 45128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->crc32 = 0; 45228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->use_crc = crc; 45328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 45428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->len = len; 45528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->block_size = block_size; 45628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 457b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (sparse) { 458b55dceea986ab24f8b836b5116b389ed619c816eColin Cross sparse_header_t sparse_header = { 459b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .magic = SPARSE_HEADER_MAGIC, 460b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .major_version = SPARSE_HEADER_MAJOR_VER, 461b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .minor_version = SPARSE_HEADER_MINOR_VER, 462b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .file_hdr_sz = SPARSE_HEADER_LEN, 463b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .chunk_hdr_sz = CHUNK_HEADER_LEN, 464b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .blk_sz = out->block_size, 465b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .total_blks = out->len / out->block_size, 466b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .total_chunks = chunks, 467b55dceea986ab24f8b836b5116b389ed619c816eColin Cross .image_checksum = 0 468b55dceea986ab24f8b836b5116b389ed619c816eColin Cross }; 469b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 470b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (out->use_crc) { 47128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header.total_chunks++; 472b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 47328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 474b55dceea986ab24f8b836b5116b389ed619c816eColin Cross ret = out->ops->write(out, &sparse_header, sizeof(sparse_header)); 475b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (ret < 0) { 476b55dceea986ab24f8b836b5116b389ed619c816eColin Cross goto err_write; 477b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 47828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 47928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 48028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return out; 481b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 482b55dceea986ab24f8b836b5116b389ed619c816eColin Crosserr_write: 483b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (gz) { 484b55dceea986ab24f8b836b5116b389ed619c816eColin Cross gzclose(out->gz_fd); 485b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 486b55dceea986ab24f8b836b5116b389ed619c816eColin Crosserr_gzopen: 487b55dceea986ab24f8b836b5116b389ed619c816eColin Cross free(out->fill_buf); 488b55dceea986ab24f8b836b5116b389ed619c816eColin Crosserr_fill_buf: 489b55dceea986ab24f8b836b5116b389ed619c816eColin Cross free(out->zero_buf); 490b55dceea986ab24f8b836b5116b389ed619c816eColin Crosserr_zero_buf: 491b55dceea986ab24f8b836b5116b389ed619c816eColin Cross free(out); 492b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return NULL; 49328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 49428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 49528fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file *open_output_file(const char *filename, 49628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block_size, int64_t len, 49728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int gz, int sparse, int chunks, int crc) 49828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 49928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int fd; 50028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file *file; 50128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 50228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (strcmp(filename, "-")) { 50328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); 50428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (fd < 0) { 50528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("open"); 50628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 50728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 50828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 50928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fd = STDOUT_FILENO; 51028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 51128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 51228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file = open_output_fd(fd, block_size, len, gz, sparse, chunks, crc); 51328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!file) { 51428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(fd); 51528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 51628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 51728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 51828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file->close_fd = true; // we opened descriptor thus we responsible for closing it 51928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 52028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return file; 52128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 52228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 52328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks from a memory buffer */ 524b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_data_chunk(struct output_file *out, unsigned int len, void *data) 52528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 526b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return out->sparse_ops->write_data_chunk(out, len, data); 52728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 52828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 52928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks with a fill value */ 530b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_fill_chunk(struct output_file *out, unsigned int len, 531b55dceea986ab24f8b836b5116b389ed619c816eColin Cross uint32_t fill_val) 53228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 533b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return out->sparse_ops->write_fill_chunk(out, len, fill_val); 53428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 53528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 5369e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Crossint write_fd_chunk(struct output_file *out, unsigned int len, 5379e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross int fd, int64_t offset) 53828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 53928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 54028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t aligned_offset; 54128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int aligned_diff; 54228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int buffer_size; 54313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross char *ptr; 54428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 54528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross aligned_offset = offset & ~(4096 - 1); 54628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross aligned_diff = offset - aligned_offset; 54728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross buffer_size = len + aligned_diff; 54828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 54928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW 5509e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, 55128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross aligned_offset); 55228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (data == MAP_FAILED) { 5539e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross return -errno; 55428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 55513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross ptr = data + aligned_diff; 55628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else 55713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross off64_t pos; 55813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross char *data = malloc(len); 55928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!data) { 5609e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross return -errno; 56128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 56213a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross pos = lseek64(fd, offset, SEEK_SET); 56313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross if (pos < 0) { 56413a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross return -errno; 56513a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross } 56613a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross ret = read_all(fd, data, len); 56713a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross if (ret < 0) { 56813a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross return ret; 56913a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross } 57013a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross ptr = data; 57128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 57228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 57313a560659381b34ce3edbfa8dbe6c0aa6c076f20Colin Cross ret = out->sparse_ops->write_data_chunk(out, len, ptr); 57428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 57528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW 57628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross munmap(data, buffer_size); 57728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else 57828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross free(data); 57928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 5809e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross 5819e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross return ret; 5829e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross} 5839e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross 5849e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross/* Write a contiguous region of data blocks from a file */ 5859e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Crossint write_file_chunk(struct output_file *out, unsigned int len, 5869e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross const char *file, int64_t offset) 5879e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross{ 5889e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross int ret; 5899e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross 5909e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross int file_fd = open(file, O_RDONLY | O_BINARY); 5919e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross if (file_fd < 0) { 5929e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross return -errno; 5939e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross } 5949e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross 5959e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross ret = write_fd_chunk(out, len, file_fd, offset); 5969e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross 59728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(file_fd); 598b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 599b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return ret; 600b55dceea986ab24f8b836b5116b389ed619c816eColin Cross} 601b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 602b55dceea986ab24f8b836b5116b389ed619c816eColin Crossint write_skip_chunk(struct output_file *out, int64_t len) 603b55dceea986ab24f8b836b5116b389ed619c816eColin Cross{ 604b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return out->sparse_ops->write_skip_chunk(out, len); 60528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 606