sparse.c revision 9e1f17e926fa20255c5f4b4d2f68aa98a964253a
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
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{
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
10228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
10328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		bool crc)
10428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{
105b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	struct backed_block *bb;
106b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	unsigned int last_block = 0;
107b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int64_t pad;
108b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	int chunks;
109b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	struct output_file *out;
110b55dceea986ab24f8b836b5116b389ed619c816eColin Cross
111b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	chunks = sparse_count_chunks(s);
112b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	out = open_output_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
11328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
11428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	if (!out)
11528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross		return -ENOMEM;
11628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
117b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	for (bb = backed_block_iter_new(s->backed_block_list); bb;
118b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			bb = backed_block_iter_next(bb)) {
119b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		if (backed_block_block(bb) > last_block) {
120b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			unsigned int blocks = backed_block_block(bb) - last_block;
121b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			write_skip_chunk(out, (int64_t)blocks * s->block_size);
122b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		}
123b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		switch (backed_block_type(bb)) {
124b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		case BACKED_BLOCK_DATA:
125b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
126b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			break;
127b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		case BACKED_BLOCK_FILE:
128b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			write_file_chunk(out, backed_block_len(bb),
129b55dceea986ab24f8b836b5116b389ed619c816eColin Cross					backed_block_filename(bb), backed_block_file_offset(bb));
130b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			break;
1319e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross		case BACKED_BLOCK_FD:
1329e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross			write_fd_chunk(out, backed_block_len(bb),
1339e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross					backed_block_fd(bb), backed_block_file_offset(bb));
1349e1f17e926fa20255c5f4b4d2f68aa98a964253aColin Cross			break;
135b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		case BACKED_BLOCK_FILL:
136b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			write_fill_chunk(out, backed_block_len(bb),
137b55dceea986ab24f8b836b5116b389ed619c816eColin Cross					backed_block_fill_val(bb));
138b55dceea986ab24f8b836b5116b389ed619c816eColin Cross			break;
139b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		}
140b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		last_block = backed_block_block(bb) +
141b55dceea986ab24f8b836b5116b389ed619c816eColin Cross				DIV_ROUND_UP(backed_block_len(bb), s->block_size);
142b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
14328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
144b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	pad = s->len - last_block * s->block_size;
145b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	assert(pad >= 0);
146b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	if (pad > 0) {
147b55dceea986ab24f8b836b5116b389ed619c816eColin Cross		write_skip_chunk(out, pad);
148b55dceea986ab24f8b836b5116b389ed619c816eColin Cross	}
14928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
15028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	close_output_file(out);
15128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross
15228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross	return 0;
15328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross}
154