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 */