OSDN Git Service

am c04808a5: make_ext4fs: fix sepolicy lookup for lost+found
[android-x86/system-extras.git] / ext4_utils / ext2simg.c
1 /*
2  * Copyright (C) 2010 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 #define _FILE_OFFSET_BITS 64
18 #define _LARGEFILE64_SOURCE 1
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <sys/mman.h>
24 #include <fcntl.h>
25 #include <libgen.h>
26 #include <unistd.h>
27
28 #include <sparse/sparse.h>
29
30 #include "ext4_utils.h"
31 #include "make_ext4fs.h"
32 #include "allocate.h"
33
34 #if defined(__APPLE__) && defined(__MACH__)
35 #define off64_t off_t
36 #endif
37
38 #ifndef USE_MINGW /* O_BINARY is windows-specific flag */
39 #define O_BINARY 0
40 #endif
41
42 extern struct fs_info info;
43
44 static int verbose = 0;
45
46 static void usage(char *path)
47 {
48         fprintf(stderr, "%s [ options ] <image or block device> <output image>\n", path);
49         fprintf(stderr, "\n");
50         fprintf(stderr, "  -c include CRC block\n");
51         fprintf(stderr, "  -v verbose output\n");
52         fprintf(stderr, "  -z gzip output\n");
53         fprintf(stderr, "  -S don't use sparse output format\n");
54 }
55
56 static int read_ext(int fd)
57 {
58         off64_t ret;
59         struct ext4_super_block sb;
60         unsigned int i;
61
62         ret = lseek64(fd, 1024, SEEK_SET);
63         if (ret < 0)
64                 critical_error_errno("failed to seek to superblock");
65
66         ret = read(fd, &sb, sizeof(sb));
67         if (ret < 0)
68                 critical_error_errno("failed to read superblock");
69         if (ret != sizeof(sb))
70                 critical_error("failed to read all of superblock");
71
72         ext4_parse_sb(&sb);
73
74         ret = lseek64(fd, info.len, SEEK_SET);
75         if (ret < 0)
76                 critical_error_errno("failed to seek to end of input image");
77
78         ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
79         if (ret < 0)
80                 critical_error_errno("failed to seek to block group descriptors");
81
82         ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
83         if (ret < 0)
84                 critical_error_errno("failed to read block group descriptors");
85         if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
86                 critical_error("failed to read all of block group descriptors");
87
88         if (verbose) {
89                 printf("Found filesystem with parameters:\n");
90                 printf("    Size: %llu\n", info.len);
91                 printf("    Block size: %d\n", info.block_size);
92                 printf("    Blocks per group: %d\n", info.blocks_per_group);
93                 printf("    Inodes per group: %d\n", info.inodes_per_group);
94                 printf("    Inode size: %d\n", info.inode_size);
95                 printf("    Label: %s\n", info.label);
96                 printf("    Blocks: %llu\n", aux_info.len_blocks);
97                 printf("    Block groups: %d\n", aux_info.groups);
98                 printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
99                 printf("    Used %d/%d inodes and %d/%d blocks\n",
100                                 aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
101                                 aux_info.sb->s_inodes_count,
102                                 aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
103                                 aux_info.sb->s_blocks_count_lo);
104         }
105
106         return 0;
107 }
108
109 static int bitmap_get_bit(u8 *bitmap, u32 bit)
110 {
111         if (bitmap[bit / 8] & 1 << (bit % 8))
112                 return 1;
113
114         return 0;
115 }
116
117 static int build_sparse_ext(int fd, const char *filename)
118 {
119         unsigned int i;
120         unsigned int block;
121         int start_contiguous_block;
122         u8 *block_bitmap;
123         off64_t ret;
124
125         block_bitmap = malloc(info.block_size);
126         if (!block_bitmap)
127                 critical_error("failed to allocate block bitmap");
128
129         if (aux_info.first_data_block > 0)
130                 sparse_file_add_file(info.sparse_file, filename, 0,
131                                 info.block_size * aux_info.first_data_block, 0);
132
133         for (i = 0; i < aux_info.groups; i++) {
134                 u32 first_block = aux_info.first_data_block + i * info.blocks_per_group;
135                 u32 last_block = min(info.blocks_per_group, aux_info.len_blocks - first_block);
136
137                 ret = lseek64(fd, (u64)info.block_size * aux_info.bg_desc[i].bg_block_bitmap,
138                                 SEEK_SET);
139                 if (ret < 0)
140                         critical_error_errno("failed to seek to block group bitmap %d", i);
141
142                 ret = read(fd, block_bitmap, info.block_size);
143                 if (ret < 0)
144                         critical_error_errno("failed to read block group bitmap %d", i);
145                 if (ret != (int)info.block_size)
146                         critical_error("failed to read all of block group bitmap %d", i);
147
148                 start_contiguous_block = -1;
149                 for (block = 0; block < last_block; block++) {
150                         if (start_contiguous_block >= 0) {
151                                 if (!bitmap_get_bit(block_bitmap, block)) {
152                                         u32 start_block = first_block + start_contiguous_block;
153                                         u32 len_blocks = block - start_contiguous_block;
154
155                                         sparse_file_add_file(info.sparse_file, filename,
156                                                         (u64)info.block_size * start_block,
157                                                         info.block_size * len_blocks, start_block);
158                                         start_contiguous_block = -1;
159                                 }
160                         } else {
161                                 if (bitmap_get_bit(block_bitmap, block))
162                                         start_contiguous_block = block;
163                         }
164                 }
165
166                 if (start_contiguous_block >= 0) {
167                         u32 start_block = first_block + start_contiguous_block;
168                         u32 len_blocks = last_block - start_contiguous_block;
169                         sparse_file_add_file(info.sparse_file, filename,
170                                         (u64)info.block_size * start_block,
171                                         info.block_size * len_blocks, start_block);
172                 }
173         }
174
175         return 0;
176 }
177
178 int main(int argc, char **argv)
179 {
180         int opt;
181         const char *in = NULL;
182         const char *out = NULL;
183         int gzip = 0;
184         int sparse = 1;
185         int infd, outfd;
186         int crc = 0;
187
188         while ((opt = getopt(argc, argv, "cvzS")) != -1) {
189                 switch (opt) {
190                 case 'c':
191                         crc = 1;
192                         break;
193                 case 'v':
194                         verbose = 1;
195                         break;
196                 case 'z':
197                         gzip = 1;
198                         break;
199                 case 'S':
200                         sparse = 0;
201                         break;
202                 }
203         }
204
205         if (optind >= argc) {
206                 fprintf(stderr, "Expected image or block device after options\n");
207                 usage(argv[0]);
208                 exit(EXIT_FAILURE);
209         }
210
211         in = argv[optind++];
212
213         if (optind >= argc) {
214                 fprintf(stderr, "Expected output image after input image\n");
215                 usage(argv[0]);
216                 exit(EXIT_FAILURE);
217         }
218
219         out = argv[optind++];
220
221         if (optind < argc) {
222                 fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
223                 usage(argv[0]);
224                 exit(EXIT_FAILURE);
225         }
226
227         infd = open(in, O_RDONLY);
228
229         if (infd < 0)
230                 critical_error_errno("failed to open input image");
231
232         read_ext(infd);
233
234         info.sparse_file = sparse_file_new(info.block_size, info.len);
235
236         build_sparse_ext(infd, in);
237
238         close(infd);
239
240         if (strcmp(out, "-")) {
241                 outfd = open(out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
242                 if (outfd < 0) {
243                         error_errno("open");
244                         return EXIT_FAILURE;
245                 }
246         } else {
247                 outfd = STDOUT_FILENO;
248         }
249
250         write_ext4_image(outfd, gzip, sparse, crc);
251         close(outfd);
252
253         sparse_file_destroy(info.sparse_file);
254
255         return 0;
256 }