1: /* 2: fatfile.c 3: 4: Created: Feb 24, 1994 by Philip Homburg <philip@cs.vu.nl> 5: */ 6: 7: #include "kernel.h" 8: #include "driver.h" 9: #include "drvlib.h" 10: #if ENABLE_FATFILE 11: #include <stdlib.h> 12: #include "assert.h" 13: INIT_ASSERT 14: 15: 16: #define BOOT_POS ((unsigned long)0) 17: #define BOOT_SIZE 512 18: 19: struct bootsector { 20: u8_t b_jmp[3]; /* JMP instruction to reach boot code */ 21: u8_t b_oem_name[8]; /* OEM name and version */ 22: u8_t b_bytes_per_sector[2]; 23: u8_t b_sectors_per_cluster; 24: u8_t b_reserved[2]; 25: u8_t b_nr_fats; 26: u8_t b_rootdir_entries[2]; 27: u8_t b_nr_sectors16[2]; /* # sectors if < 32M, otherwise 0 */ 28: u8_t b_media; 29: u8_t b_sectors_per_fat16[2]; /* sec/fat if FAT-12 or FAT-16 */ 30: u8_t b_sectors_per_track[2]; 31: u8_t b_nr_heads[2]; 32: u8_t b_hidden_sectors[4]; 33: u8_t b_nr_sectors32[4]; /* # sectors if >= 32M */ 34: 35: /* Only for FAT-32: */ 36: u8_t b_sectors_per_fat32[4]; /* sec/fat if FAT-32 */ 37: u8_t b_flags[2]; 38: u8_t b_version[2]; 39: u8_t b_rootdir_cluster[4]; /* First cluster in root directory */ 40: u8_t b_info_sector[2]; 41: u8_t b_backup_boot[2]; 42: }; 43: 44: #define B_MAGIC_POS 0x1FE 45: #define B_MAGIC_OK(c1,c2) ((c1) == 0x55 && (c2) == 0xAA) 46: 47: #define MAX_FAT12_CLUSTERS 0xFEE /* Maximum for a 12 bit FAT. */ 48: 49: struct dirent 50: { 51: u8_t d_name[8]; 52: u8_t d_ext[3]; 53: u8_t d_attr; 54: u8_t d_Case; 55: u8_t d_ctime_ms; 56: u16_t d_ctime; 57: u16_t d_cdate; 58: u16_t d_adate; 59: u8_t d_cluster2; 60: u8_t d_cluster3; 61: u16_t d_time; 62: u16_t d_date; 63: u8_t d_cluster0; 64: u8_t d_cluster1; 65: u8_t d_size0; 66: u8_t d_size1; 67: u8_t d_size2; 68: u8_t d_size3; 69: }; 70: 71: #define DA_ISDIR 0x10 72: 73: #if _WORD_SIZE == 2 74: #define CMAP_NO 129 /* [0..128] */ 75: #else 76: #define CMAP_NO 513 /* [0..512] */ 77: #endif 78: 79: typedef struct ff 80: { 81: int ff_init; 82: int ff_dead; 83: int ff_dev_task; 84: int ff_dev_minor; 85: u32_t ff_rtdir_start; 86: u32_t ff_fat_start; 87: u32_t ff_data_start; 88: u32_t ff_img_size; 89: u32_t ff_nr_clusters; 90: u32_t ff_cluster_map[CMAP_NO]; 91: u32_t ff_map_step; 92: u32_t ff_step_mask; 93: u32_t ff_cache_pos; 94: int ff_fat_bits; 95: int ff_step_shift; 96: unsigned ff_cluster_size; 97: unsigned ff_cache_cluster; 98: unsigned ff_rtdir_size; 99: unsigned ff_open_ct; 100: 101: /* for driver.c */ 102: struct device ff_part[DEV_PER_DRIVE]; 103: } ff_t; 104: 105: #define MAX_DRIVES 2 106: 107: static struct ff ff_table[MAX_DRIVES]; 108: 109: #define NR_DEVICES (MAX_DRIVES * DEV_PER_DRIVE) 110: 111: #define CACHE_NR (2 * sizeof(char *)) 112: 113: static struct 114: { 115: ff_t *c_device; 116: u32_t c_sector; 117: u8_t c_block[SECTOR_SIZE]; 118: } cache[CACHE_NR]; 119: static int cache_victim= 0; 120: static int fatfile_tasknr= ANY; 121: static int ff_drive; 122: static ff_t *ff_curr; 123: static struct device *ff_dv; 124: 125: #define islower(c) ((unsigned) ((c) - 'a') <= (unsigned) ('z' - 'a')) 126: #define toupper(c) ((c) - 'a' + 'A') 127: 128: 129: _PROTOTYPE( static char *ff_name, (void) ); 130: _PROTOTYPE( static int ff_do_open, (struct driver *dp, message *m_ptr) ); 131: _PROTOTYPE( static int ff_do_close, (struct driver *dp, message *m_ptr) ); 132: _PROTOTYPE( static struct device *ff_prepare, (int device) ); 133: _PROTOTYPE( static int ff_transfer, (int proc_nr, int opcode, 134: off_t position, iovec_t *iov, unsigned nr_req) ); 135: _PROTOTYPE( static void ff_geometry, (struct partition *entry) ); 136: 137: _PROTOTYPE( static void init, (ff_t *ffp) ); 138: _PROTOTYPE( static int init_hd, (ff_t *ffp) ); 139: _PROTOTYPE( static u8_t *read_bytes, (ff_t *ffp, unsigned long pos, 140: unsigned size) ); 141: _PROTOTYPE( static u16_t b2u16, (U8_t c0, U8_t c1) ); 142: _PROTOTYPE( static u32_t b2u32, (U8_t c0, U8_t c1, U8_t c2, U8_t c3) ); 143: _PROTOTYPE( static int dir_lookup, (ff_t *ffp, u8_t *name, 144: unsigned long cluster, struct dirent *dirp) ); 145: _PROTOTYPE( static unsigned long next_cluster, (ff_t *ffp, 146: unsigned long cluster) ); 147: _PROTOTYPE( static unsigned long cluster2block, (ff_t *ffp, 148: unsigned long cluster) ); 149: _PROTOTYPE( static unsigned long img_cluster2block, (ff_t *ffp, 150: unsigned long pos) ); 151: _PROTOTYPE( static int parse_env, (int drive, int *taskp, int *minorp, 152: u8_t **namep) ); 153: 154: static struct driver ff_dtab= 155: { 156: ff_name, 157: ff_do_open, 158: ff_do_close, 159: do_diocntl, 160: ff_prepare, 161: ff_transfer, 162: nop_cleanup, 163: ff_geometry, 164: }; 165: 166: void fatfile_task() 167: { 168: fatfile_tasknr= proc_number(proc_ptr); 169: driver_task(&ff_dtab); 170: } 171: 172: static char *ff_name() 173: { 174: static char name[]= "fatfile-d0"; 175: 176: name[9]= '0' + ff_drive; 177: return name; 178: } 179: 180: static int ff_do_open(dp, m_ptr) 181: struct driver *dp; 182: message *m_ptr; 183: { 184: if (ff_prepare(m_ptr->DEVICE) == NULL) 185: return ENXIO; 186: if (!ff_curr->ff_init) 187: init(ff_curr); 188: if (ff_curr->ff_dead) 189: return ENXIO; 190: if (ff_curr->ff_open_ct++ == 0) 191: { 192: partition(&ff_dtab, ff_drive*DEV_PER_DRIVE, P_PRIMARY); 193: } 194: return OK; 195: } 196: 197: static int ff_do_close(dp, m_ptr) 198: struct driver *dp; 199: message *m_ptr; 200: { 201: if (ff_prepare(m_ptr->DEVICE) == NULL) 202: return ENXIO; 203: ff_curr->ff_open_ct--; 204: return OK; 205: } 206: 207: static struct device *ff_prepare(device) 208: int device; 209: { 210: if (device < NR_DEVICES) 211: { 212: ff_drive= device / DEV_PER_DRIVE; 213: ff_curr= &ff_table[ff_drive]; 214: ff_dv= &ff_curr->ff_part[device % DEV_PER_DRIVE]; 215: } 216: else 217: return NULL; 218: 219: if (ff_curr->ff_dead) 220: return NULL; 221: return ff_dv; 222: } 223: 224: /* 225: ff_transfer 226: */ 227: static int ff_transfer(proc_nr, opcode, position, iovec, nr_req) 228: int proc_nr; 229: int opcode; 230: off_t position; 231: iovec_t *iovec; 232: unsigned nr_req; 233: { 234: iovec_t *request, *iovec_end= iovec + nr_req; 235: unsigned long first_dev_pos, dev_pos, pos; 236: int r; 237: unsigned dev_nr_req; 238: unsigned nbytes, count; 239: unsigned dev_size; 240: unsigned long dv_size; 241: iovec_t iovec1; 242: message m; 243: 244: while (nr_req > 0) 245: { 246: /* How many bytes to transfer? */ 247: nbytes= 0; 248: for (request= iovec; request < iovec_end; request++) 249: nbytes += request->iov_size; 250: 251: /* Handle partition translation. */ 252: dv_size = cv64ul(ff_dv->dv_size); 253: pos = position; 254: if (pos >= dv_size) 255: return OK; 256: if (pos + nbytes > dv_size) 257: nbytes = dv_size - pos; 258: pos += cv64ul(ff_dv->dv_base); 259: if (pos >= ff_curr->ff_img_size) 260: return EIO; 261: if (pos + nbytes > ff_curr->ff_img_size) 262: return EIO; 263: 264: /* How many bytes can be found in consecutive clusters? */ 265: count= 0; 266: while (count < nbytes) 267: { 268: dev_pos= img_cluster2block(ff_curr, pos); 269: if (count == 0) 270: { 271: first_dev_pos= dev_pos; 272: } 273: else 274: { 275: if (dev_pos != first_dev_pos + count) 276: break; 277: } 278: dev_size= ff_curr->ff_cluster_size 279: - (pos % ff_curr->ff_cluster_size); 280: if (count + dev_size > nbytes) 281: dev_size = nbytes - count; 282: 283: pos += dev_size; 284: count += dev_size; 285: } 286: 287: /* How many I/O requests can be executed on those clusters? */ 288: dev_nr_req= 0; 289: request= iovec; 290: while (count > 0) 291: { 292: if (count < request->iov_size) 293: break; 294: count -= request->iov_size; 295: request++; 296: dev_nr_req++; 297: } 298: 299: if (dev_nr_req > 0) 300: { 301: /* Do those requests that can be done, then exit. */ 302: m.m_type= opcode; 303: m.DEVICE= ff_curr->ff_dev_minor; 304: m.PROC_NR= proc_nr; 305: m.POSITION= first_dev_pos; 306: m.ADDRESS= (char *) iovec; 307: m.COUNT= dev_nr_req; 308: r= sendrec(ff_curr->ff_dev_task, &m); 309: assert(r == OK); 310: 311: /* EOF is checked here, so no half-baked results. */ 312: return iovec[0].iov_size == 0 ? OK : EIO; 313: } 314: 315: /* The first request can only be partially executed. */ 316: iovec1.iov_addr= iovec[0].iov_addr; 317: iovec1.iov_size= count; 318: 319: m.m_type= opcode; 320: m.DEVICE= ff_curr->ff_dev_minor; 321: m.PROC_NR= proc_nr; 322: m.POSITION= first_dev_pos; 323: m.ADDRESS= (char *) &iovec1; 324: m.COUNT= 1; 325: r= sendrec(ff_curr->ff_dev_task, &m); 326: assert(r == OK); 327: 328: if (iovec1.iov_size != 0) 329: return EIO; 330: 331: /* Book the partial I/O and try again with the updated list. */ 332: iovec[0].iov_addr+= count; 333: iovec[0].iov_size-= count; 334: position += count; 335: } 336: return OK; 337: } 338: 339: static void ff_geometry(entry) 340: struct partition *entry; 341: { 342: /* The number of sectors per track is chosen to match the cluster size 343: * to make it easy for people to place partitions on cluster boundaries. 344: */ 345: entry->cylinders= ff_curr->ff_img_size / ff_curr->ff_cluster_size / 64; 346: entry->heads= 64; 347: entry->sectors= ff_curr->ff_cluster_size >> SECTOR_SHIFT; 348: } 349: 350: /* 351: init 352: */ 353: static void init(ffp) 354: ff_t *ffp; 355: { 356: u8_t *cp, *name; 357: struct bootsector *bp; 358: struct dirent dirent; 359: int i, r; 360: unsigned long cluster; 361: unsigned long off; 362: 363: unsigned rtdir_ents; 364: unsigned bytespsec; 365: unsigned long secspfat; 366: unsigned long fatsize; 367: unsigned secspclus; 368: unsigned long nr_secs; 369: unsigned long rtdir_cluster; 370: unsigned long max_cluster; 371: 372: ffp->ff_init= 1; 373: ffp->ff_dead= 1; 374: 375: if (parse_env(ff_drive, &ffp->ff_dev_task, &ffp->ff_dev_minor, 376: &name) != OK) 377: { 378: return; 379: } 380: if (init_hd(ffp) != OK) 381: { 382: printf("%s: init_hd failed\n", ff_name()); 383: return; 384: } 385: cp= read_bytes(ffp, BOOT_POS, BOOT_SIZE); 386: if (cp == NULL) 387: return; 388: bp= (struct bootsector *) cp; 389: if (!B_MAGIC_OK(cp[B_MAGIC_POS], cp[B_MAGIC_POS + 1])) 390: { 391: printf("%s: magic AA55 not found\n", ff_name()); 392: return; 393: } 394: bytespsec= b2u16(bp->b_bytes_per_sector[0], bp->b_bytes_per_sector[1]); 395: if (bp->b_nr_fats != 2) 396: { 397: printf("%s: strange number of fats: %d\n", 398: ff_name(), bp->b_nr_fats); 399: return; 400: } 401: ffp->ff_fat_bits= 12; /* Assume 12, later correct to 16 or 32 */ 402: 403: secspfat= b2u16(bp->b_sectors_per_fat16[0], bp->b_sectors_per_fat16[1]); 404: if (secspfat == 0) { 405: ffp->ff_fat_bits= 32; 406: secspfat= b2u32(bp->b_sectors_per_fat32[0], 407: bp->b_sectors_per_fat32[1], 408: bp->b_sectors_per_fat32[2], 409: bp->b_sectors_per_fat32[3]); 410: } 411: fatsize= secspfat * bytespsec; 412: ffp->ff_fat_start= b2u16(bp->b_reserved[0], 413: bp->b_reserved[1]) * bytespsec; 414: rtdir_ents= b2u16(bp->b_rootdir_entries[0], bp->b_rootdir_entries[1]); 415: ffp->ff_rtdir_size= rtdir_ents * sizeof(struct dirent); 416: ffp->ff_rtdir_start= ffp->ff_fat_start + bp->b_nr_fats * fatsize; 417: rtdir_cluster= b2u32(bp->b_rootdir_cluster[0], 418: bp->b_rootdir_cluster[1], 419: bp->b_rootdir_cluster[2], 420: bp->b_rootdir_cluster[3]); 421: secspclus= bp->b_sectors_per_cluster; 422: nr_secs= b2u16(bp->b_nr_sectors16[0], bp->b_nr_sectors16[1]); 423: if (nr_secs == 0) 424: { 425: nr_secs= b2u32(bp->b_nr_sectors32[0], bp->b_nr_sectors32[1], 426: bp->b_nr_sectors32[2], bp->b_nr_sectors32[3]); 427: } 428: ffp->ff_nr_clusters= nr_secs / (secspclus == 0 ? 1 : secspclus); 429: ffp->ff_cluster_size= bytespsec * secspclus; 430: ffp->ff_data_start= ffp->ff_rtdir_start + ffp->ff_rtdir_size; 431: if (ffp->ff_fat_bits == 12 && ffp->ff_nr_clusters > MAX_FAT12_CLUSTERS) 432: { 433: ffp->ff_fat_bits= 16; 434: } 435: max_cluster= 436: ((u32_t) -1 - ffp->ff_data_start) / ffp->ff_cluster_size + 2; 437: if (ffp->ff_nr_clusters > max_cluster) { 438: /* A filesystem > 4G? I'm afraid we can't do that. */ 439: ffp->ff_nr_clusters= max_cluster; 440: } 441: 442: #if DEBUG 443: printf("%s: os name is '%.8s'\n", ff_name(), bp->b_oem_name); 444: #endif 445: 446: if (ffp->ff_fat_bits <= 16) { 447: cluster= 0; /* Indicates root directory segment. */ 448: } else { 449: cluster= rtdir_cluster; /* FAT-32 root directory chain. */ 450: } 451: 452: for (;;) 453: { 454: cp= name; 455: while (*cp == '\\' || *cp == '/') cp++; 456: name= cp; 457: while (*name != 0) 458: { 459: if (*name == '\\' || *name == '/') 460: { 461: *name++ = 0; 462: break; 463: } 464: name++; 465: } 466: r= dir_lookup(ffp, cp, cluster, &dirent); 467: if (r != OK) 468: return; 469: if (ffp->ff_fat_bits <= 16) { 470: cluster= b2u16(dirent.d_cluster0, dirent.d_cluster1); 471: } else { 472: cluster= b2u32(dirent.d_cluster0, dirent.d_cluster1, 473: dirent.d_cluster2, dirent.d_cluster3); 474: } 475: if (*name == 0) 476: break; 477: if (!(dirent.d_attr & DA_ISDIR)) 478: { 479: printf("%s: '%s' is not a directory\n", ff_name(), cp); 480: return; 481: } 482: } 483: if (dirent.d_attr & DA_ISDIR) 484: { 485: printf("%s: '%s' is not a file\n", ff_name(), cp); 486: return; 487: } 488: ffp->ff_img_size= b2u32(dirent.d_size0, dirent.d_size1, dirent.d_size2, 489: dirent.d_size3); 490: ffp->ff_map_step= ffp->ff_cluster_size; 491: while (ffp->ff_map_step * (CMAP_NO-1) < ffp->ff_img_size) 492: ffp->ff_map_step <<= 1; 493: 494: for (i= 0; (1L << i) < ffp->ff_map_step; i++) 495: ; /* no nothing */ 496: if ((1L << i) != ffp->ff_map_step) 497: { 498: printf("%s: ff_map_step (= %ld) is not a power of 2\n", 499: ff_name(), ffp->ff_map_step); 500: return; 501: } 502: ffp->ff_step_shift= i; 503: ffp->ff_step_mask= ffp->ff_map_step-1; 504: i= 0; 505: for (off= 0; off < ffp->ff_img_size; off += ffp->ff_cluster_size) 506: { 507: if ((off & ffp->ff_step_mask) == 0) 508: { 509: ffp->ff_cluster_map[i++]= cluster; 510: } 511: if (cluster == 0) 512: { 513: printf("%s: cluster chain finishes early!\n", 514: ff_name()); 515: return; 516: } 517: cluster= next_cluster(ffp, cluster); 518: } 519: ffp->ff_cache_pos= 0; 520: ffp->ff_cache_cluster= ffp->ff_cluster_map[0]; 521: ffp->ff_dead= 0; 522: ffp->ff_part[0].dv_size= cvul64(ffp->ff_img_size); 523: } 524: 525: static int init_hd(ffp) 526: ff_t *ffp; 527: { 528: message m; 529: int r; 530: 531: m.m_type= DEV_OPEN; 532: m.DEVICE= ffp->ff_dev_minor; 533: m.PROC_NR= fatfile_tasknr; 534: m.COUNT= R_BIT|W_BIT; 535: r= sendrec(ffp->ff_dev_task, &m); 536: assert (r == OK); 537: r= m.REP_STATUS; 538: if (r != OK) 539: { 540: printf("%s: dev_open failed: %d\n", ff_name(), r); 541: return EIO; 542: } 543: return OK; 544: } 545: 546: /* 547: read_bytes 548: */ 549: static u8_t *read_bytes(ffp, pos, size) 550: ff_t *ffp; 551: unsigned long pos; 552: unsigned size; 553: { 554: message m; 555: unsigned long sector; 556: unsigned off; 557: int i, r; 558: iovec_t iovec1; 559: 560: sector= pos >> SECTOR_SHIFT; 561: off= pos & SECTOR_MASK; 562: assert(off+size <= SECTOR_SIZE); 563: 564: /* search the cache */ 565: for (i= 0; i<CACHE_NR; i++) 566: { 567: if (cache[i].c_device == ffp && cache[i].c_sector == sector) 568: return cache[i].c_block + off; 569: } 570: 571: i= cache_victim; 572: if (++cache_victim == CACHE_NR) 573: cache_victim= 0; 574: 575: cache[i].c_device= NULL; /* in case of failures */ 576: iovec1.iov_addr= (vir_bytes)cache[i].c_block; 577: iovec1.iov_size= SECTOR_SIZE; 578: m.m_type= DEV_GATHER; 579: m.DEVICE= ffp->ff_dev_minor; 580: m.POSITION= sector << SECTOR_SHIFT; 581: m.PROC_NR= fatfile_tasknr; 582: m.ADDRESS= (char *) &iovec1; 583: m.COUNT= 1; 584: r= sendrec(ffp->ff_dev_task, &m); 585: assert(r == OK); 586: if (iovec1.iov_size != 0) 587: { 588: printf("%s: dev_read failed: %d\n", ff_name(), m.REP_STATUS); 589: return NULL; 590: } 591: cache[i].c_device= ffp; 592: cache[i].c_sector= sector; 593: return cache[i].c_block+off; 594: } 595: 596: static u16_t b2u16(c0, c1) 597: u8_t c0; 598: u8_t c1; 599: { 600: return c0 | (c1 << 8); 601: } 602: 603: static u32_t b2u32(c0, c1, c2, c3) 604: u8_t c0; 605: u8_t c1; 606: u8_t c2; 607: u8_t c3; 608: { 609: return (u32_t)c0 | ((u32_t)c1 << 8) 610: | ((u32_t)c2 << 16) | ((u32_t)c3 << 24); 611: } 612: 613: /* 614: dir_lookup 615: */ 616: static int dir_lookup(ffp, name, cluster, dirp) 617: ff_t *ffp; 618: u8_t *name; 619: unsigned long cluster; 620: struct dirent *dirp; 621: { 622: struct dirent *direntp; 623: u8_t base[8], ext[3]; 624: int i; 625: u8_t *cp; 626: unsigned long offset; 627: unsigned long cluster_block; 628: unsigned off; 629: 630: cp= name; 631: memset(base, ' ', 8); 632: for (i= 0; *cp != '\0' && *cp != '.'; i++, cp++) 633: { 634: if (i >= 8) 635: continue; 636: if (islower(*cp)) 637: base[i]= toupper(*cp); 638: else 639: base[i]= *cp; 640: } 641: if (*cp == '.') 642: cp++; 643: memset(ext, ' ', 3); 644: for (i= 0; *cp != '\0'; i++, cp++) 645: { 646: if (i >= 3) 647: continue; 648: if (islower(*cp)) 649: ext[i]= toupper(*cp); 650: else 651: ext[i]= *cp; 652: } 653: 654: if (cluster == 0) 655: { 656: /* Root directory */ 657: offset= 0; 658: while(offset < ffp->ff_rtdir_size) 659: { 660: cp= read_bytes(ffp, ffp->ff_rtdir_start + offset, 661: SECTOR_SIZE); 662: if (cp == NULL) 663: return EIO; 664: for (i= 0; i<SECTOR_SIZE && offset < ffp->ff_rtdir_size; 665: i += sizeof(struct dirent)) 666: { 667: direntp= (struct dirent *)&cp[i]; 668: if (memcmp(direntp->d_name, base, 8) == 0 && 669: memcmp(direntp->d_ext, ext, 3) == 0) 670: { 671: memcpy(dirp, cp+i, 672: sizeof(struct dirent)); 673: return OK; 674: } 675: offset += sizeof(struct dirent); 676: } 677: } 678: } 679: else 680: { 681: /* Any sub directory */ 682: offset= 0; 683: off= 0; 684: cluster_block= cluster2block(ffp, cluster); 685: for (;;) 686: { 687: cp= read_bytes(ffp, cluster_block + off, SECTOR_SIZE); 688: if (cp == NULL) 689: return EIO; 690: for (i= 0; i<SECTOR_SIZE; i += sizeof(struct dirent)) 691: { 692: direntp= (struct dirent *)&cp[i]; 693: if (memcmp(direntp->d_name, base, 8) == 0 && 694: memcmp(direntp->d_ext, ext, 3) == 0) 695: { 696: memcpy(dirp, cp+i, 697: sizeof(struct dirent)); 698: return OK; 699: } 700: offset += sizeof(struct dirent); 701: } 702: off += SECTOR_SIZE; 703: if (off >= ffp->ff_cluster_size) 704: { 705: cluster= next_cluster(ffp, cluster); 706: off= 0; 707: if (cluster == 0) 708: break; 709: } 710: } 711: } 712: printf("%s: '%s' not found\n", ff_name(), name); 713: return ENOENT; 714: } 715: 716: /* 717: next_cluster 718: */ 719: static unsigned long next_cluster(ffp, cluster) 720: ff_t *ffp; 721: unsigned long cluster; 722: { 723: unsigned long next; 724: u8_t *pnext; 725: 726: switch (ffp->ff_fat_bits) 727: { 728: case 12: 729: pnext= read_bytes(ffp, ffp->ff_fat_start + 730: ((unsigned) cluster * 3 / 2), 2); 731: if (pnext == 0) 732: return 0; 733: next= b2u16(pnext[0], pnext[1]); 734: 735: if ((cluster & 1) == 0) { 736: next &= 0xfff; 737: } else { 738: next >>= 4; 739: } 740: break; 741: case 16: 742: pnext= read_bytes(ffp, ffp->ff_fat_start + 743: (cluster * 2), 2); 744: if (pnext == 0) 745: return 0; 746: next= b2u16(pnext[0], pnext[1]); 747: break; 748: case 32: 749: pnext= read_bytes(ffp, ffp->ff_fat_start + 750: (cluster * 4), 4); 751: if (pnext == 0) 752: return 0; 753: next= b2u32(pnext[0], pnext[1], pnext[2], pnext[3]); 754: break; 755: } 756: return next < ffp->ff_nr_clusters ? next : 0; 757: } 758: 759: static unsigned long cluster2block(ffp, cluster) 760: ff_t *ffp; 761: unsigned long cluster; 762: { 763: return ffp->ff_data_start + (cluster-2) * ffp->ff_cluster_size; 764: } 765: 766: static unsigned long img_cluster2block(ffp, pos) 767: ff_t *ffp; 768: unsigned long pos; 769: { 770: unsigned long posbase, cachebase; 771: int posindx; 772: 773: posbase= (pos & ~ffp->ff_step_mask); 774: cachebase= (ffp->ff_cache_pos & ~ffp->ff_step_mask); 775: if (posbase != cachebase || pos < ffp->ff_cache_pos) 776: { 777: posindx= posbase >> ffp->ff_step_shift; 778: ffp->ff_cache_pos= posbase; 779: ffp->ff_cache_cluster= ffp->ff_cluster_map[posindx]; 780: } 781: while (ffp->ff_cache_pos + ffp->ff_cluster_size <= pos) 782: { 783: ffp->ff_cache_pos += ffp->ff_cluster_size; 784: ffp->ff_cache_cluster= next_cluster(ffp, ffp->ff_cache_cluster); 785: assert(ffp->ff_cache_cluster != 0); 786: } 787: assert(pos-ffp->ff_cache_pos < ffp->ff_cluster_size); 788: return cluster2block(ffp, ffp->ff_cache_cluster)+ 789: pos-ffp->ff_cache_pos; 790: } 791: 792: static int parse_env(drive, taskp, minorp, namep) 793: int drive; 794: int *taskp; 795: int *minorp; 796: u8_t **namep; 797: { 798: static char namebuf[256]; 799: 800: char *env_var, *env_val; 801: char *cp, *check, *taskname; 802: int ok, task; 803: unsigned long minor; 804: 805: env_var= ff_name(); 806: env_val= getenv(env_var); 807: if (env_val == NULL) 808: { 809: printf("%s: no environment variable '%s'\n", 810: ff_name(), env_var); 811: return ESRCH; 812: } 813: 814: cp= env_val; 815: ok= (cp= strchr(cp, ':')) != NULL; 816: if (ok) { 817: *cp= 0; 818: for (task= -NR_TASKS; task < 0; task++) { 819: if (strcmp(env_val, tasktab[task+NR_TASKS].name) == 0) 820: break; 821: } 822: *cp++= ':'; 823: if (task == 0) { 824: printf("%s: driver named in '%s' is not available\n", 825: ff_name(), env_val); 826: return EINVAL; 827: } 828: } 829: if (ok) { 830: minor= strtoul(cp, &check, 0); 831: if (minor >= 256) { 832: printf( 833: "%s: minor device number in '%s' is out of range\n", 834: ff_name(), env_val); 835: return EINVAL; 836: } 837: if (check == cp || *check != ':') ok= 0; 838: cp= check+1; 839: } 840: 841: if (!ok) 842: { 843: printf("%s: unable to parse '%s'\n", ff_name(), env_val); 844: return EINVAL; 845: } 846: if (strlen(cp) > sizeof(namebuf)-1) 847: { 848: printf("%s: file name too long in '%s'\n", ff_name(), env_val); 849: return EINVAL; 850: } 851: strcpy(namebuf, cp); 852: *taskp= task; 853: *minorp= minor; 854: *namep= (u8_t *) namebuf; 855: printf("%s: using %s\n", ff_name(), env_val); 856: return OK; 857: } 858: #endif /* ENABLE_FATFILE */