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