sparse.c revision 1e17b313a6257b7b5081e178e81435c09d60378e
128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* 228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Copyright (C) 2012 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 17b55dceea986ab24f8b836b5116b389ed619c816eColin Cross#include <assert.h> 1828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdlib.h> 1928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sparse/sparse.h> 2128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_file.h" 2328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "output_file.h" 2528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "backed_block.h" 2628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_defs.h" 2728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2828fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct sparse_file *sparse_file_new(unsigned int block_size, int64_t len) 2928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 3028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct sparse_file *s = calloc(sizeof(struct sparse_file), 1); 3128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!s) { 3228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return NULL; 3328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 3428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 35be8ddcb35a459481c0bcf5bfe645c1fefe963f5cColin Cross s->backed_block_list = backed_block_list_new(block_size); 36411619e921904b896eddae81c086c1f687c8304dColin Cross if (!s->backed_block_list) { 37411619e921904b896eddae81c086c1f687c8304dColin Cross free(s); 38411619e921904b896eddae81c086c1f687c8304dColin Cross return NULL; 39411619e921904b896eddae81c086c1f687c8304dColin Cross } 4028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 4128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross s->block_size = block_size; 4228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross s->len = len; 4328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 4428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return s; 4528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 4628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 4728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossvoid sparse_file_destroy(struct sparse_file *s) 4828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 49411619e921904b896eddae81c086c1f687c8304dColin Cross backed_block_list_destroy(s->backed_block_list); 5028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross free(s); 5128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 5228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 5328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_add_data(struct sparse_file *s, 5428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross void *data, unsigned int len, unsigned int block) 5528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 56b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return backed_block_add_data(s->backed_block_list, data, len, block); 5728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 5828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 5928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_add_fill(struct sparse_file *s, 6028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross uint32_t fill_val, unsigned int len, unsigned int block) 6128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 62b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return backed_block_add_fill(s->backed_block_list, fill_val, len, block); 6328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 6428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6528fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_add_file(struct sparse_file *s, 6628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross const char *filename, int64_t file_offset, unsigned int len, 6728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block) 6828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 69b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return backed_block_add_file(s->backed_block_list, filename, file_offset, 70b55dceea986ab24f8b836b5116b389ed619c816eColin Cross len, block); 7128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 7228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 739e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Crossint sparse_file_add_fd(struct sparse_file *s, 749e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross int fd, int64_t file_offset, unsigned int len, unsigned int block) 759e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross{ 769e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross return backed_block_add_fd(s->backed_block_list, fd, file_offset, 779e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross len, block); 789e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross} 79b55dceea986ab24f8b836b5116b389ed619c816eColin Crossunsigned int sparse_count_chunks(struct sparse_file *s) 8028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 81b55dceea986ab24f8b836b5116b389ed619c816eColin Cross struct backed_block *bb; 82b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int last_block = 0; 83b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int chunks = 0; 84b55dceea986ab24f8b836b5116b389ed619c816eColin Cross 85b55dceea986ab24f8b836b5116b389ed619c816eColin Cross for (bb = backed_block_iter_new(s->backed_block_list); bb; 86b55dceea986ab24f8b836b5116b389ed619c816eColin Cross bb = backed_block_iter_next(bb)) { 87b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (backed_block_block(bb) > last_block) { 88b55dceea986ab24f8b836b5116b389ed619c816eColin Cross /* If there is a gap between chunks, add a skip chunk */ 89b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunks++; 90b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 91b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunks++; 92b55dceea986ab24f8b836b5116b389ed619c816eColin Cross last_block = backed_block_block(bb) + 93b55dceea986ab24f8b836b5116b389ed619c816eColin Cross DIV_ROUND_UP(backed_block_len(bb), s->block_size); 94b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 95b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (last_block < DIV_ROUND_UP(s->len, s->block_size)) { 96b55dceea986ab24f8b836b5116b389ed619c816eColin Cross chunks++; 97b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 9828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 99b55dceea986ab24f8b836b5116b389ed619c816eColin Cross return chunks; 10028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 10128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 1021e17b313a6257b7b5081e178e81435c09d60378eColin Crossstatic void sparse_file_write_block(struct output_file *out, 1031e17b313a6257b7b5081e178e81435c09d60378eColin Cross struct backed_block *bb) 1041e17b313a6257b7b5081e178e81435c09d60378eColin Cross{ 1051e17b313a6257b7b5081e178e81435c09d60378eColin Cross switch (backed_block_type(bb)) { 1061e17b313a6257b7b5081e178e81435c09d60378eColin Cross case BACKED_BLOCK_DATA: 1071e17b313a6257b7b5081e178e81435c09d60378eColin Cross write_data_chunk(out, backed_block_len(bb), backed_block_data(bb)); 1081e17b313a6257b7b5081e178e81435c09d60378eColin Cross break; 1091e17b313a6257b7b5081e178e81435c09d60378eColin Cross case BACKED_BLOCK_FILE: 1101e17b313a6257b7b5081e178e81435c09d60378eColin Cross write_file_chunk(out, backed_block_len(bb), 1111e17b313a6257b7b5081e178e81435c09d60378eColin Cross backed_block_filename(bb), backed_block_file_offset(bb)); 1121e17b313a6257b7b5081e178e81435c09d60378eColin Cross break; 1131e17b313a6257b7b5081e178e81435c09d60378eColin Cross case BACKED_BLOCK_FD: 1141e17b313a6257b7b5081e178e81435c09d60378eColin Cross write_fd_chunk(out, backed_block_len(bb), 1151e17b313a6257b7b5081e178e81435c09d60378eColin Cross backed_block_fd(bb), backed_block_file_offset(bb)); 1161e17b313a6257b7b5081e178e81435c09d60378eColin Cross break; 1171e17b313a6257b7b5081e178e81435c09d60378eColin Cross case BACKED_BLOCK_FILL: 1181e17b313a6257b7b5081e178e81435c09d60378eColin Cross write_fill_chunk(out, backed_block_len(bb), 1191e17b313a6257b7b5081e178e81435c09d60378eColin Cross backed_block_fill_val(bb)); 1201e17b313a6257b7b5081e178e81435c09d60378eColin Cross break; 1211e17b313a6257b7b5081e178e81435c09d60378eColin Cross } 1221e17b313a6257b7b5081e178e81435c09d60378eColin Cross} 1231e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1241e17b313a6257b7b5081e178e81435c09d60378eColin Crossstatic int write_all_blocks(struct sparse_file *s, struct output_file *out) 12528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 126b55dceea986ab24f8b836b5116b389ed619c816eColin Cross struct backed_block *bb; 127b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int last_block = 0; 128b55dceea986ab24f8b836b5116b389ed619c816eColin Cross int64_t pad; 12928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 130b55dceea986ab24f8b836b5116b389ed619c816eColin Cross for (bb = backed_block_iter_new(s->backed_block_list); bb; 131b55dceea986ab24f8b836b5116b389ed619c816eColin Cross bb = backed_block_iter_next(bb)) { 132b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (backed_block_block(bb) > last_block) { 133b55dceea986ab24f8b836b5116b389ed619c816eColin Cross unsigned int blocks = backed_block_block(bb) - last_block; 134b55dceea986ab24f8b836b5116b389ed619c816eColin Cross write_skip_chunk(out, (int64_t)blocks * s->block_size); 135b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 1361e17b313a6257b7b5081e178e81435c09d60378eColin Cross sparse_file_write_block(out, bb); 137b55dceea986ab24f8b836b5116b389ed619c816eColin Cross last_block = backed_block_block(bb) + 138b55dceea986ab24f8b836b5116b389ed619c816eColin Cross DIV_ROUND_UP(backed_block_len(bb), s->block_size); 139b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 14028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 141b55dceea986ab24f8b836b5116b389ed619c816eColin Cross pad = s->len - last_block * s->block_size; 142b55dceea986ab24f8b836b5116b389ed619c816eColin Cross assert(pad >= 0); 143b55dceea986ab24f8b836b5116b389ed619c816eColin Cross if (pad > 0) { 144b55dceea986ab24f8b836b5116b389ed619c816eColin Cross write_skip_chunk(out, pad); 145b55dceea986ab24f8b836b5116b389ed619c816eColin Cross } 14628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 1471e17b313a6257b7b5081e178e81435c09d60378eColin Cross return 0; 1481e17b313a6257b7b5081e178e81435c09d60378eColin Cross} 1491e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1501e17b313a6257b7b5081e178e81435c09d60378eColin Crossint sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, 1511e17b313a6257b7b5081e178e81435c09d60378eColin Cross bool crc) 1521e17b313a6257b7b5081e178e81435c09d60378eColin Cross{ 1531e17b313a6257b7b5081e178e81435c09d60378eColin Cross int ret; 1541e17b313a6257b7b5081e178e81435c09d60378eColin Cross int chunks; 1551e17b313a6257b7b5081e178e81435c09d60378eColin Cross struct output_file *out; 1561e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1571e17b313a6257b7b5081e178e81435c09d60378eColin Cross chunks = sparse_count_chunks(s); 1581e17b313a6257b7b5081e178e81435c09d60378eColin Cross out = open_output_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc); 1591e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1601e17b313a6257b7b5081e178e81435c09d60378eColin Cross if (!out) 1611e17b313a6257b7b5081e178e81435c09d60378eColin Cross return -ENOMEM; 1621e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1631e17b313a6257b7b5081e178e81435c09d60378eColin Cross ret = write_all_blocks(s, out); 1641e17b313a6257b7b5081e178e81435c09d60378eColin Cross 16528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close_output_file(out); 16628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 1671e17b313a6257b7b5081e178e81435c09d60378eColin Cross return ret; 1681e17b313a6257b7b5081e178e81435c09d60378eColin Cross} 1691e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1701e17b313a6257b7b5081e178e81435c09d60378eColin Crossint sparse_file_callback(struct sparse_file *s, bool sparse, bool crc, 1711e17b313a6257b7b5081e178e81435c09d60378eColin Cross int (*write)(void *priv, const void *data, int len), void *priv) 1721e17b313a6257b7b5081e178e81435c09d60378eColin Cross{ 1731e17b313a6257b7b5081e178e81435c09d60378eColin Cross int ret; 1741e17b313a6257b7b5081e178e81435c09d60378eColin Cross int chunks; 1751e17b313a6257b7b5081e178e81435c09d60378eColin Cross struct output_file *out; 1761e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1771e17b313a6257b7b5081e178e81435c09d60378eColin Cross chunks = sparse_count_chunks(s); 1781e17b313a6257b7b5081e178e81435c09d60378eColin Cross out = open_output_callback(write, priv, s->block_size, s->len, false, 1791e17b313a6257b7b5081e178e81435c09d60378eColin Cross sparse, chunks, crc); 1801e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1811e17b313a6257b7b5081e178e81435c09d60378eColin Cross if (!out) 1821e17b313a6257b7b5081e178e81435c09d60378eColin Cross return -ENOMEM; 1831e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1841e17b313a6257b7b5081e178e81435c09d60378eColin Cross ret = write_all_blocks(s, out); 1851e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1861e17b313a6257b7b5081e178e81435c09d60378eColin Cross close_output_file(out); 1871e17b313a6257b7b5081e178e81435c09d60378eColin Cross 1881e17b313a6257b7b5081e178e81435c09d60378eColin Cross return ret; 18928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 190a21930b6b0dbb04a52948566d58fb48c6db58babColin Cross 191a21930b6b0dbb04a52948566d58fb48c6db58babColin Crossvoid sparse_file_verbose(struct sparse_file *s) 192a21930b6b0dbb04a52948566d58fb48c6db58babColin Cross{ 193a21930b6b0dbb04a52948566d58fb48c6db58babColin Cross s->verbose = true; 194a21930b6b0dbb04a52948566d58fb48c6db58babColin Cross} 195