diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-12 11:17:49 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-12 11:17:49 +0000 |
commit | d5e305944a9db25f57b252cc9f56c18311e68481 (patch) | |
tree | 5f76ea7623209d379a9ea34bfa943ef86af2032a /util-linux/volume_id/fat.c | |
parent | cdd1f732bc5b8447dd12b59613663b7d08fce20b (diff) | |
download | busybox-w32-d5e305944a9db25f57b252cc9f56c18311e68481.tar.gz busybox-w32-d5e305944a9db25f57b252cc9f56c18311e68481.tar.bz2 busybox-w32-d5e305944a9db25f57b252cc9f56c18311e68481.zip |
findfs: fix LUKS and FAT detection routines; do not exit if corrupted
FAT fs makes us try to seek past volume
function old new delta
volume_id_get_buffer 301 327 +26
volume_id_probe_luks 79 82 +3
get_attr_volume_id 73 65 -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 29/-8) Total: 21 bytes
Diffstat (limited to 'util-linux/volume_id/fat.c')
-rw-r--r-- | util-linux/volume_id/fat.c | 128 |
1 files changed, 62 insertions, 66 deletions
diff --git a/util-linux/volume_id/fat.c b/util-linux/volume_id/fat.c index 9ab1cef02..816d69d4c 100644 --- a/util-linux/volume_id/fat.c +++ b/util-linux/volume_id/fat.c | |||
@@ -20,8 +20,11 @@ | |||
20 | 20 | ||
21 | #include "volume_id_internal.h" | 21 | #include "volume_id_internal.h" |
22 | 22 | ||
23 | #define FAT12_MAX 0xff5 | 23 | /* linux/msdos_fs.h says: */ |
24 | #define FAT16_MAX 0xfff5 | 24 | #define FAT12_MAX 0xff4 |
25 | #define FAT16_MAX 0xfff4 | ||
26 | #define FAT32_MAX 0x0ffffff6 | ||
27 | |||
25 | #define FAT_ATTR_VOLUME_ID 0x08 | 28 | #define FAT_ATTR_VOLUME_ID 0x08 |
26 | #define FAT_ATTR_DIR 0x10 | 29 | #define FAT_ATTR_DIR 0x10 |
27 | #define FAT_ATTR_LONG_NAME 0x0f | 30 | #define FAT_ATTR_LONG_NAME 0x0f |
@@ -31,9 +34,9 @@ | |||
31 | struct vfat_super_block { | 34 | struct vfat_super_block { |
32 | uint8_t boot_jump[3]; | 35 | uint8_t boot_jump[3]; |
33 | uint8_t sysid[8]; | 36 | uint8_t sysid[8]; |
34 | uint16_t sector_size; | 37 | uint16_t sector_size_bytes; |
35 | uint8_t sectors_per_cluster; | 38 | uint8_t sectors_per_cluster; |
36 | uint16_t reserved; | 39 | uint16_t reserved_sct; |
37 | uint8_t fats; | 40 | uint8_t fats; |
38 | uint16_t dir_entries; | 41 | uint16_t dir_entries; |
39 | uint16_t sectors; | 42 | uint16_t sectors; |
@@ -84,32 +87,30 @@ struct vfat_dir_entry { | |||
84 | uint32_t size; | 87 | uint32_t size; |
85 | } __attribute__((__packed__)); | 88 | } __attribute__((__packed__)); |
86 | 89 | ||
87 | static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned count) | 90 | static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, int count) |
88 | { | 91 | { |
89 | unsigned i; | 92 | for (;--count >= 0; dir++) { |
90 | |||
91 | for (i = 0; i < count; i++) { | ||
92 | /* end marker */ | 93 | /* end marker */ |
93 | if (dir[i].name[0] == 0x00) { | 94 | if (dir->name[0] == 0x00) { |
94 | dbg("end of dir"); | 95 | dbg("end of dir"); |
95 | break; | 96 | break; |
96 | } | 97 | } |
97 | 98 | ||
98 | /* empty entry */ | 99 | /* empty entry */ |
99 | if (dir[i].name[0] == FAT_ENTRY_FREE) | 100 | if (dir->name[0] == FAT_ENTRY_FREE) |
100 | continue; | 101 | continue; |
101 | 102 | ||
102 | /* long name */ | 103 | /* long name */ |
103 | if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) | 104 | if ((dir->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) |
104 | continue; | 105 | continue; |
105 | 106 | ||
106 | if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { | 107 | if ((dir->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { |
107 | /* labels do not have file data */ | 108 | /* labels do not have file data */ |
108 | if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) | 109 | if (dir->cluster_high != 0 || dir->cluster_low != 0) |
109 | continue; | 110 | continue; |
110 | 111 | ||
111 | dbg("found ATTR_VOLUME_ID id in root dir"); | 112 | dbg("found ATTR_VOLUME_ID id in root dir"); |
112 | return dir[i].name; | 113 | return dir->name; |
113 | } | 114 | } |
114 | 115 | ||
115 | dbg("skip dir entry"); | 116 | dbg("skip dir entry"); |
@@ -118,31 +119,29 @@ static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned count) | |||
118 | return NULL; | 119 | return NULL; |
119 | } | 120 | } |
120 | 121 | ||
121 | int volume_id_probe_vfat(struct volume_id *id, uint64_t off) | 122 | int volume_id_probe_vfat(struct volume_id *id, uint64_t fat_partition_off) |
122 | { | 123 | { |
123 | struct vfat_super_block *vs; | 124 | struct vfat_super_block *vs; |
124 | struct vfat_dir_entry *dir; | 125 | struct vfat_dir_entry *dir; |
125 | uint16_t sector_size; | 126 | uint16_t sector_size_bytes; |
126 | uint16_t dir_entries; | 127 | uint16_t dir_entries; |
127 | uint32_t sect_count; | 128 | uint32_t sect_count; |
128 | uint16_t reserved; | 129 | uint16_t reserved_sct; |
129 | uint32_t fat_size; | 130 | uint32_t fat_size_sct; |
130 | uint32_t root_cluster; | 131 | uint32_t root_cluster; |
131 | uint32_t dir_size; | 132 | uint32_t dir_size_sct; |
132 | uint32_t cluster_count; | 133 | uint32_t cluster_count; |
133 | uint32_t fat_length; | 134 | uint64_t root_start_off; |
134 | uint64_t root_start; | 135 | uint32_t start_data_sct; |
135 | uint32_t start_data_sect; | ||
136 | uint16_t root_dir_entries; | ||
137 | uint8_t *buf; | 136 | uint8_t *buf; |
138 | uint32_t buf_size; | 137 | uint32_t buf_size; |
139 | uint8_t *label = NULL; | 138 | uint8_t *label = NULL; |
140 | uint32_t next; | 139 | uint32_t next_cluster; |
141 | int maxloop; | 140 | int maxloop; |
142 | 141 | ||
143 | dbg("probing at offset 0x%llx", (unsigned long long) off); | 142 | dbg("probing at offset 0x%llx", (unsigned long long) fat_partition_off); |
144 | 143 | ||
145 | vs = volume_id_get_buffer(id, off, 0x200); | 144 | vs = volume_id_get_buffer(id, fat_partition_off, 0x200); |
146 | if (vs == NULL) | 145 | if (vs == NULL) |
147 | return -1; | 146 | return -1; |
148 | 147 | ||
@@ -196,34 +195,34 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) | |||
196 | 195 | ||
197 | valid: | 196 | valid: |
198 | /* sector size check */ | 197 | /* sector size check */ |
199 | sector_size = le16_to_cpu(vs->sector_size); | 198 | sector_size_bytes = le16_to_cpu(vs->sector_size_bytes); |
200 | if (sector_size != 0x200 && sector_size != 0x400 && | 199 | if (sector_size_bytes != 0x200 && sector_size_bytes != 0x400 && |
201 | sector_size != 0x800 && sector_size != 0x1000) | 200 | sector_size_bytes != 0x800 && sector_size_bytes != 0x1000) |
202 | return -1; | 201 | return -1; |
203 | 202 | ||
204 | dbg("sector_size 0x%x", sector_size); | 203 | dbg("sector_size_bytes 0x%x", sector_size_bytes); |
205 | dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster); | 204 | dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster); |
206 | 205 | ||
207 | dir_entries = le16_to_cpu(vs->dir_entries); | 206 | reserved_sct = le16_to_cpu(vs->reserved_sct); |
208 | reserved = le16_to_cpu(vs->reserved); | 207 | dbg("reserved_sct 0x%x", reserved_sct); |
209 | dbg("reserved 0x%x", reserved); | ||
210 | 208 | ||
211 | sect_count = le16_to_cpu(vs->sectors); | 209 | sect_count = le16_to_cpu(vs->sectors); |
212 | if (sect_count == 0) | 210 | if (sect_count == 0) |
213 | sect_count = le32_to_cpu(vs->total_sect); | 211 | sect_count = le32_to_cpu(vs->total_sect); |
214 | dbg("sect_count 0x%x", sect_count); | 212 | dbg("sect_count 0x%x", sect_count); |
215 | 213 | ||
216 | fat_length = le16_to_cpu(vs->fat_length); | 214 | fat_size_sct = le16_to_cpu(vs->fat_length); |
217 | if (fat_length == 0) | 215 | if (fat_size_sct == 0) |
218 | fat_length = le32_to_cpu(vs->type.fat32.fat32_length); | 216 | fat_size_sct = le32_to_cpu(vs->type.fat32.fat32_length); |
219 | dbg("fat_length 0x%x", fat_length); | 217 | fat_size_sct *= vs->fats; |
218 | dbg("fat_size_sct 0x%x", fat_size_sct); | ||
220 | 219 | ||
221 | fat_size = fat_length * vs->fats; | 220 | dir_entries = le16_to_cpu(vs->dir_entries); |
222 | dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + | 221 | dir_size_sct = ((dir_entries * sizeof(struct vfat_dir_entry)) + |
223 | (sector_size-1)) / sector_size; | 222 | (sector_size_bytes-1)) / sector_size_bytes; |
224 | dbg("dir_size 0x%x", dir_size); | 223 | dbg("dir_size_sct 0x%x", dir_size_sct); |
225 | 224 | ||
226 | cluster_count = sect_count - (reserved + fat_size + dir_size); | 225 | cluster_count = sect_count - (reserved_sct + fat_size_sct + dir_size_sct); |
227 | cluster_count /= vs->sectors_per_cluster; | 226 | cluster_count /= vs->sectors_per_cluster; |
228 | dbg("cluster_count 0x%x", cluster_count); | 227 | dbg("cluster_count 0x%x", cluster_count); |
229 | 228 | ||
@@ -239,21 +238,18 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) | |||
239 | goto fat32; | 238 | goto fat32; |
240 | 239 | ||
241 | /* the label may be an attribute in the root directory */ | 240 | /* the label may be an attribute in the root directory */ |
242 | root_start = (reserved + fat_size) * sector_size; | 241 | root_start_off = (reserved_sct + fat_size_sct) * sector_size_bytes; |
243 | dbg("root dir start 0x%llx", (unsigned long long) root_start); | 242 | dbg("root dir start 0x%llx", (unsigned long long) root_start_off); |
244 | root_dir_entries = le16_to_cpu(vs->dir_entries); | 243 | dbg("expected entries 0x%x", dir_entries); |
245 | dbg("expected entries 0x%x", root_dir_entries); | ||
246 | 244 | ||
247 | buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); | 245 | buf_size = dir_entries * sizeof(struct vfat_dir_entry); |
248 | buf = volume_id_get_buffer(id, off + root_start, buf_size); | 246 | buf = volume_id_get_buffer(id, fat_partition_off + root_start_off, buf_size); |
249 | if (buf == NULL) | 247 | if (buf == NULL) |
250 | goto found; | 248 | goto found; |
251 | 249 | ||
252 | dir = (struct vfat_dir_entry*) buf; | 250 | label = get_attr_volume_id((struct vfat_dir_entry*) buf, dir_entries); |
253 | |||
254 | label = get_attr_volume_id(dir, root_dir_entries); | ||
255 | 251 | ||
256 | vs = volume_id_get_buffer(id, off, 0x200); | 252 | vs = volume_id_get_buffer(id, fat_partition_off, 0x200); |
257 | if (vs == NULL) | 253 | if (vs == NULL) |
258 | return -1; | 254 | return -1; |
259 | 255 | ||
@@ -269,26 +265,25 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) | |||
269 | 265 | ||
270 | fat32: | 266 | fat32: |
271 | /* FAT32 root dir is a cluster chain like any other directory */ | 267 | /* FAT32 root dir is a cluster chain like any other directory */ |
272 | buf_size = vs->sectors_per_cluster * sector_size; | 268 | buf_size = vs->sectors_per_cluster * sector_size_bytes; |
273 | root_cluster = le32_to_cpu(vs->type.fat32.root_cluster); | 269 | root_cluster = le32_to_cpu(vs->type.fat32.root_cluster); |
274 | dbg("root dir cluster %u", root_cluster); | 270 | start_data_sct = reserved_sct + fat_size_sct; |
275 | start_data_sect = reserved + fat_size; | ||
276 | 271 | ||
277 | next = root_cluster; | 272 | next_cluster = root_cluster; |
278 | maxloop = 100; | 273 | maxloop = 100; |
279 | while (--maxloop) { | 274 | while (--maxloop) { |
280 | uint32_t next_sect_off; | 275 | uint32_t next_off_sct; |
281 | uint64_t next_off; | 276 | uint64_t next_off; |
282 | uint64_t fat_entry_off; | 277 | uint64_t fat_entry_off; |
283 | int count; | 278 | int count; |
284 | 279 | ||
285 | dbg("next cluster %u", next); | 280 | dbg("next_cluster 0x%x", (unsigned)next_cluster); |
286 | next_sect_off = (next - 2) * vs->sectors_per_cluster; | 281 | next_off_sct = (next_cluster - 2) * vs->sectors_per_cluster; |
287 | next_off = (start_data_sect + next_sect_off) * sector_size; | 282 | next_off = (start_data_sct + next_off_sct) * sector_size_bytes; |
288 | dbg("cluster offset 0x%llx", (unsigned long long) next_off); | 283 | dbg("cluster offset 0x%llx", (unsigned long long) next_off); |
289 | 284 | ||
290 | /* get cluster */ | 285 | /* get cluster */ |
291 | buf = volume_id_get_buffer(id, off + next_off, buf_size); | 286 | buf = volume_id_get_buffer(id, fat_partition_off + next_off, buf_size); |
292 | if (buf == NULL) | 287 | if (buf == NULL) |
293 | goto found; | 288 | goto found; |
294 | 289 | ||
@@ -301,20 +296,21 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) | |||
301 | break; | 296 | break; |
302 | 297 | ||
303 | /* get FAT entry */ | 298 | /* get FAT entry */ |
304 | fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t)); | 299 | fat_entry_off = (reserved_sct * sector_size_bytes) + (next_cluster * sizeof(uint32_t)); |
305 | buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size); | 300 | dbg("fat_entry_off 0x%llx", (unsigned long long)fat_entry_off); |
301 | buf = volume_id_get_buffer(id, fat_partition_off + fat_entry_off, buf_size); | ||
306 | if (buf == NULL) | 302 | if (buf == NULL) |
307 | goto found; | 303 | goto found; |
308 | 304 | ||
309 | /* set next cluster */ | 305 | /* set next cluster */ |
310 | next = le32_to_cpu(*((uint32_t *) buf) & 0x0fffffff); | 306 | next_cluster = le32_to_cpu(*(uint32_t*)buf) & 0x0fffffff; |
311 | if (next == 0) | 307 | if (next_cluster < 2 || next_cluster > FAT32_MAX) |
312 | break; | 308 | break; |
313 | } | 309 | } |
314 | if (maxloop == 0) | 310 | if (maxloop == 0) |
315 | dbg("reached maximum follow count of root cluster chain, give up"); | 311 | dbg("reached maximum follow count of root cluster chain, give up"); |
316 | 312 | ||
317 | vs = volume_id_get_buffer(id, off, 0x200); | 313 | vs = volume_id_get_buffer(id, fat_partition_off, 0x200); |
318 | if (vs == NULL) | 314 | if (vs == NULL) |
319 | return -1; | 315 | return -1; |
320 | 316 | ||