diff options
Diffstat (limited to 'src/stream/fs/fat.c')
-rw-r--r-- | src/stream/fs/fat.c | 516 |
1 files changed, 0 insertions, 516 deletions
diff --git a/src/stream/fs/fat.c b/src/stream/fs/fat.c deleted file mode 100644 index 01e4e03cc2..0000000000 --- a/src/stream/fs/fat.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2000, 2001 Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <console/console.h> -#include <string.h> -#include <fs/fs.h> -#include <fs/fat.h> -#include <arch/byteorder.h> - -struct fat_superblock -{ - int fat_offset; - int fat_length; - int fat_size; - int root_offset; - int root_max; - int data_offset; - - int num_sectors; - int num_clust; - int clust_eof_marker; - int sects_per_clust; - int sectsize_bits; - int clustsize_bits; - int root_cluster; - - int cached_fat; - int file_cluster; - int current_cluster_num; - int current_cluster; -}; - -/* pointer(s) into filesystem info buffer for DOS stuff */ -#define FAT_SUPER ( (struct fat_superblock *) \ - ( FSYS_BUF + 32256) )/* 512 bytes long */ -#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */ -#define NAME_BUF ( FSYS_BUF + 29184 ) /* Filename buffer (833 bytes) */ - -#define FAT_CACHE_SIZE 2048 - -#ifdef __i386 -static __inline__ unsigned long -log2 (unsigned long word) -{ - __asm__ ("bsfl %1,%0" - : "=r" (word) - : "r" (word)); - return word; -} -#else /* !PPC */ -static __inline__ unsigned long -__ilog2(unsigned long x) -{ - unsigned long lz; - - asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); - return 31 - lz; -} -static __inline__ unsigned long -log2(unsigned long x) -{ - return __ilog2(x & -x); -} -#endif - -int -fat_mount (void) -{ - struct fat_bpb bpb; - __u32 magic, first_fat; - - /* Check partition type for harddisk */ - if (((current_drive & 0x80) || (current_slice != 0)) - && ! IS_PC_SLICE_TYPE_FAT (current_slice) - && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS))) - return 0; - - /* Read bpb */ - if (! devread (0, 0, sizeof (bpb), (char *) &bpb)) - return 0; - - /* Check if the number of sectors per cluster is zero here, to avoid - zero division. */ - if (bpb.sects_per_clust == 0) - return 0; - - FAT_SUPER->sectsize_bits = log2(FAT_CVT_U16(bpb.bytes_per_sect)); - FAT_SUPER->clustsize_bits - = FAT_SUPER->sectsize_bits + log2(bpb.sects_per_clust); - -printk_debug("BytsPerSec = %d\n", FAT_CVT_U16(bpb.bytes_per_sect)); -printk_debug("SecPerClus = %d\n", bpb.sects_per_clust); - - /* Fill in info about super block */ - FAT_SUPER->num_sectors = FAT_CVT_U16(bpb.short_sectors) - ? FAT_CVT_U16(bpb.short_sectors) : FAT_CVT_U32(bpb.long_sectors); - -printk_debug("TotSec16 = %d\n", FAT_CVT_U16(bpb.short_sectors)); -printk_debug("TotSec32 = %d\n", FAT_CVT_U32(bpb.long_sectors)); - - /* FAT offset and length */ - FAT_SUPER->fat_offset = FAT_CVT_U16(bpb.reserved_sects); - FAT_SUPER->fat_length = FAT_CVT_U16(bpb.fat_length) - ? FAT_CVT_U16(bpb.fat_length) : FAT_CVT_U32(bpb.fat32_length); - -printk_debug("RsvdSecCnt = %d\n", FAT_CVT_U16(bpb.reserved_sects)); -printk_debug("FATSx16 = %d\n", FAT_CVT_U16(bpb.fat_length)); -printk_debug("FATSx32 = %d\n", FAT_CVT_U32(bpb.fat32_length)); - - /* Rootdir offset and length for FAT12/16 */ - FAT_SUPER->root_offset = - FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length; - FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries); - -printk_debug("RootEntCnt = %d\n", FAT_CVT_U16(bpb.dir_entries)); - - /* Data offset and number of clusters */ - FAT_SUPER->data_offset = - FAT_SUPER->root_offset - + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1; - FAT_SUPER->num_clust = - 2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset) - / bpb.sects_per_clust); - FAT_SUPER->sects_per_clust = bpb.sects_per_clust; - - if (!bpb.fat_length) - { - /* This is a FAT32 */ - if (FAT_CVT_U16(bpb.dir_entries)) - return 0; - -printk_debug("We seem to be FAT32\n"); -printk_debug("ExtFlags = 0x%x\n", FAT_CVT_U16(bpb.flags)); -printk_debug("RootClus = %d\n", FAT_CVT_U32(bpb.root_cluster)); - if (FAT_CVT_U16(bpb.flags) & 0x0080) - { - /* FAT mirroring is disabled, get active FAT */ - int active_fat = FAT_CVT_U16(bpb.flags) & 0x000f; - if (active_fat >= bpb.num_fats) - return 0; - FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length; - } - - FAT_SUPER->fat_size = 8; - FAT_SUPER->root_cluster = FAT_CVT_U32(bpb.root_cluster); - - /* Yes the following is correct. FAT32 should be called FAT28 :) */ - FAT_SUPER->clust_eof_marker = 0xffffff8; - } - else - { - if (!FAT_SUPER->root_max) - return 0; - -printk_debug("We seem to be FAT12/16\n"); - FAT_SUPER->root_cluster = -1; - if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST) - { - FAT_SUPER->fat_size = 4; - FAT_SUPER->clust_eof_marker = 0xfff8; - } - else - { - FAT_SUPER->fat_size = 3; - FAT_SUPER->clust_eof_marker = 0xff8; - } - } - - /* Now do some sanity checks */ - - if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits) - || FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE - || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits - - FAT_SUPER->sectsize_bits)) - || FAT_SUPER->num_clust <= 2 - || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE) - > FAT_SUPER->fat_length)) - return 0; - - /* kbs: Media check on first FAT entry [ported from PUPA] */ - - if (!devread(FAT_SUPER->fat_offset, 0, - sizeof(first_fat), (char *)&first_fat)) - return 0; - -printk_debug("Media = 0x%x\n", bpb.media); - - if (FAT_SUPER->fat_size == 8) - { - first_fat = le32_to_cpu(first_fat) & 0x0fffffff; - magic = 0x0fffff00; - } - else if (FAT_SUPER->fat_size == 4) - { - first_fat = le32_to_cpu(first_fat) & 0x0000ffff; - magic = 0xff00; - } - else - { - first_fat = le32_to_cpu(first_fat) & 0x00000fff; - magic = 0x0f00; - } - - if (first_fat != (magic | bpb.media)) - return 0; - - FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE; - return 1; -} - -int -fat_read (char *buf, int len) -{ - int logical_clust; - int offset; - int ret = 0; - int size; - - if (FAT_SUPER->file_cluster < 0) - { - /* root directory for fat16 */ - size = FAT_SUPER->root_max - filepos; - if (size > len) - size = len; - if (!devread(FAT_SUPER->root_offset, filepos, size, buf)) - return 0; - filepos += size; - return size; - } - - logical_clust = filepos >> FAT_SUPER->clustsize_bits; - offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1)); - if (logical_clust < FAT_SUPER->current_cluster_num) - { - FAT_SUPER->current_cluster_num = 0; - FAT_SUPER->current_cluster = FAT_SUPER->file_cluster; - } - - while (len > 0) - { - int sector; - while (logical_clust > FAT_SUPER->current_cluster_num) - { - /* calculate next cluster */ - int fat_entry = - FAT_SUPER->current_cluster * FAT_SUPER->fat_size; - int next_cluster; - int cached_pos = (fat_entry - FAT_SUPER->cached_fat); - - if (cached_pos < 0 || - (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE) - { - FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1)); - cached_pos = (fat_entry - FAT_SUPER->cached_fat); - sector = FAT_SUPER->fat_offset - + FAT_SUPER->cached_fat / (2*SECTOR_SIZE); - if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF)) - return 0; - } - next_cluster = FAT_CVT_U32(FAT_BUF + (cached_pos >> 1)); - if (FAT_SUPER->fat_size == 3) - { - if (cached_pos & 1) - next_cluster >>= 4; - next_cluster &= 0xFFF; - } - else if (FAT_SUPER->fat_size == 4) - next_cluster &= 0xFFFF; - - if (next_cluster >= FAT_SUPER->clust_eof_marker) - return ret; - if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust) - { - errnum = ERR_FSYS_CORRUPT; - return 0; - } - - FAT_SUPER->current_cluster = next_cluster; - FAT_SUPER->current_cluster_num++; - } - - sector = FAT_SUPER->data_offset + - ((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits - - FAT_SUPER->sectsize_bits)); - size = (1 << FAT_SUPER->clustsize_bits) - offset; - if (size > len) - size = len; - - disk_read_func = disk_read_hook; - - devread(sector, offset, size, buf); - - disk_read_func = 0; - - len -= size; - buf += size; - ret += size; - filepos += size; - logical_clust++; - offset = 0; - } - return errnum ? 0 : ret; -} - -int -fat_dir (char *dirname) -{ - char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH]; - char *filename = (char *) NAME_BUF; - int attrib = FAT_ATTRIB_DIR; -#ifndef STAGE1_5 - int do_possibilities = 0; -#endif - - /* XXX I18N: - * the positions 2,4,6 etc are high bytes of a 16 bit unicode char - */ - static unsigned char longdir_pos[] = - { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; - int slot = -2; - int alias_checksum = -1; - - FAT_SUPER->file_cluster = FAT_SUPER->root_cluster; - filepos = 0; - FAT_SUPER->current_cluster_num = MAXINT; - - /* main loop to find desired directory entry */ - loop: - - /* if we have a real file (and we're not just printing possibilities), - then this is where we want to exit */ - - if (!*dirname || isspace (*dirname)) - { - if (attrib & FAT_ATTRIB_DIR) - { - errnum = ERR_BAD_FILETYPE; - return 0; - } - - return 1; - } - - /* continue with the file/directory name interpretation */ - - while (*dirname == '/') - dirname++; - - if (!(attrib & FAT_ATTRIB_DIR)) - { - errnum = ERR_BAD_FILETYPE; - return 0; - } - /* Directories don't have a file size */ - filemax = MAXINT; - - for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); - - *rest = 0; - -# ifndef STAGE1_5 - if (print_possibilities && ch != '/') - do_possibilities = 1; -# endif - - while (1) - { - if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH - || dir_buf[0] == 0) - { - if (!errnum) - { -# ifndef STAGE1_5 - if (print_possibilities < 0) - { -#if 0 - putchar ('\n'); -#endif - return 1; - } -# endif /* STAGE1_5 */ - - errnum = ERR_FILE_NOT_FOUND; - *rest = ch; - } - - return 0; - } - - if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME) - { - /* This is a long filename. The filename is build from back - * to front and may span multiple entries. To bind these - * entries together they all contain the same checksum over - * the short alias. - * - * The id field tells if this is the first entry (the last - * part) of the long filename, and also at which offset this - * belongs. - * - * We just write the part of the long filename this entry - * describes and continue with the next dir entry. - */ - int i, offset; - unsigned char id = FAT_LONGDIR_ID(dir_buf); - - if ((id & 0x40)) - { - id &= 0x3f; - slot = id; - filename[slot * 13] = 0; - alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf); - } - - if (id != slot || slot == 0 - || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf)) - { - alias_checksum = -1; - continue; - } - - slot--; - offset = slot * 13; - - for (i=0; i < 13; i++) - filename[offset+i] = dir_buf[longdir_pos[i]]; - continue; - } - - if (!FAT_DIRENTRY_VALID (dir_buf)) - continue; - - if (alias_checksum != -1 && slot == 0) - { - int i; - unsigned char sum; - - slot = -2; - for (sum = 0, i = 0; i< 11; i++) - sum = ((sum >> 1) | (sum << 7)) + dir_buf[i]; - - if (sum == alias_checksum) - { -# ifndef STAGE1_5 - if (do_possibilities) - goto print_filename; -# endif /* STAGE1_5 */ - - if (substring (dirname, filename) == 0) - break; - } - } - - /* XXX convert to 8.3 filename format here */ - { - int i, j, c; - - for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i])) - && !isspace (c); i++); - - filename[i++] = '.'; - - for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j])) - && !isspace (c); j++); - - if (j == 0) - i--; - - filename[i + j] = 0; - } - -# ifndef STAGE1_5 - if (do_possibilities) - { - print_filename: - if (substring (dirname, filename) <= 0) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - print_a_completion (filename); - } - continue; - } -# endif /* STAGE1_5 */ - - if (substring (dirname, filename) == 0) - break; - } - - *(dirname = rest) = ch; - - attrib = FAT_DIRENTRY_ATTRIB (dir_buf); - filemax = FAT_DIRENTRY_FILELENGTH (dir_buf); - filepos = 0; - FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf); - FAT_SUPER->current_cluster_num = MAXINT; - - /* go back to main loop at top of function */ - goto loop; -} |