sparse.c revision 28fa5bc347390480fe190294c6c385b6a9f0d68b
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdlib.h> 18 19#include <sparse/sparse.h> 20 21#include "sparse_file.h" 22 23#include "output_file.h" 24#include "backed_block.h" 25#include "sparse_defs.h" 26 27 28struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len) 29{ 30 struct sparse_file *s = calloc(sizeof(struct sparse_file), 1); 31 if (!s) { 32 return NULL; 33 } 34 35 /* TODO: allocate backed block list */ 36 37 s->block_size = block_size; 38 s->len = len; 39 40 return s; 41} 42 43void sparse_file_destroy(struct sparse_file *s) 44{ 45 free_data_blocks(); 46 free(s); 47} 48 49int sparse_file_add_data(struct sparse_file *s, 50 void *data, unsigned int len, unsigned int block) 51{ 52 queue_data_block(data, len, block); 53 54 return 0; 55} 56 57int sparse_file_add_fill(struct sparse_file *s, 58 uint32_t fill_val, unsigned int len, unsigned int block) 59{ 60 queue_fill_block(fill_val, len, block); 61 62 return 0; 63} 64 65int sparse_file_add_file(struct sparse_file *s, 66 const char *filename, int64_t file_offset, unsigned int len, 67 unsigned int block) 68{ 69 queue_data_file(filename, file_offset, len, block); 70 71 return 0; 72} 73 74struct count_chunks { 75 unsigned int chunks; 76 int64_t cur_ptr; 77 unsigned int block_size; 78}; 79 80static void count_data_block(void *priv, int64_t off, void *data, int len) 81{ 82 struct count_chunks *count_chunks = priv; 83 if (off > count_chunks->cur_ptr) 84 count_chunks->chunks++; 85 count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size); 86 count_chunks->chunks++; 87} 88 89static void count_fill_block(void *priv, int64_t off, unsigned int fill_val, int len) 90{ 91 struct count_chunks *count_chunks = priv; 92 if (off > count_chunks->cur_ptr) 93 count_chunks->chunks++; 94 count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size); 95 count_chunks->chunks++; 96} 97 98static void count_file_block(void *priv, int64_t off, const char *file, 99 int64_t offset, int len) 100{ 101 struct count_chunks *count_chunks = priv; 102 if (off > count_chunks->cur_ptr) 103 count_chunks->chunks++; 104 count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size); 105 count_chunks->chunks++; 106} 107 108static int count_sparse_chunks(unsigned int block_size, int64_t len) 109{ 110 struct count_chunks count_chunks = {0, 0, block_size}; 111 112 for_each_data_block(count_data_block, count_file_block, count_fill_block, &count_chunks, block_size); 113 114 if (count_chunks.cur_ptr != len) 115 count_chunks.chunks++; 116 117 return count_chunks.chunks; 118} 119 120static void ext4_write_data_block(void *priv, int64_t off, void *data, int len) 121{ 122 write_data_block(priv, off, data, len); 123} 124 125static void ext4_write_fill_block(void *priv, int64_t off, unsigned int fill_val, int len) 126{ 127 write_fill_block(priv, off, fill_val, len); 128} 129 130static void ext4_write_data_file(void *priv, int64_t off, const char *file, 131 int64_t offset, int len) 132{ 133 write_data_file(priv, off, file, offset, len); 134} 135 136int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, 137 bool crc) 138{ 139 int chunks = count_sparse_chunks(s->block_size, s->len); 140 struct output_file *out = open_output_fd(fd, s->block_size, s->len, 141 gz, sparse, chunks, crc); 142 143 if (!out) 144 return -ENOMEM; 145 146 for_each_data_block(ext4_write_data_block, ext4_write_data_file, ext4_write_fill_block, out, s->block_size); 147 148 if (s->len) 149 pad_output_file(out, s->len); 150 151 close_output_file(out); 152 153 return 0; 154} 155