|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.