ia64/xen-unstable

view tools/libfsimage/fat/fsys_fat.c @ 19648:f0e2df69a8eb

x86 hvm: Allow cross-vendor migration

Intercept #UD and emulate SYSCALL/SYSENTER/SYSEXIT as necessary.

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