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