⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 This SPI-mode SD Card controller is a free SOPC Builder component that can be used in any SOPC Build
💻 C
📖 第 1 页 / 共 5 页
字号:
        fce->secnum = secnum;
#ifdef HAVE_MULTIVOLUME
        fce->fat_vol = fat_bpb;
#endif
    }
    if (dirty)
        fce->dirty = true; /* dirt remains, sticky until flushed */
    mutex_unlock(&cache_mutex);
    return sectorbuf;
}



void fat_recalc_free(IF_MV_NONVOID(int volume))
{
#ifndef HAVE_MULTIVOLUME
    const int volume = 0;
#endif
    struct bpb* fat_bpb = &fat_bpbs[volume];
    long free = 0;
    unsigned long i;
#ifdef HAVE_FAT16SUPPORT
    if (fat_bpb->is_fat16)
    {
        for (i = 0; i<fat_bpb->fatsize; i++) {
            unsigned int j;
            unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
            for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
                unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
                if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
                    break;
      
                if (letoh16(fat[j]) == 0x0000) {
                    free++;
                    if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
                        fat_bpb->fsinfo.nextfree = c;
                }
            }
        }
    }
    else
#endif /* #ifdef HAVE_FAT16SUPPORT */
    {
        for (i = 0; i<fat_bpb->fatsize; i++) {
            unsigned int j;
            unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) i, false);
            for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
                unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
                if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
                    break;
      
                if (!(letoh32(fat[j]) & 0x0fffffff)) {
                    free++;
                    if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
                        fat_bpb->fsinfo.nextfree = c;
                }
            }
        }
    }
    fat_bpb->fsinfo.freecount = free;
    update_fsinfo(IF_MV(fat_bpb));
}

int fat_find_bootsector(  unsigned char *buf )
{
  int i;
       
  for (i=0; i<256; i++)
  {
    rb_fat_read_sectors( i, 1, (unsigned short*)buf );  
    if (buf[510] == 0x55 && buf[511] == 0xaa &&
          (buf[0] == 0xeb || buf[0] == 0xe9))
    {
      DEBUGF("Found the bpb at sector number %d\n",i);
      break;
    }
    if (i == 255) 
    {
      DEBUGF("Can't find fat boot sector. Exiting ...\n");
      return -1;
    }
  }
  return( i );
}

static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
{
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    if(fat_bpb->bpb_bytspersec != 512)
    {
        DEBUGF( "bpb_is_sane() - Error: sector size is not 512 (%d)\n",
                fat_bpb->bpb_bytspersec);
        return -1;
    }
    if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec > 128L*1024L)
    {
        DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
                "(%d * %d = %d)\n",
                fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
                fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
        return -2;
    }
    if(fat_bpb->bpb_numfats != 2)
    {
        DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
                fat_bpb->bpb_numfats);
    }
    if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
    {
        DEBUGF( "bpb_is_sane() - Warning: Non-standard "
                "media type (0x%02x)\n",
                fat_bpb->bpb_media);
    }
    if(fat_bpb->last_word != 0xaa55)
    {
        DEBUGF( "bpb_is_sane() - Error: Last word is not "
                "0xaa55 (0x%04x)\n", fat_bpb->last_word);
        return -3;
    }

    if (fat_bpb->fsinfo.freecount >
        (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
        fat_bpb->bpb_secperclus)
    {
        DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
                 "(0x%04lx)\n", fat_bpb->fsinfo.freecount);
        return -4;
    }

    return 0;
}


