• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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