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 #include "ext4_utils/ext4_utils.h"
18
19 #include <fcntl.h>
20 #include <inttypes.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #ifdef _WIN32
27 #include <winsock2.h>
28 #else
29 #include <arpa/inet.h>
30 #include <sys/ioctl.h>
31 #endif
32
33 #if defined(__linux__)
34 #include <linux/fs.h>
35 #elif defined(__APPLE__) && defined(__MACH__)
36 #include <sys/disk.h>
37 #endif
38
39 #include "helpers.h"
40
41 int force = 0;
42 struct fs_info info;
43 struct fs_aux_info aux_info;
44
45 jmp_buf setjmp_env;
46
47 /* returns 1 if a is a power of b */
is_power_of(int a,int b)48 static int is_power_of(int a, int b)
49 {
50 while (a > b) {
51 if (a % b)
52 return 0;
53 a /= b;
54 }
55
56 return (a == b) ? 1 : 0;
57 }
58
bitmap_get_bit(u8 * bitmap,u32 bit)59 int bitmap_get_bit(u8 *bitmap, u32 bit)
60 {
61 if (bitmap[bit / 8] & (1 << (bit % 8)))
62 return 1;
63
64 return 0;
65 }
66
bitmap_clear_bit(u8 * bitmap,u32 bit)67 void bitmap_clear_bit(u8 *bitmap, u32 bit)
68 {
69 bitmap[bit / 8] &= ~(1 << (bit % 8));
70
71 return;
72 }
73
74 /* Returns 1 if the bg contains a backup superblock. On filesystems with
75 the sparse_super feature, only block groups 0, 1, and powers of 3, 5,
76 and 7 have backup superblocks. Otherwise, all block groups have backup
77 superblocks */
ext4_bg_has_super_block(int bg)78 int ext4_bg_has_super_block(int bg)
79 {
80 /* Without sparse_super, every block group has a superblock */
81 if (!(info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
82 return 1;
83
84 if (bg == 0 || bg == 1)
85 return 1;
86
87 if (is_power_of(bg, 3) || is_power_of(bg, 5) || is_power_of(bg, 7))
88 return 1;
89
90 return 0;
91 }
92
93 /* Function to read the primary superblock */
read_sb(int fd,struct ext4_super_block * sb)94 void read_sb(int fd, struct ext4_super_block *sb)
95 {
96 off64_t ret;
97
98 ret = lseek64(fd, 1024, SEEK_SET);
99 if (ret < 0)
100 critical_error_errno("failed to seek to superblock");
101
102 ret = read(fd, sb, sizeof(*sb));
103 if (ret < 0)
104 critical_error_errno("failed to read superblock");
105 if (ret != sizeof(*sb))
106 critical_error("failed to read all of superblock");
107 }
108
109 /* Compute the rest of the parameters of the filesystem from the basic info */
ext4_create_fs_aux_info()110 void ext4_create_fs_aux_info()
111 {
112 aux_info.first_data_block = (info.block_size > 1024) ? 0 : 1;
113 aux_info.len_blocks = info.len / info.block_size;
114 aux_info.inode_table_blocks = DIV_ROUND_UP(info.inodes_per_group * info.inode_size,
115 info.block_size);
116 aux_info.groups = DIV_ROUND_UP(aux_info.len_blocks - aux_info.first_data_block,
117 info.blocks_per_group);
118 aux_info.blocks_per_ind = info.block_size / sizeof(u32);
119 aux_info.blocks_per_dind = aux_info.blocks_per_ind * aux_info.blocks_per_ind;
120 aux_info.blocks_per_tind = aux_info.blocks_per_dind * aux_info.blocks_per_dind;
121
122 aux_info.bg_desc_blocks =
123 DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc),
124 info.block_size);
125
126 aux_info.default_i_flags = EXT4_NOATIME_FL;
127
128 u32 last_group_size = aux_info.len_blocks == info.blocks_per_group
129 ? aux_info.len_blocks : aux_info.len_blocks % info.blocks_per_group;
130 u32 last_header_size = 2 + aux_info.inode_table_blocks;
131 if (ext4_bg_has_super_block((int)aux_info.groups - 1))
132 last_header_size += 1 + aux_info.bg_desc_blocks +
133 info.bg_desc_reserve_blocks;
134 if (aux_info.groups <= 1 && last_group_size < last_header_size) {
135 critical_error("filesystem size too small");
136 }
137 if (last_group_size > 0 && last_group_size < last_header_size) {
138 aux_info.groups--;
139 aux_info.len_blocks -= last_group_size;
140 }
141
142 /* A zero-filled superblock to be written firstly to the block
143 * device to mark the file-system as invalid
144 */
145 aux_info.sb_zero = (struct ext4_super_block *)calloc(1, info.block_size);
146 if (!aux_info.sb_zero)
147 critical_error_errno("calloc");
148
149 /* The write_data* functions expect only block aligned calls.
150 * This is not an issue, except when we write out the super
151 * block on a system with a block size > 1K. So, we need to
152 * deal with that here.
153 */
154 aux_info.sb_block = (struct ext4_super_block *)calloc(1, info.block_size);
155 if (!aux_info.sb_block)
156 critical_error_errno("calloc");
157
158 if (info.block_size > 1024)
159 aux_info.sb = (struct ext4_super_block *)((char *)aux_info.sb_block + 1024);
160 else
161 aux_info.sb = aux_info.sb_block;
162
163 /* Alloc an array to hold the pointers to the backup superblocks */
164 aux_info.backup_sb = (struct ext4_super_block **)calloc(aux_info.groups, sizeof(char *));
165
166 if (!aux_info.sb)
167 critical_error_errno("calloc");
168
169 aux_info.bg_desc = (struct ext2_group_desc *)calloc(info.block_size, aux_info.bg_desc_blocks);
170 if (!aux_info.bg_desc)
171 critical_error_errno("calloc");
172 aux_info.xattrs = NULL;
173 }
174
ext4_free_fs_aux_info()175 void ext4_free_fs_aux_info()
176 {
177 unsigned int i;
178
179 for (i=0; i<aux_info.groups; i++) {
180 if (aux_info.backup_sb[i])
181 free(aux_info.backup_sb[i]);
182 }
183 free(aux_info.sb_block);
184 free(aux_info.sb_zero);
185 free(aux_info.bg_desc);
186 }
187
ext4_parse_sb_info(struct ext4_super_block * sb)188 void ext4_parse_sb_info(struct ext4_super_block *sb)
189 {
190 if (sb->s_magic != EXT4_SUPER_MAGIC)
191 error("superblock magic incorrect");
192
193 if ((sb->s_state & EXT4_VALID_FS) != EXT4_VALID_FS)
194 error("filesystem state not valid");
195
196 ext4_parse_sb(sb, &info);
197
198 ext4_create_fs_aux_info();
199
200 memcpy(aux_info.sb, sb, sizeof(*sb));
201
202 if (aux_info.first_data_block != sb->s_first_data_block)
203 critical_error("first data block does not match");
204 }
205
get_block_device_size(int fd)206 u64 get_block_device_size(int fd)
207 {
208 u64 size = 0;
209 int ret;
210
211 #if defined(__linux__)
212 ret = ioctl(fd, BLKGETSIZE64, &size);
213 #elif defined(__APPLE__) && defined(__MACH__)
214 ret = ioctl(fd, DKIOCGETBLOCKCOUNT, &size);
215 #else
216 close(fd);
217 return 0;
218 #endif
219
220 if (ret)
221 return 0;
222
223 return size;
224 }
225
is_block_device_fd(int fd)226 int is_block_device_fd(int fd __attribute__((unused)))
227 {
228 #ifdef _WIN32
229 return 0;
230 #else
231 struct stat st;
232 int ret = fstat(fd, &st);
233 if (ret < 0)
234 return 0;
235
236 return S_ISBLK(st.st_mode);
237 #endif
238 }
239
get_file_size(int fd)240 u64 get_file_size(int fd)
241 {
242 struct stat buf;
243 int ret;
244 u64 reserve_len = 0;
245 s64 computed_size;
246
247 ret = fstat(fd, &buf);
248 if (ret)
249 return 0;
250
251 if (info.len < 0)
252 reserve_len = -info.len;
253
254 if (S_ISREG(buf.st_mode))
255 computed_size = buf.st_size - reserve_len;
256 else if (S_ISBLK(buf.st_mode))
257 computed_size = get_block_device_size(fd) - reserve_len;
258 else
259 computed_size = 0;
260
261 if (computed_size < 0) {
262 warn("Computed filesystem size less than 0");
263 computed_size = 0;
264 }
265
266 return computed_size;
267 }
268
read_ext(int fd,int verbose)269 int read_ext(int fd, int verbose)
270 {
271 off64_t ret;
272 struct ext4_super_block sb;
273
274 read_sb(fd, &sb);
275
276 ext4_parse_sb_info(&sb);
277
278 ret = lseek64(fd, info.len, SEEK_SET);
279 if (ret < 0)
280 critical_error_errno("failed to seek to end of input image");
281
282 ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
283 if (ret < 0)
284 critical_error_errno("failed to seek to block group descriptors");
285
286 ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
287 if (ret < 0)
288 critical_error_errno("failed to read block group descriptors");
289 if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
290 critical_error("failed to read all of block group descriptors");
291
292 if (verbose) {
293 printf("Found filesystem with parameters:\n");
294 printf(" Size: %" PRIu64 "\n", info.len);
295 printf(" Block size: %d\n", info.block_size);
296 printf(" Blocks per group: %d\n", info.blocks_per_group);
297 printf(" Inodes per group: %d\n", info.inodes_per_group);
298 printf(" Inode size: %d\n", info.inode_size);
299 printf(" Label: %s\n", info.label);
300 printf(" Blocks: %" PRIext4u64 "\n", aux_info.len_blocks);
301 printf(" Block groups: %d\n", aux_info.groups);
302 printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
303 printf(" Used %d/%d inodes and %d/%d blocks\n",
304 aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
305 aux_info.sb->s_inodes_count,
306 aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
307 aux_info.sb->s_blocks_count_lo);
308 }
309
310 return 0;
311 }
312
313