int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector)
{
#ifndef HAVE_MULTIVOLUME
    const int volume = 0;
#endif
    struct bpb* fat_bpb = &fat_bpbs[volume];
    unsigned char buf[SECTOR_SIZE];
    int rc;
    long datasec;
#ifdef HAVE_FAT16SUPPORT
    int rootdirsectors;
#endif

      
    /* Read the sector */
    rc = rb_fat_read_sectors(IF_MV2(drive,) startsector,1,(unsigned short*)buf);
    if(rc)
    {
        DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
        return rc * 10 - 1;
    }

    memset(fat_bpb, 0, sizeof(struct bpb));
    fat_bpb->startsector    = startsector;
#ifdef HAVE_MULTIVOLUME
    fat_bpb->drive          = drive;
#endif
  
    fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
    fat_bpb->bpb_secperclus = buf[BPB_SECPERCLUS];
    fat_bpb->bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT);
    fat_bpb->bpb_numfats    = buf[BPB_NUMFATS];
    fat_bpb->bpb_totsec16   = BYTES2INT16(buf,BPB_TOTSEC16);
    fat_bpb->bpb_media      = buf[BPB_MEDIA];
    fat_bpb->bpb_fatsz16    = BYTES2INT16(buf,BPB_FATSZ16);
    fat_bpb->bpb_fatsz32    = BYTES2INT32(buf,BPB_FATSZ32);
    fat_bpb->bpb_totsec32   = BYTES2INT32(buf,BPB_TOTSEC32);
    fat_bpb->last_word      = BYTES2INT16(buf,BPB_LAST_WORD);

    /* calculate a few commonly used values */
    if (fat_bpb->bpb_fatsz16 != 0)
        fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
    else
        fat_bpb->fatsize = fat_bpb->bpb_fatsz32;

    if (fat_bpb->bpb_totsec16 != 0)
        fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
    else
        fat_bpb->totalsectors = fat_bpb->bpb_totsec32;

#ifdef HAVE_FAT16SUPPORT
    fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
    rootdirsectors = ((fat_bpb->bpb_rootentcnt * 32)
        + (fat_bpb->bpb_bytspersec - 1)) / fat_bpb->bpb_bytspersec;

#endif /* #ifdef HAVE_FAT16SUPPORT */
    
    fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
#ifdef HAVE_FAT16SUPPORT
        + rootdirsectors
#endif
        + (fat_bpb->bpb_numfats * fat_bpb->fatsize);

    /* Determine FAT type */
    datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
    fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;

#ifdef TEST_FAT
    /*
      we are sometimes testing with "illegally small" fat32 images,
      so we don't use the proper fat32 test case for test code
    */
    if ( fat_bpb->bpb_fatsz16 )
#else
    if ( fat_bpb->dataclusters < 65525 )
#endif
    { /* FAT16 */
#ifdef HAVE_FAT16SUPPORT
        fat_bpb->is_fat16 = true;
        if (fat_bpb->dataclusters < 4085)
        { /* FAT12 */
            DEBUGF("This is FAT12. Go away!\n");
            return -2;
        }
#else /* #ifdef HAVE_FAT16SUPPORT */
        DEBUGF("This is not FAT32. Go away!\n");
        return -2;
#endif /* #ifndef HAVE_FAT16SUPPORT */
    }

#ifdef HAVE_FAT16SUPPORT
    if (fat_bpb->is_fat16)
    { /* FAT16 specific part of BPB */
        int dirclusters;  
        fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
            + (fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16) ;
        dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
            / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
        /* I assign negative pseudo cluster numbers for the root directory,
           their range is counted upward until -1. */
        fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
        fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
            - rootdirsectors;
    }
    else
#endif /* #ifdef HAVE_FAT16SUPPORT */
    { /* FAT32 specific part of BPB */
        fat_bpb->bpb_rootclus  = BYTES2INT32(buf,BPB_ROOTCLUS);
        fat_bpb->bpb_fsinfo    = BYTES2INT16(buf,BPB_FSINFO);
        fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,) fat_bpb->bpb_rootclus);
    }

    rc = bpb_is_sane(IF_MV(fat_bpb));
    if (rc < 0)
    {
        DEBUGF( "fat_mount() - BPB is not sane\n");
        return rc * 10 - 3;
    }

#ifdef HAVE_FAT16SUPPORT
    if (fat_bpb->is_fat16)
    {
        fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
        fat_bpb->fsinfo.nextfree = 0xffffffff;
    }
    else
