blob: fce9dbbb65a8f22e8975c5926ea8b0890c1cec56 [file] [log] [blame]
Colin Cross28fa5bc2012-05-20 13:28:05 -07001/*
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
Colin Crossb55dcee2012-04-24 23:07:49 -070017#include <assert.h>
Colin Cross28fa5bc2012-05-20 13:28:05 -070018#include <stdlib.h>
19
20#include <sparse/sparse.h>
21
22#include "sparse_file.h"
23
24#include "output_file.h"
25#include "backed_block.h"
26#include "sparse_defs.h"
27
Colin Cross28fa5bc2012-05-20 13:28:05 -070028struct 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
Colin Cross411619e2012-04-24 18:51:42 -070035 s->backed_block_list = backed_block_list_new();
36 if (!s->backed_block_list) {
37 free(s);
38 return NULL;
39 }
Colin Cross28fa5bc2012-05-20 13:28:05 -070040
41 s->block_size = block_size;
42 s->len = len;
43
44 return s;
45}
46
47void sparse_file_destroy(struct sparse_file *s)
48{
Colin Cross411619e2012-04-24 18:51:42 -070049 backed_block_list_destroy(s->backed_block_list);
Colin Cross28fa5bc2012-05-20 13:28:05 -070050 free(s);
51}
52
53int sparse_file_add_data(struct sparse_file *s,
54 void *data, unsigned int len, unsigned int block)
55{
Colin Crossb55dcee2012-04-24 23:07:49 -070056 return backed_block_add_data(s->backed_block_list, data, len, block);
Colin Cross28fa5bc2012-05-20 13:28:05 -070057}
58
59int sparse_file_add_fill(struct sparse_file *s,
60 uint32_t fill_val, unsigned int len, unsigned int block)
61{
Colin Crossb55dcee2012-04-24 23:07:49 -070062 return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
Colin Cross28fa5bc2012-05-20 13:28:05 -070063}
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{
Colin Crossb55dcee2012-04-24 23:07:49 -070069 return backed_block_add_file(s->backed_block_list, filename, file_offset,
70 len, block);
Colin Cross28fa5bc2012-05-20 13:28:05 -070071}
72
Colin Crossb55dcee2012-04-24 23:07:49 -070073unsigned int sparse_count_chunks(struct sparse_file *s)
Colin Cross28fa5bc2012-05-20 13:28:05 -070074{
Colin Crossb55dcee2012-04-24 23:07:49 -070075 struct backed_block *bb;
76 unsigned int last_block = 0;
77 unsigned int chunks = 0;
Colin Cross28fa5bc2012-05-20 13:28:05 -070078
Colin Crossb55dcee2012-04-24 23:07:49 -070079 for (bb = backed_block_iter_new(s->backed_block_list); bb;
80 bb = backed_block_iter_next(bb)) {
81 if (backed_block_block(bb) > last_block) {
82 /* If there is a gap between chunks, add a skip chunk */
83 chunks++;
84 }
85 chunks++;
86 last_block = backed_block_block(bb) +
87 DIV_ROUND_UP(backed_block_len(bb), s->block_size);
88 }
89 if (last_block < DIV_ROUND_UP(s->len, s->block_size)) {
90 chunks++;
91 }
Colin Cross28fa5bc2012-05-20 13:28:05 -070092
Colin Crossb55dcee2012-04-24 23:07:49 -070093 return chunks;
Colin Cross28fa5bc2012-05-20 13:28:05 -070094}
95
96int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
97 bool crc)
98{
Colin Crossb55dcee2012-04-24 23:07:49 -070099 struct backed_block *bb;
100 unsigned int last_block = 0;
101 int64_t pad;
102 int chunks;
103 struct output_file *out;
104
105 chunks = sparse_count_chunks(s);
106 out = open_output_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700107
108 if (!out)
109 return -ENOMEM;
110
Colin Crossb55dcee2012-04-24 23:07:49 -0700111 for (bb = backed_block_iter_new(s->backed_block_list); bb;
112 bb = backed_block_iter_next(bb)) {
113 if (backed_block_block(bb) > last_block) {
114 unsigned int blocks = backed_block_block(bb) - last_block;
115 write_skip_chunk(out, (int64_t)blocks * s->block_size);
116 }
117 switch (backed_block_type(bb)) {
118 case BACKED_BLOCK_DATA:
119 write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
120 break;
121 case BACKED_BLOCK_FILE:
122 write_file_chunk(out, backed_block_len(bb),
123 backed_block_filename(bb), backed_block_file_offset(bb));
124 break;
125 case BACKED_BLOCK_FILL:
126 write_fill_chunk(out, backed_block_len(bb),
127 backed_block_fill_val(bb));
128 break;
129 }
130 last_block = backed_block_block(bb) +
131 DIV_ROUND_UP(backed_block_len(bb), s->block_size);
132 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700133
Colin Crossb55dcee2012-04-24 23:07:49 -0700134 pad = s->len - last_block * s->block_size;
135 assert(pad >= 0);
136 if (pad > 0) {
137 write_skip_chunk(out, pad);
138 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700139
140 close_output_file(out);
141
142 return 0;
143}