aboutsummaryrefslogtreecommitdiff
path: root/util-linux/volume_id/fat.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-12 11:17:49 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-12 11:17:49 +0000
commitd5e305944a9db25f57b252cc9f56c18311e68481 (patch)
tree5f76ea7623209d379a9ea34bfa943ef86af2032a /util-linux/volume_id/fat.c
parentcdd1f732bc5b8447dd12b59613663b7d08fce20b (diff)
downloadbusybox-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.c128
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 @@
31struct vfat_super_block { 34struct 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
87static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned count) 90static 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
121int volume_id_probe_vfat(struct volume_id *id, uint64_t off) 122int 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