1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6a54128fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6a54128fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6a54128fSAndroid Build Coastguard Worker *
8*6a54128fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6a54128fSAndroid Build Coastguard Worker *
10*6a54128fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6a54128fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6a54128fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6a54128fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6a54128fSAndroid Build Coastguard Worker * limitations under the License.
15*6a54128fSAndroid Build Coastguard Worker */
16*6a54128fSAndroid Build Coastguard Worker
17*6a54128fSAndroid Build Coastguard Worker #include <libgen.h>
18*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
19*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
20*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
21*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
22*6a54128fSAndroid Build Coastguard Worker #include <ext2fs/ext2fs.h>
23*6a54128fSAndroid Build Coastguard Worker #include <et/com_err.h>
24*6a54128fSAndroid Build Coastguard Worker #include <sparse/sparse.h>
25*6a54128fSAndroid Build Coastguard Worker
26*6a54128fSAndroid Build Coastguard Worker struct {
27*6a54128fSAndroid Build Coastguard Worker bool crc;
28*6a54128fSAndroid Build Coastguard Worker bool sparse;
29*6a54128fSAndroid Build Coastguard Worker bool gzip;
30*6a54128fSAndroid Build Coastguard Worker char *in_file;
31*6a54128fSAndroid Build Coastguard Worker char *out_file;
32*6a54128fSAndroid Build Coastguard Worker bool overwrite_input;
33*6a54128fSAndroid Build Coastguard Worker } params = {
34*6a54128fSAndroid Build Coastguard Worker .sparse = true,
35*6a54128fSAndroid Build Coastguard Worker };
36*6a54128fSAndroid Build Coastguard Worker
37*6a54128fSAndroid Build Coastguard Worker #define ext2fs_fatal(Retval, Format, ...) \
38*6a54128fSAndroid Build Coastguard Worker do { \
39*6a54128fSAndroid Build Coastguard Worker com_err("error", Retval, Format, __VA_ARGS__); \
40*6a54128fSAndroid Build Coastguard Worker exit(EXIT_FAILURE); \
41*6a54128fSAndroid Build Coastguard Worker } while(0)
42*6a54128fSAndroid Build Coastguard Worker
43*6a54128fSAndroid Build Coastguard Worker #define sparse_fatal(Format) \
44*6a54128fSAndroid Build Coastguard Worker do { \
45*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "sparse: "Format); \
46*6a54128fSAndroid Build Coastguard Worker exit(EXIT_FAILURE); \
47*6a54128fSAndroid Build Coastguard Worker } while(0)
48*6a54128fSAndroid Build Coastguard Worker
usage(char * path)49*6a54128fSAndroid Build Coastguard Worker static void usage(char *path)
50*6a54128fSAndroid Build Coastguard Worker {
51*6a54128fSAndroid Build Coastguard Worker char *progname = basename(path);
52*6a54128fSAndroid Build Coastguard Worker
53*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "%s [ options ] <image or block device> <output image>\n"
54*6a54128fSAndroid Build Coastguard Worker " -c include CRC block\n"
55*6a54128fSAndroid Build Coastguard Worker " -z gzip output\n"
56*6a54128fSAndroid Build Coastguard Worker " -S don't use sparse output format\n", progname);
57*6a54128fSAndroid Build Coastguard Worker }
58*6a54128fSAndroid Build Coastguard Worker
59*6a54128fSAndroid Build Coastguard Worker static struct buf_item {
60*6a54128fSAndroid Build Coastguard Worker struct buf_item *next;
61*6a54128fSAndroid Build Coastguard Worker void *buf[];
62*6a54128fSAndroid Build Coastguard Worker } *buf_list;
63*6a54128fSAndroid Build Coastguard Worker
64*6a54128fSAndroid Build Coastguard Worker /*
65*6a54128fSAndroid Build Coastguard Worker * Add @num_blks blocks, starting at index @chunk_start, of the filesystem @fs
66*6a54128fSAndroid Build Coastguard Worker * to the sparse file @s.
67*6a54128fSAndroid Build Coastguard Worker */
add_chunk(ext2_filsys fs,struct sparse_file * s,blk_t chunk_start,int num_blks)68*6a54128fSAndroid Build Coastguard Worker static void add_chunk(ext2_filsys fs, struct sparse_file *s,
69*6a54128fSAndroid Build Coastguard Worker blk_t chunk_start, int num_blks)
70*6a54128fSAndroid Build Coastguard Worker {
71*6a54128fSAndroid Build Coastguard Worker uint64_t len = (uint64_t)num_blks * fs->blocksize;
72*6a54128fSAndroid Build Coastguard Worker int64_t offset = (int64_t)chunk_start * fs->blocksize;
73*6a54128fSAndroid Build Coastguard Worker struct buf_item *bi;
74*6a54128fSAndroid Build Coastguard Worker int retval;
75*6a54128fSAndroid Build Coastguard Worker
76*6a54128fSAndroid Build Coastguard Worker if (!params.overwrite_input) {
77*6a54128fSAndroid Build Coastguard Worker if (sparse_file_add_file(s, params.in_file, offset, len, chunk_start) < 0)
78*6a54128fSAndroid Build Coastguard Worker sparse_fatal("adding data to the sparse file");
79*6a54128fSAndroid Build Coastguard Worker return;
80*6a54128fSAndroid Build Coastguard Worker }
81*6a54128fSAndroid Build Coastguard Worker
82*6a54128fSAndroid Build Coastguard Worker /* The input file will be overwritten, so make a copy of the blocks. */
83*6a54128fSAndroid Build Coastguard Worker if (len > SIZE_MAX - sizeof(*bi))
84*6a54128fSAndroid Build Coastguard Worker sparse_fatal("filesystem is too large");
85*6a54128fSAndroid Build Coastguard Worker bi = calloc(1, sizeof(*bi) + len);
86*6a54128fSAndroid Build Coastguard Worker if (!bi)
87*6a54128fSAndroid Build Coastguard Worker sparse_fatal("out of memory");
88*6a54128fSAndroid Build Coastguard Worker bi->next = buf_list;
89*6a54128fSAndroid Build Coastguard Worker buf_list = bi;
90*6a54128fSAndroid Build Coastguard Worker retval = io_channel_read_blk64(fs->io, chunk_start, num_blks, bi->buf);
91*6a54128fSAndroid Build Coastguard Worker if (retval)
92*6a54128fSAndroid Build Coastguard Worker ext2fs_fatal(retval, "reading data from %s", params.in_file);
93*6a54128fSAndroid Build Coastguard Worker
94*6a54128fSAndroid Build Coastguard Worker if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0)
95*6a54128fSAndroid Build Coastguard Worker sparse_fatal("adding data to the sparse file");
96*6a54128fSAndroid Build Coastguard Worker }
97*6a54128fSAndroid Build Coastguard Worker
free_chunks(void)98*6a54128fSAndroid Build Coastguard Worker static void free_chunks(void)
99*6a54128fSAndroid Build Coastguard Worker {
100*6a54128fSAndroid Build Coastguard Worker struct buf_item *bi;
101*6a54128fSAndroid Build Coastguard Worker
102*6a54128fSAndroid Build Coastguard Worker while (buf_list) {
103*6a54128fSAndroid Build Coastguard Worker bi = buf_list->next;
104*6a54128fSAndroid Build Coastguard Worker free(buf_list);
105*6a54128fSAndroid Build Coastguard Worker buf_list = bi;
106*6a54128fSAndroid Build Coastguard Worker }
107*6a54128fSAndroid Build Coastguard Worker }
108*6a54128fSAndroid Build Coastguard Worker
fs_blocks_count(ext2_filsys fs)109*6a54128fSAndroid Build Coastguard Worker static blk_t fs_blocks_count(ext2_filsys fs)
110*6a54128fSAndroid Build Coastguard Worker {
111*6a54128fSAndroid Build Coastguard Worker blk64_t blks = ext2fs_blocks_count(fs->super);
112*6a54128fSAndroid Build Coastguard Worker
113*6a54128fSAndroid Build Coastguard Worker /* libsparse assumes 32-bit block numbers. */
114*6a54128fSAndroid Build Coastguard Worker if ((blk_t)blks != blks)
115*6a54128fSAndroid Build Coastguard Worker sparse_fatal("filesystem is too large");
116*6a54128fSAndroid Build Coastguard Worker return blks;
117*6a54128fSAndroid Build Coastguard Worker }
118*6a54128fSAndroid Build Coastguard Worker
ext_to_sparse(const char * in_file)119*6a54128fSAndroid Build Coastguard Worker static struct sparse_file *ext_to_sparse(const char *in_file)
120*6a54128fSAndroid Build Coastguard Worker {
121*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
122*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs;
123*6a54128fSAndroid Build Coastguard Worker struct sparse_file *s;
124*6a54128fSAndroid Build Coastguard Worker int64_t chunk_start = -1;
125*6a54128fSAndroid Build Coastguard Worker blk_t fs_blks, cur_blk;
126*6a54128fSAndroid Build Coastguard Worker
127*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_open(in_file, 0, 0, 0, unix_io_manager, &fs);
128*6a54128fSAndroid Build Coastguard Worker if (retval)
129*6a54128fSAndroid Build Coastguard Worker ext2fs_fatal(retval, "while reading %s", in_file);
130*6a54128fSAndroid Build Coastguard Worker
131*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_block_bitmap(fs);
132*6a54128fSAndroid Build Coastguard Worker if (retval)
133*6a54128fSAndroid Build Coastguard Worker ext2fs_fatal(retval, "while reading block bitmap of %s", in_file);
134*6a54128fSAndroid Build Coastguard Worker
135*6a54128fSAndroid Build Coastguard Worker fs_blks = fs_blocks_count(fs);
136*6a54128fSAndroid Build Coastguard Worker
137*6a54128fSAndroid Build Coastguard Worker s = sparse_file_new(fs->blocksize, (uint64_t)fs_blks * fs->blocksize);
138*6a54128fSAndroid Build Coastguard Worker if (!s)
139*6a54128fSAndroid Build Coastguard Worker sparse_fatal("creating sparse file");
140*6a54128fSAndroid Build Coastguard Worker
141*6a54128fSAndroid Build Coastguard Worker /*
142*6a54128fSAndroid Build Coastguard Worker * The sparse format encodes the size of a chunk (and its header) in a
143*6a54128fSAndroid Build Coastguard Worker * 32-bit unsigned integer (UINT32_MAX)
144*6a54128fSAndroid Build Coastguard Worker * When writing the chunk, the library uses a single call to write().
145*6a54128fSAndroid Build Coastguard Worker * Linux's implementation of the 'write' syscall does not allow transfers
146*6a54128fSAndroid Build Coastguard Worker * larger than INT32_MAX (32-bit _and_ 64-bit systems).
147*6a54128fSAndroid Build Coastguard Worker * Make sure we do not create chunks larger than this limit.
148*6a54128fSAndroid Build Coastguard Worker */
149*6a54128fSAndroid Build Coastguard Worker int32_t max_blk_per_chunk = (INT32_MAX - 12) / fs->blocksize;
150*6a54128fSAndroid Build Coastguard Worker
151*6a54128fSAndroid Build Coastguard Worker /*
152*6a54128fSAndroid Build Coastguard Worker * Iterate through the filesystem's blocks, identifying "chunks" that
153*6a54128fSAndroid Build Coastguard Worker * are contiguous ranges of blocks that are in-use by the filesystem.
154*6a54128fSAndroid Build Coastguard Worker * Add each chunk to the sparse_file.
155*6a54128fSAndroid Build Coastguard Worker */
156*6a54128fSAndroid Build Coastguard Worker for (cur_blk = ext2fs_get_block_bitmap_start2(fs->block_map);
157*6a54128fSAndroid Build Coastguard Worker cur_blk < fs_blks; ++cur_blk) {
158*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_block_bitmap2(fs->block_map, cur_blk)) {
159*6a54128fSAndroid Build Coastguard Worker /*
160*6a54128fSAndroid Build Coastguard Worker * @cur_blk is in-use. Append it to the pending chunk
161*6a54128fSAndroid Build Coastguard Worker * if there is one, otherwise start a new chunk.
162*6a54128fSAndroid Build Coastguard Worker */
163*6a54128fSAndroid Build Coastguard Worker if (chunk_start == -1) {
164*6a54128fSAndroid Build Coastguard Worker chunk_start = cur_blk;
165*6a54128fSAndroid Build Coastguard Worker } else if (cur_blk - chunk_start + 1 == max_blk_per_chunk) {
166*6a54128fSAndroid Build Coastguard Worker /*
167*6a54128fSAndroid Build Coastguard Worker * Appending @cur_blk to the pending chunk made
168*6a54128fSAndroid Build Coastguard Worker * it reach the maximum length, so end it.
169*6a54128fSAndroid Build Coastguard Worker */
170*6a54128fSAndroid Build Coastguard Worker add_chunk(fs, s, chunk_start, max_blk_per_chunk);
171*6a54128fSAndroid Build Coastguard Worker chunk_start = -1;
172*6a54128fSAndroid Build Coastguard Worker }
173*6a54128fSAndroid Build Coastguard Worker } else if (chunk_start != -1) {
174*6a54128fSAndroid Build Coastguard Worker /* @cur_blk is not in-use, so end the pending chunk. */
175*6a54128fSAndroid Build Coastguard Worker add_chunk(fs, s, chunk_start, cur_blk - chunk_start);
176*6a54128fSAndroid Build Coastguard Worker chunk_start = -1;
177*6a54128fSAndroid Build Coastguard Worker }
178*6a54128fSAndroid Build Coastguard Worker }
179*6a54128fSAndroid Build Coastguard Worker /* If there's still a pending chunk, end it. */
180*6a54128fSAndroid Build Coastguard Worker if (chunk_start != -1)
181*6a54128fSAndroid Build Coastguard Worker add_chunk(fs, s, chunk_start, cur_blk - chunk_start);
182*6a54128fSAndroid Build Coastguard Worker
183*6a54128fSAndroid Build Coastguard Worker ext2fs_free(fs);
184*6a54128fSAndroid Build Coastguard Worker return s;
185*6a54128fSAndroid Build Coastguard Worker }
186*6a54128fSAndroid Build Coastguard Worker
same_file(const char * in,const char * out)187*6a54128fSAndroid Build Coastguard Worker static bool same_file(const char *in, const char *out)
188*6a54128fSAndroid Build Coastguard Worker {
189*6a54128fSAndroid Build Coastguard Worker struct stat st1, st2;
190*6a54128fSAndroid Build Coastguard Worker
191*6a54128fSAndroid Build Coastguard Worker if (stat(in, &st1) == -1)
192*6a54128fSAndroid Build Coastguard Worker ext2fs_fatal(errno, "stat %s\n", in);
193*6a54128fSAndroid Build Coastguard Worker if (stat(out, &st2) == -1) {
194*6a54128fSAndroid Build Coastguard Worker if (errno == ENOENT)
195*6a54128fSAndroid Build Coastguard Worker return false;
196*6a54128fSAndroid Build Coastguard Worker ext2fs_fatal(errno, "stat %s\n", out);
197*6a54128fSAndroid Build Coastguard Worker }
198*6a54128fSAndroid Build Coastguard Worker return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
199*6a54128fSAndroid Build Coastguard Worker }
200*6a54128fSAndroid Build Coastguard Worker
main(int argc,char * argv[])201*6a54128fSAndroid Build Coastguard Worker int main(int argc, char *argv[])
202*6a54128fSAndroid Build Coastguard Worker {
203*6a54128fSAndroid Build Coastguard Worker int opt;
204*6a54128fSAndroid Build Coastguard Worker int out_fd;
205*6a54128fSAndroid Build Coastguard Worker struct sparse_file *s;
206*6a54128fSAndroid Build Coastguard Worker
207*6a54128fSAndroid Build Coastguard Worker while ((opt = getopt(argc, argv, "czS")) != -1) {
208*6a54128fSAndroid Build Coastguard Worker switch(opt) {
209*6a54128fSAndroid Build Coastguard Worker case 'c':
210*6a54128fSAndroid Build Coastguard Worker params.crc = true;
211*6a54128fSAndroid Build Coastguard Worker break;
212*6a54128fSAndroid Build Coastguard Worker case 'z':
213*6a54128fSAndroid Build Coastguard Worker params.gzip = true;
214*6a54128fSAndroid Build Coastguard Worker break;
215*6a54128fSAndroid Build Coastguard Worker case 'S':
216*6a54128fSAndroid Build Coastguard Worker params.sparse = false;
217*6a54128fSAndroid Build Coastguard Worker break;
218*6a54128fSAndroid Build Coastguard Worker default:
219*6a54128fSAndroid Build Coastguard Worker usage(argv[0]);
220*6a54128fSAndroid Build Coastguard Worker exit(EXIT_FAILURE);
221*6a54128fSAndroid Build Coastguard Worker }
222*6a54128fSAndroid Build Coastguard Worker }
223*6a54128fSAndroid Build Coastguard Worker if (optind + 1 >= argc) {
224*6a54128fSAndroid Build Coastguard Worker usage(argv[0]);
225*6a54128fSAndroid Build Coastguard Worker exit(EXIT_FAILURE);
226*6a54128fSAndroid Build Coastguard Worker }
227*6a54128fSAndroid Build Coastguard Worker params.in_file = strdup(argv[optind++]);
228*6a54128fSAndroid Build Coastguard Worker params.out_file = strdup(argv[optind]);
229*6a54128fSAndroid Build Coastguard Worker params.overwrite_input = same_file(params.in_file, params.out_file);
230*6a54128fSAndroid Build Coastguard Worker
231*6a54128fSAndroid Build Coastguard Worker s = ext_to_sparse(params.in_file);
232*6a54128fSAndroid Build Coastguard Worker
233*6a54128fSAndroid Build Coastguard Worker out_fd = open(params.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
234*6a54128fSAndroid Build Coastguard Worker if (out_fd == -1)
235*6a54128fSAndroid Build Coastguard Worker ext2fs_fatal(errno, "opening %s\n", params.out_file);
236*6a54128fSAndroid Build Coastguard Worker if (sparse_file_write(s, out_fd, params.gzip, params.sparse, params.crc) < 0)
237*6a54128fSAndroid Build Coastguard Worker sparse_fatal("writing sparse file");
238*6a54128fSAndroid Build Coastguard Worker
239*6a54128fSAndroid Build Coastguard Worker sparse_file_destroy(s);
240*6a54128fSAndroid Build Coastguard Worker
241*6a54128fSAndroid Build Coastguard Worker free(params.in_file);
242*6a54128fSAndroid Build Coastguard Worker free(params.out_file);
243*6a54128fSAndroid Build Coastguard Worker free_chunks();
244*6a54128fSAndroid Build Coastguard Worker close(out_fd);
245*6a54128fSAndroid Build Coastguard Worker
246*6a54128fSAndroid Build Coastguard Worker return 0;
247*6a54128fSAndroid Build Coastguard Worker }
248