#endif /* #ifdef HAVE_FAT16SUPPORT */
    {
        /* Read the fsinfo sector */
        rc = rb_fat_read_sectors(IF_MV2(drive,) 
            startsector + fat_bpb->bpb_fsinfo, 1, (unsigned short*)buf);
        if (rc < 0)
        {
            DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
            return rc * 10 - 4;
        }
        fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
        fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
    }

    /* calculate freecount if unset */
    if ( fat_bpb->fsinfo.freecount == 0xffffffff )
    {
        fat_recalc_free(IF_MV(volume));
    }

    LDEBUGF("Freecount: %ld\n",fat_bpb->fsinfo.freecount);
    LDEBUGF("Nextfree: 0x%lx\n",fat_bpb->fsinfo.nextfree);
    LDEBUGF("Cluster count: 0x%lx\n",fat_bpb->dataclusters);
    LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
    LDEBUGF("FAT sectors: 0x%lx\n",fat_bpb->fatsize);

#ifdef HAVE_MULTIVOLUME
    fat_bpb->mounted = true;
#endif

    return 0;
}

static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
{
    int i=0,j=0;
    unsigned char c;
    bool lowercase;

    memset(de, 0, sizeof(struct fat_direntry));
    de->attr = buf[FATDIR_ATTR];
    de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
    de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
    de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
    de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
    de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
    de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
    de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
        ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
    /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
       (the result of the shift is always considered signed) */
       
    /* fix the name */
    lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
    c = buf[FATDIR_NAME];
    if (c == 0x05)  /* special kanji char */
        c = 0xe5;
    i = 0;
    while (c != ' ') {
        de->name[j++] = lowercase ? tolower(c) : c;
        if (++i >= 8)
            break;
        c = buf[FATDIR_NAME+i];
    }
    if (buf[FATDIR_NAME+8] != ' ') {
        lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
        de->name[j++] = '.';
        for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
            de->name[j++] = lowercase ? tolower(c) : c;
    }
    return 1;
}


int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
{
    bool done = false;
    int i;
    int rc;
    unsigned char firstbyte;
    int longarray[20];
    int longs=0;
    int sectoridx=0;
    unsigned char* cached_buf = dir->sectorcache[0];

    dir->entrycount = 0;

    while(!done)
    {
        if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
        {
            rc = fat_readwrite(&dir->file, 1, cached_buf, false);
            if (rc == 0) {
                /* eof */
                entry->name[0] = 0;
                break;
            }
            if (rc < 0) {
                DEBUGF( "fat_getnext() - Couldn't read dir"
                        " (error code %d)\n", rc);
                return rc * 10 - 1;
            }
            dir->sector = dir->file.lastsector;
        }

        for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
             i < DIR_ENTRIES_PER_SECTOR; i++)
        {
            unsigned int entrypos = i * DIR_ENTRY_SIZE;

            firstbyte = cached_buf[entrypos];
            dir->entry++;

            if (firstbyte == 0xe5) {
                /* free entry */
                sectoridx = 0;
                dir->entrycount = 0;
                continue;
            }

            if (firstbyte == 0) {
                /* last entry */
                entry->name[0] = 0;
                dir->entrycount = 0;
                return 0;
            }

            dir->entrycount++;

            /* longname entry? */
            if ( ( cached_buf[entrypos + FATDIR_ATTR] &
                   FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
                longarray[longs++] = entrypos + sectoridx;
            }
            else {
                if ( parse_direntry(entry,
                                    &cached_buf[entrypos]) ) {

                    /* don't return volume id entry */
                    if ( entry->attr == FAT_ATTR_VOLUME_ID )
                        continue;

                    /* replace shortname with longname? */
                    if ( longs ) {
                        int j;
                        unsigned char* utf8 = entry->name;
                        /* iterate backwards through the dir entries */
                        for (j=longs-1; j>=0; j--) {
                            unsigned char* ptr = cached_buf;
                            int index = longarray[j];
                            /* current or cached sector? */
                            if ( sectoridx >= SECTOR_SIZE ) {
                                if ( sectoridx >= SECTOR_SIZE*2 ) {
                                    if ( ( index >= SECTOR_SIZE ) &&
                                         ( index < SECTOR_SIZE*2 ))
                                        ptr = dir->sectorcache[1];
                                    else
                                        ptr = dir->sectorcache[2];
                                }
                                else {
                                    if ( index < SECTOR_SIZE )
                                        ptr = dir->sectorcache[1];
                                }

                                index &= SECTOR_SIZE-1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -