Annotation of qemu/roms/openbios/fs/grubfs/fsys_fat.c, revision 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.