1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2000,2001,2005 Free Software Foundation, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifdef FSYS_FAT
21
22 #include "shared.h"
23 #include "filesys.h"
24 #include "fat.h"
25
26 struct fat_superblock
27 {
28 int fat_offset;
29 int fat_length;
30 int fat_size;
31 int root_offset;
32 int root_max;
33 int data_offset;
34
35 int num_sectors;
36 int num_clust;
37 int clust_eof_marker;
38 int sects_per_clust;
39 int sectsize_bits;
40 int clustsize_bits;
41 int root_cluster;
42
43 int cached_fat;
44 int file_cluster;
45 int current_cluster_num;
46 int current_cluster;
47 };
48
49 /* pointer(s) into filesystem info buffer for DOS stuff */
50 #define FAT_SUPER ( (struct fat_superblock *) \
51 ( FSYS_BUF + 32256) )/* 512 bytes long */
52 #define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */
53 #define NAME_BUF ( FSYS_BUF + 29184 ) /* Filename buffer (833 bytes) */
54
55 #define FAT_CACHE_SIZE 2048
56
57 static __inline__ unsigned long
log2(unsigned long word)58 log2 (unsigned long word)
59 {
60 __asm__ ("bsfl %1,%0"
61 : "=r" (word)
62 : "r" (word));
63 return word;
64 }
65
66 int
fat_mount(void)67 fat_mount (void)
68 {
69 struct fat_bpb bpb;
70 __u32 magic, first_fat;
71
72 /* Check partition type for harddisk */
73 if (((current_drive & 0x80) || (current_slice != 0))
74 && ! IS_PC_SLICE_TYPE_FAT (current_slice)
75 && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
76 return 0;
77
78 /* Read bpb */
79 if (! devread (0, 0, sizeof (bpb), (char *) &bpb))
80 return 0;
81
82 /* Check if the number of sectors per cluster is zero here, to avoid
83 zero division. */
84 if (bpb.sects_per_clust == 0)
85 return 0;
86
87 FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect));
88 FAT_SUPER->clustsize_bits
89 = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust);
90
91 /* Fill in info about super block */
92 FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors)
93 ? FAT_CVT_U16 (bpb.short_sectors) : bpb.long_sectors;
94
95 /* FAT offset and length */
96 FAT_SUPER->fat_offset = FAT_CVT_U16 (bpb.reserved_sects);
97 FAT_SUPER->fat_length =
98 bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
99
100 /* Rootdir offset and length for FAT12/16 */
101 FAT_SUPER->root_offset =
102 FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
103 FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries);
104
105 /* Data offset and number of clusters */
106 FAT_SUPER->data_offset =
107 FAT_SUPER->root_offset
108 + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
109 FAT_SUPER->num_clust =
110 2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset)
111 / bpb.sects_per_clust);
112 FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
113
114 if (!bpb.fat_length)
115 {
116 /* This is a FAT32 */
117 if (FAT_CVT_U16(bpb.dir_entries))
118 return 0;
119
120 if (bpb.flags & 0x0080)
121 {
122 /* FAT mirroring is disabled, get active FAT */
123 int active_fat = bpb.flags & 0x000f;
124 if (active_fat >= bpb.num_fats)
125 return 0;
126 FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length;
127 }
128
129 FAT_SUPER->fat_size = 8;
130 FAT_SUPER->root_cluster = bpb.root_cluster;
131
132 /* Yes the following is correct. FAT32 should be called FAT28 :) */
133 FAT_SUPER->clust_eof_marker = 0xffffff8;
134 }
135 else
136 {
137 if (!FAT_SUPER->root_max)
138 return 0;
139
140 FAT_SUPER->root_cluster = -1;
141 if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST)
142 {
143 FAT_SUPER->fat_size = 4;
144 FAT_SUPER->clust_eof_marker = 0xfff8;
145 }
146 else
147 {
148 FAT_SUPER->fat_size = 3;
149 FAT_SUPER->clust_eof_marker = 0xff8;
150 }
151 }
152
153 /* Now do some sanity checks */
154
155 if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits)
156 || FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE
157 || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
158 - FAT_SUPER->sectsize_bits))
159 || FAT_SUPER->num_clust <= 2
160 || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
161 > FAT_SUPER->fat_length))
162 return 0;
163
164 /* kbs: Media check on first FAT entry [ported from PUPA] */
165
166 if (!devread(FAT_SUPER->fat_offset, 0,
167 sizeof(first_fat), (char *)&first_fat))
168 return 0;
169
170 if (FAT_SUPER->fat_size == 8)
171 {
172 first_fat &= 0x0fffffff;
173 magic = 0x0fffff00;
174 }
175 else if (FAT_SUPER->fat_size == 4)
176 {
177 first_fat &= 0x0000ffff;
178 magic = 0xff00;
179 }
180 else
181 {
182 first_fat &= 0x00000fff;
183 magic = 0x0f00;
184 }
185
186 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
187 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
188 The check may be too strict for this kind of stupid BIOSes, as
189 they overwrite the media descriptor. */
190 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
191 return 0;
192
193 FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
194 return 1;
195 }
196
197 int
fat_read(char * buf,int len)198 fat_read (char *buf, int len)
199 {
200 int logical_clust;
201 int offset;
202 int ret = 0;
203 int size;
204
205 if (FAT_SUPER->file_cluster < 0)
206 {
207 /* root directory for fat16 */
208 size = FAT_SUPER->root_max - filepos;
209 if (size > len)
210 size = len;
211 if (!devread(FAT_SUPER->root_offset, filepos, size, buf))
212 return 0;
213 filepos += size;
214 return size;
215 }
216
217 logical_clust = filepos >> FAT_SUPER->clustsize_bits;
218 offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
219 if (logical_clust < FAT_SUPER->current_cluster_num)
220 {
221 FAT_SUPER->current_cluster_num = 0;
222 FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
223 }
224
225 while (len > 0)
226 {
227 int sector;
228 while (logical_clust > FAT_SUPER->current_cluster_num)
229 {
230 /* calculate next cluster */
231 int fat_entry =
232 FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
233 int next_cluster;
234 int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
235
236 if (cached_pos < 0 ||
237 (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
238 {
239 FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
240 cached_pos = (fat_entry - FAT_SUPER->cached_fat);
241 sector = FAT_SUPER->fat_offset
242 + FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
243 if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
244 return 0;
245 }
246 next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
247 if (FAT_SUPER->fat_size == 3)
248 {
249 if (cached_pos & 1)
250 next_cluster >>= 4;
251 next_cluster &= 0xFFF;
252 }
253 else if (FAT_SUPER->fat_size == 4)
254 next_cluster &= 0xFFFF;
255
256 if (next_cluster >= FAT_SUPER->clust_eof_marker)
257 return ret;
258 if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust)
259 {
260 errnum = ERR_FSYS_CORRUPT;
261 return 0;
262 }
263
264 FAT_SUPER->current_cluster = next_cluster;
265 FAT_SUPER->current_cluster_num++;
266 }
267
268 sector = FAT_SUPER->data_offset +
269 ((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
270 - FAT_SUPER->sectsize_bits));
271 size = (1 << FAT_SUPER->clustsize_bits) - offset;
272 if (size > len)
273 size = len;
274
275 disk_read_func = disk_read_hook;
276
277 devread(sector, offset, size, buf);
278
279 disk_read_func = NULL;
280
281 len -= size;
282 buf += size;
283 ret += size;
284 filepos += size;
285 logical_clust++;
286 offset = 0;
287 }
288 return errnum ? 0 : ret;
289 }
290
291 int
fat_dir(char * dirname)292 fat_dir (char *dirname)
293 {
294 char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
295 char *filename = (char *) NAME_BUF;
296 int attrib = FAT_ATTRIB_DIR;
297 #ifndef STAGE1_5
298 int do_possibilities = 0;
299 #endif
300
301 /* XXX I18N:
302 * the positions 2,4,6 etc are high bytes of a 16 bit unicode char
303 */
304 static unsigned char longdir_pos[] =
305 { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
306 int slot = -2;
307 int alias_checksum = -1;
308
309 FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
310 filepos = 0;
311 FAT_SUPER->current_cluster_num = MAXINT;
312
313 /* main loop to find desired directory entry */
314 loop:
315
316 /* if we have a real file (and we're not just printing possibilities),
317 then this is where we want to exit */
318
319 if (!*dirname || isspace (*dirname))
320 {
321 if (attrib & FAT_ATTRIB_DIR)
322 {
323 errnum = ERR_BAD_FILETYPE;
324 return 0;
325 }
326
327 return 1;
328 }
329
330 /* continue with the file/directory name interpretation */
331
332 while (*dirname == '/')
333 dirname++;
334
335 if (!(attrib & FAT_ATTRIB_DIR))
336 {
337 errnum = ERR_BAD_FILETYPE;
338 return 0;
339 }
340 /* Directories don't have a file size */
341 filemax = MAXINT;
342
343 for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
344
345 *rest = 0;
346
347 # ifndef STAGE1_5
348 if (print_possibilities && ch != '/')
349 do_possibilities = 1;
350 # endif
351
352 while (1)
353 {
354 if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
355 || dir_buf[0] == 0)
356 {
357 if (!errnum)
358 {
359 # ifndef STAGE1_5
360 if (print_possibilities < 0)
361 {
362 #if 0
363 putchar ('\n');
364 #endif
365 return 1;
366 }
367 # endif /* STAGE1_5 */
368
369 errnum = ERR_FILE_NOT_FOUND;
370 *rest = ch;
371 }
372
373 return 0;
374 }
375
376 if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
377 {
378 /* This is a long filename. The filename is build from back
379 * to front and may span multiple entries. To bind these
380 * entries together they all contain the same checksum over
381 * the short alias.
382 *
383 * The id field tells if this is the first entry (the last
384 * part) of the long filename, and also at which offset this
385 * belongs.
386 *
387 * We just write the part of the long filename this entry
388 * describes and continue with the next dir entry.
389 */
390 int i, offset;
391 unsigned char id = FAT_LONGDIR_ID(dir_buf);
392
393 if ((id & 0x40))
394 {
395 id &= 0x3f;
396 slot = id;
397 filename[slot * 13] = 0;
398 alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
399 }
400
401 if (id != slot || slot == 0
402 || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
403 {
404 alias_checksum = -1;
405 continue;
406 }
407
408 slot--;
409 offset = slot * 13;
410
411 for (i=0; i < 13; i++)
412 filename[offset+i] = dir_buf[longdir_pos[i]];
413 continue;
414 }
415
416 if (!FAT_DIRENTRY_VALID (dir_buf))
417 continue;
418
419 if (alias_checksum != -1 && slot == 0)
420 {
421 int i;
422 unsigned char sum;
423
424 slot = -2;
425 for (sum = 0, i = 0; i< 11; i++)
426 sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
427
428 if (sum == alias_checksum)
429 {
430 # ifndef STAGE1_5
431 if (do_possibilities)
432 goto print_filename;
433 # endif /* STAGE1_5 */
434
435 if (substring (dirname, filename) == 0)
436 break;
437 }
438 }
439
440 /* XXX convert to 8.3 filename format here */
441 {
442 int i, j, c;
443
444 for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
445 && !isspace (c); i++);
446
447 filename[i++] = '.';
448
449 for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
450 && !isspace (c); j++);
451
452 if (j == 0)
453 i--;
454
455 filename[i + j] = 0;
456 }
457
458 # ifndef STAGE1_5
459 if (do_possibilities)
460 {
461 print_filename:
462 if (substring (dirname, filename) <= 0)
463 {
464 if (print_possibilities > 0)
465 print_possibilities = -print_possibilities;
466 print_a_completion (filename);
467 }
468 continue;
469 }
470 # endif /* STAGE1_5 */
471
472 if (substring (dirname, filename) == 0)
473 break;
474 }
475
476 *(dirname = rest) = ch;
477
478 attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
479 filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
480 filepos = 0;
481 FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
482 FAT_SUPER->current_cluster_num = MAXINT;
483
484 /* go back to main loop at top of function */
485 goto loop;
486 }
487
488 #endif /* FSYS_FAT */
489