sparse.c revision 411619e921904b896eddae81c086c1f687c8304d
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 1728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdlib.h> 1828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 1928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sparse/sparse.h> 2028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_file.h" 2228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "output_file.h" 2428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "backed_block.h" 2528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_defs.h" 2628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 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 35411619e921904b896eddae81c086c1f687c8304dColin Cross s->backed_block_list = backed_block_list_new(); 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{ 56411619e921904b896eddae81c086c1f687c8304dColin Cross queue_data_block(s->backed_block_list, data, len, block); 5728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 5828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 5928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 6028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6128fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_add_fill(struct sparse_file *s, 6228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross uint32_t fill_val, unsigned int len, unsigned int block) 6328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 64411619e921904b896eddae81c086c1f687c8304dColin Cross queue_fill_block(s->backed_block_list, fill_val, len, block); 6528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 6728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 6828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6928fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_add_file(struct sparse_file *s, 7028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross const char *filename, int64_t file_offset, unsigned int len, 7128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block) 7228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 73411619e921904b896eddae81c086c1f687c8304dColin Cross queue_data_file(s->backed_block_list, filename, file_offset, len, block); 7428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 7528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 7628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 7728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 7828fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstruct count_chunks { 7928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int chunks; 8028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t cur_ptr; 8128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int block_size; 8228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}; 8328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 8428fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void count_data_block(void *priv, int64_t off, void *data, int len) 8528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 8628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct count_chunks *count_chunks = priv; 8728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off > count_chunks->cur_ptr) 8828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->chunks++; 8928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size); 9028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->chunks++; 9128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 9228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 9328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void count_fill_block(void *priv, int64_t off, unsigned int fill_val, int len) 9428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 9528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct count_chunks *count_chunks = priv; 9628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off > count_chunks->cur_ptr) 9728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->chunks++; 9828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size); 9928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->chunks++; 10028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 10128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 10228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void count_file_block(void *priv, int64_t off, const char *file, 10328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t offset, int len) 10428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 10528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct count_chunks *count_chunks = priv; 10628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (off > count_chunks->cur_ptr) 10728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->chunks++; 10828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size); 10928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks->chunks++; 11028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 11128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 112411619e921904b896eddae81c086c1f687c8304dColin Crossstatic int count_sparse_chunks(struct backed_block_list *b, 113411619e921904b896eddae81c086c1f687c8304dColin Cross unsigned int block_size, int64_t len) 11428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 11528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct count_chunks count_chunks = {0, 0, block_size}; 11628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 117411619e921904b896eddae81c086c1f687c8304dColin Cross for_each_data_block(b, count_data_block, count_file_block, 118411619e921904b896eddae81c086c1f687c8304dColin Cross count_fill_block, &count_chunks, block_size); 11928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (count_chunks.cur_ptr != len) 12128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross count_chunks.chunks++; 12228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return count_chunks.chunks; 12428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 12528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12628fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void ext4_write_data_block(void *priv, int64_t off, void *data, int len) 12728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 12828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_data_block(priv, off, data, len); 12928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 13028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 13128fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void ext4_write_fill_block(void *priv, int64_t off, unsigned int fill_val, int len) 13228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 13328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_fill_block(priv, off, fill_val, len); 13428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 13528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 13628fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void ext4_write_data_file(void *priv, int64_t off, const char *file, 13728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int64_t offset, int len) 13828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 13928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross write_data_file(priv, off, file, offset, len); 14028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 14128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 14228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, 14328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross bool crc) 14428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 145411619e921904b896eddae81c086c1f687c8304dColin Cross int chunks = count_sparse_chunks(s->backed_block_list, s->block_size, 146411619e921904b896eddae81c086c1f687c8304dColin Cross s->len); 14728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct output_file *out = open_output_fd(fd, s->block_size, s->len, 14828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross gz, sparse, chunks, crc); 14928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 15028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!out) 15128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -ENOMEM; 15228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 153411619e921904b896eddae81c086c1f687c8304dColin Cross for_each_data_block(s->backed_block_list, ext4_write_data_block, 154411619e921904b896eddae81c086c1f687c8304dColin Cross ext4_write_data_file, ext4_write_fill_block, out, s->block_size); 15528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 15628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (s->len) 15728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross pad_output_file(out, s->len); 15828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 15928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross close_output_file(out); 16028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 16128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 16228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 163