output_file.c revision 28fa5bc347390480fe190294c6c385b6a9f0d68b
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 5428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_MAJOR_VER 1 5528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_MINOR_VER 0 5628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 5728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define CHUNK_HEADER_LEN (sizeof(chunk_header_t)) 5828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 5928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file_ops { 6028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int (*seek)(struct output_file *, int64_t); 6128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int (*write)(struct output_file *, u8 *, int); 6228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross void (*close)(struct output_file *); 6328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 6428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6528fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file { 6628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int fd; 6728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross gzFile gz_fd; 6828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross bool close_fd; 6928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int sparse; 7028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t cur_out_ptr; 7128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross u32 chunk_cnt; 7228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross u32 crc32; 7328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file_ops *ops; 7428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int use_crc; 7528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block_size; 7628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t len; 7728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 7828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 7928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int file_seek(struct output_file *out, int64_t off) 8028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 8128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off64_t ret; 8228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 8328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = lseek64(out->fd, off, SEEK_SET); 8428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 8528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("lseek64"); 8628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 8728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 8828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 8928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 9028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 9128fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int file_write(struct output_file *out, u8 *data, int len) 9228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 9328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 9428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = write(out->fd, data, len); 9528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 9628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("write"); 9728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 9828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else if (ret < len) { 9928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("incomplete write"); 10028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 10128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 10228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 10328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 10428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 10528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 10628fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void file_close(struct output_file *out) 10728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 10828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->close_fd) { 10928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(out->fd); 11028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 11128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 11228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 11328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 11428fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic struct output_file_ops file_ops = { 11528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .seek = file_seek, 11628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .write = file_write, 11728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .close = file_close, 11828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 11928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12028fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int gz_file_seek(struct output_file *out, int64_t off) 12128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 12228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off64_t ret; 12328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = gzseek(out->gz_fd, off, SEEK_SET); 12528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 12628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("gzseek"); 12728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 12828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 12928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 13028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 13128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 13228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int gz_file_write(struct output_file *out, u8 *data, int len) 13328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 13428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 13528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = gzwrite(out->gz_fd, data, len); 13628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 13728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("gzwrite"); 13828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 13928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else if (ret < len) { 14028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("incomplete gzwrite"); 14128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 14228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 14328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 14428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 14528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 14628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 14728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void gz_file_close(struct output_file *out) 14828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 14928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross gzclose(out->gz_fd); 15028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 15128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 15228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic struct output_file_ops gz_file_ops = { 15328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .seek = gz_file_seek, 15428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .write = gz_file_write, 15528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .close = gz_file_close, 15628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 15728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 15828fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic sparse_header_t sparse_header = { 15928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .magic = SPARSE_HEADER_MAGIC, 16028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .major_version = SPARSE_HEADER_MAJOR_VER, 16128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .minor_version = SPARSE_HEADER_MINOR_VER, 16228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .file_hdr_sz = SPARSE_HEADER_LEN, 16328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .chunk_hdr_sz = CHUNK_HEADER_LEN, 16428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .blk_sz = 0, 16528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .total_blks = 0, 16628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .total_chunks = 0, 16728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross .image_checksum = 0 16828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 16928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17028fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic u8 *zero_buf; 17128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int emit_skip_chunk(struct output_file *out, u64 skip_len) 17328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 17428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 17528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret, chunk; 17628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross //DBG printf("skip chunk: 0x%llx bytes\n", skip_len); 17828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (skip_len % out->block_size) { 18028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("don't care size %llu is not a multiple of the block size %u", 18128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross skip_len, out->block_size); 18228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 18328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 18428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 18528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* We are skipping data, so emit a don't care chunk. */ 18628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE; 18728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 18828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = skip_len / out->block_size; 18928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN; 19028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header)); 19128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 19228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 19328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 19428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr += skip_len; 19528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 19628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 19728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 19828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 19928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 20028fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int write_chunk_fill(struct output_file *out, int64_t off, u32 fill_val, int len) 20128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 20228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 20328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int rnd_up_len, zero_len, count; 20428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 20528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int i; 20628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross u32 fill_buf[4096/sizeof(u32)]; /* Maximum size of a block */ 20728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 20828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* We can assume that all the chunks to be written are in 20928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * ascending order, block-size aligned, and non-overlapping. 21028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * So, if the offset is less than the current output pointer, 21128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * throw an error, and if there is a gap, emit a "don't care" 21228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * chunk. The first write (of the super block) may not be 21328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * blocksize aligned, so we need to deal with that too. 21428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross */ 21528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross //DBG printf("write chunk: offset 0x%llx, length 0x%x bytes\n", off, len); 21628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 21728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off < out->cur_out_ptr) { 21828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("offset %llu is less than the current output offset %llu", 21928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off, out->cur_out_ptr); 22028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 22128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 22228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 22328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off > out->cur_out_ptr) { 22428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross emit_skip_chunk(out, off - out->cur_out_ptr); 22528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 22628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 22728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off % out->block_size) { 22828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("write chunk offset %llu is not a multiple of the block size %u", 22928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off, out->block_size); 23028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 23128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 23228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 23328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off != out->cur_out_ptr) { 23428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("internal error, offset accounting screwy in write_chunk_raw()"); 23528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 23628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 23728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 23828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Round up the file length to a multiple of the block size */ 23928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross rnd_up_len = (len + (out->block_size - 1)) & (~(out->block_size -1)); 24028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 24128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Finally we can safely emit a chunk of data */ 24228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_FILL; 24328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 24428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = rnd_up_len / out->block_size; 24528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val); 24628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header)); 24728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 24828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 24928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 25028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8 *)&fill_val, sizeof(fill_val)); 25128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 25228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 25328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 25428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->use_crc) { 25528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Initialize fill_buf with the fill_val */ 25628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross for (i = 0; i < (out->block_size / sizeof(u32)); i++) { 25728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fill_buf[i] = fill_val; 25828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 25928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 26028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count = chunk_header.chunk_sz; 26128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross while (count) { 26228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->crc32 = sparse_crc32(out->crc32, fill_buf, out->block_size); 26328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count--; 26428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 26528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 26628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 26728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr += rnd_up_len; 26828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 26928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 27028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 27128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 27228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 27328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int write_chunk_raw(struct output_file *out, int64_t off, u8 *data, int len) 27428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 27528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 27628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int rnd_up_len, zero_len; 27728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 27828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 27928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* We can assume that all the chunks to be written are in 28028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * ascending order, block-size aligned, and non-overlapping. 28128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * So, if the offset is less than the current output pointer, 28228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * throw an error, and if there is a gap, emit a "don't care" 28328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * chunk. The first write (of the super block) may not be 28428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * blocksize aligned, so we need to deal with that too. 28528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross */ 28628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross //DBG printf("write chunk: offset 0x%llx, length 0x%x bytes\n", off, len); 28728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 28828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off < out->cur_out_ptr) { 28928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("offset %llu is less than the current output offset %llu", 29028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off, out->cur_out_ptr); 29128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 29228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 29328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 29428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off > out->cur_out_ptr) { 29528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross emit_skip_chunk(out, off - out->cur_out_ptr); 29628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 29728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 29828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off % out->block_size) { 29928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("write chunk offset %llu is not a multiple of the block size %u", 30028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off, out->block_size); 30128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 30228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 30328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 30428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off != out->cur_out_ptr) { 30528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("internal error, offset accounting screwy in write_chunk_raw()"); 30628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 30728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 30828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 30928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Round up the file length to a multiple of the block size */ 31028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross rnd_up_len = (len + (out->block_size - 1)) & (~(out->block_size -1)); 31128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross zero_len = rnd_up_len - len; 31228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 31328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Finally we can safely emit a chunk of data */ 31428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_RAW; 31528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 31628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = rnd_up_len / out->block_size; 31728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len; 31828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header)); 31928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 32028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 32128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 32228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, data, len); 32328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 32428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 32528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (zero_len) { 32628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, zero_buf, zero_len); 32728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 32828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 32928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 33028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 33128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->use_crc) { 33228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->crc32 = sparse_crc32(out->crc32, data, len); 33328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (zero_len) 33428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->crc32 = sparse_crc32(out->crc32, zero_buf, zero_len); 33528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 33628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 33728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr += rnd_up_len; 33828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 33928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 34028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 34128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 34228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 34328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossvoid close_output_file(struct output_file *out) 34428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 34528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 34628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t chunk_header; 34728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 34828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->sparse) { 34928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->use_crc) { 35028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_type = CHUNK_TYPE_CRC32; 35128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.reserved1 = 0; 35228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.chunk_sz = 0; 35328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header.total_sz = CHUNK_HEADER_LEN + 4; 35428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 35528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header)); 35628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops->write(out, (u8 *)&out->crc32, 4); 35728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 35828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt++; 35928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 36028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 36128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->chunk_cnt != sparse_header.total_chunks) 36228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("sparse chunk count did not match: %d %d", out->chunk_cnt, 36328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header.total_chunks); 36428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 36528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops->close(out); 36628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 36728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 36828fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, 36928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int gz, int sparse, int chunks, int crc) 37028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 37128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 37228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file *out = malloc(sizeof(struct output_file)); 37328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!out) { 37428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("malloc struct out"); 37528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 37628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 37728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross zero_buf = malloc(out->block_size); 37828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!zero_buf) { 37928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("malloc zero_buf"); 38028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross free(out); 38128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 38228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 38328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross memset(zero_buf, '\0', out->block_size); 38428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 38528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (gz) { 38628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops = &gz_file_ops; 38728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->gz_fd = gzdopen(fd, "wb9"); 38828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!out->gz_fd) { 38928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("gzopen"); 39028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross free(out); 39128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 39228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 39328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 39428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->fd = fd; 39528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->ops = &file_ops; 39628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 39728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->close_fd = false; 39828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->sparse = sparse; 39928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr = 0ll; 40028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->chunk_cnt = 0; 40128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 40228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Initialize the crc32 value */ 40328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->crc32 = 0; 40428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->use_crc = crc; 40528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 40628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->len = len; 40728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->block_size = block_size; 40828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 40928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->sparse) { 41028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header.blk_sz = out->block_size, 41128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header.total_blks = out->len / out->block_size, 41228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header.total_chunks = chunks; 41328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->use_crc) 41428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header.total_chunks++; 41528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 41628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header)); 41728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 41828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 41928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 42028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 42128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return out; 42228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 42328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 42428fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct output_file *open_output_file(const char *filename, 42528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block_size, int64_t len, 42628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int gz, int sparse, int chunks, int crc) 42728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 42828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int fd; 42928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file *file; 43028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 43128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (strcmp(filename, "-")) { 43228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); 43328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (fd < 0) { 43428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("open"); 43528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 43628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 43728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 43828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fd = STDOUT_FILENO; 43928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 44028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 44128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file = open_output_fd(fd, block_size, len, gz, sparse, chunks, crc); 44228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!file) { 44328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(fd); 44428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 44528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 44628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 44728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file->close_fd = true; // we opened descriptor thus we responsible for closing it 44828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 44928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return file; 45028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 45128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 45228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossvoid pad_output_file(struct output_file *out, int64_t len) 45328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 45428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 45528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 45628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (len > out->len) { 45728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("attempted to pad file %llu bytes past end of filesystem", 45828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross len - out->len); 45928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 46028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 46128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->sparse) { 46228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* We need to emit a DONT_CARE chunk to pad out the file if the 46328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * cur_out_ptr is not already at the end of the filesystem. 46428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross */ 46528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (len < out->cur_out_ptr) { 46628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("attempted to pad file %llu bytes less than the current output pointer", 46728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out->cur_out_ptr - len); 46828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 46928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 47028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (len > out->cur_out_ptr) { 47128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross emit_skip_chunk(out, len - out->cur_out_ptr); 47228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 47328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 47428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross //KEN TODO: Fixme. If the filesystem image needs no padding, 47528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross // this will overwrite the last byte in the file with 0 47628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross // The answer is to do accounting like the sparse image 47728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross // code does and know if there is already data there. 47828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->seek(out, len - 1); 47928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 48028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 48128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 48228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8*)"", 1); 48328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 48428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 48528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 48628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 48728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 48828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks from a memory buffer */ 48928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossvoid write_data_block(struct output_file *out, int64_t off, void *data, int len) 49028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 49128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 49228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 49328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off + len > out->len) { 49428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("attempted to write block %llu past end of filesystem", 49528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off + len - out->len); 49628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 49728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 49828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 49928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->sparse) { 50028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_chunk_raw(out, off, data, len); 50128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 50228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->seek(out, off); 50328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 50428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 50528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 50628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, data, len); 50728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 50828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 50928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 51028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 51128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 51228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks with a fill value */ 51328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossvoid write_fill_block(struct output_file *out, int64_t off, unsigned int fill_val, int len) 51428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 51528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 51628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int i; 51728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int write_len; 51828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross u32 fill_buf[4096/sizeof(u32)]; /* Maximum size of a block */ 51928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 52028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off + len > out->len) { 52128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("attempted to write block %llu past end of filesystem", 52228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off + len - out->len); 52328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 52428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 52528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 52628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->sparse) { 52728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_chunk_fill(out, off, fill_val, len); 52828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 52928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Initialize fill_buf with the fill_val */ 53028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross for (i = 0; i < sizeof(fill_buf)/sizeof(u32); i++) { 53128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fill_buf[i] = fill_val; 53228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 53328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 53428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->seek(out, off); 53528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 53628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 53728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 53828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross while (len) { 53928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_len = (len > (int)sizeof(fill_buf) ? (int)sizeof(fill_buf) : len); 54028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, (u8 *)fill_buf, write_len); 54128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) { 54228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 54328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 54428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross len -= write_len; 54528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 54628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 54728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 54828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 54928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 55028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* Write a contiguous region of data blocks from a file */ 55128fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossvoid write_data_file(struct output_file *out, int64_t off, const char *file, 55228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t offset, int len) 55328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 55428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int ret; 55528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t aligned_offset; 55628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int aligned_diff; 55728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int buffer_size; 55828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 55928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off + len >= out->len) { 56028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error("attempted to write block %llu past end of filesystem", 56128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off + len - out->len); 56228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 56328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 56428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 56528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int file_fd = open(file, O_RDONLY | O_BINARY); 56628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (file_fd < 0) { 56728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("open"); 56828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 56928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 57028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 57128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross aligned_offset = offset & ~(4096 - 1); 57228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross aligned_diff = offset - aligned_offset; 57328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross buffer_size = len + aligned_diff; 57428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 57528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW 57628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross u8 *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, file_fd, 57728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross aligned_offset); 57828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (data == MAP_FAILED) { 57928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("mmap64"); 58028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(file_fd); 58128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 58228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 58328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else 58428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross u8 *data = malloc(buffer_size); 58528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!data) { 58628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_errno("malloc"); 58728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(file_fd); 58828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return; 58928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 59028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross memset(data, 0, buffer_size); 59128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 59228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 59328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (out->sparse) { 59428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_chunk_raw(out, off, data + aligned_diff, len); 59528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } else { 59628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->seek(out, off); 59728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 59828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross goto err; 59928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 60028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ret = out->ops->write(out, data + aligned_diff, len); 60128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (ret < 0) 60228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross goto err; 60328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 60428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 60528fa5bc347390480fe190294c6c385b6a9f0d68bColin Crosserr: 60628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#ifndef USE_MINGW 60728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross munmap(data, buffer_size); 60828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else 60928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write(file_fd, data, buffer_size); 61028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross free(data); 61128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 61228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close(file_fd); 61328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 614