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