xref: /titanic_44/usr/src/grub/grub-0.97/stage2/fsys_fat.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
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