Annotation of qemu/roms/openbios/fs/grubfs/fsys_fat.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.