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