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

📄 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 页
字号:
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Copyright (C) 2002 by Linus Nielsen Feltzing
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "fat.h"

#define SECTOR_SIZE     512
#define MAX_BLOCK_SIZE  2048

#define BYTES2INT16(array,pos) \
          (array[pos] | (array[pos+1] << 8 ))
#define BYTES2INT32(array,pos)          \
    ((long)array[pos] | ((long)array[pos+1] << 8 ) |    \
     ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))

/* BPB offsets; generic */
#define BS_JMPBOOT          0
#define BS_OEMNAME          3
#define BPB_BYTSPERSEC      11
#define BPB_SECPERCLUS      13
#define BPB_RSVDSECCNT      14
#define BPB_NUMFATS         16
#define BPB_ROOTENTCNT      17
#define BPB_TOTSEC16        19
#define BPB_MEDIA           21
#define BPB_FATSZ16         22
#define BPB_SECPERTRK       24
#define BPB_NUMHEADS        26
#define BPB_HIDDSEC         28
#define BPB_TOTSEC32        32

/* fat32 */
#define BPB_FATSZ32         36
#define BPB_EXTFLAGS        40
#define BPB_FSVER           42
#define BPB_ROOTCLUS        44
#define BPB_FSINFO          48
#define BPB_BKBOOTSEC       50
#define BS_32_DRVNUM        64
#define BS_32_BOOTSIG       66
#define BS_32_VOLID         67
#define BS_32_VOLLAB        71
#define BS_32_FILSYSTYPE    82

#define BPB_LAST_WORD       510

/* attributes */
#define FAT_ATTR_LONG_NAME   (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
                              FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
#define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
                                 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
                                 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )

/* NTRES flags */
#define FAT_NTRES_LC_NAME    0x08
#define FAT_NTRES_LC_EXT     0x10

#define FATDIR_NAME          0
#define FATDIR_ATTR          11
#define FATDIR_NTRES         12
#define FATDIR_CRTTIMETENTH  13
#define FATDIR_CRTTIME       14
#define FATDIR_CRTDATE       16
#define FATDIR_LSTACCDATE    18
#define FATDIR_FSTCLUSHI     20
#define FATDIR_WRTTIME       22
#define FATDIR_WRTDATE       24
#define FATDIR_FSTCLUSLO     26
#define FATDIR_FILESIZE      28

#define FATLONG_ORDER        0
#define FATLONG_TYPE         12
#define FATLONG_CHKSUM       13

#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
#define DIR_ENTRIES_PER_SECTOR  (SECTOR_SIZE / DIR_ENTRY_SIZE)
#define DIR_ENTRY_SIZE       32
#define NAME_BYTES_PER_ENTRY 13
#define FAT_BAD_MARK         0x0ffffff7
#define FAT_EOF_MARK         0x0ffffff8


struct fsinfo {
    unsigned long freecount; /* last known free cluster count */
    unsigned long nextfree;  /* first cluster to start looking for free
                               clusters, or 0xffffffff for no hint */
};
/* fsinfo offsets */
#define FSINFO_FREECOUNT 488
#define FSINFO_NEXTFREE  492


#define FAT_CACHE_SIZE 0x20
#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)

struct fat_cache_entry
{
    long secnum;
    bool inuse;
    bool dirty;
};
static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];

static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];

struct bpb
{
    int bpb_bytspersec;  /* Bytes per sector, typically 512 */
    unsigned int bpb_secperclus;  /* Sectors per cluster */
    int bpb_rsvdseccnt;  /* Number of reserved sectors */
    int bpb_numfats;     /* Number of FAT structures, typically 2 */
    int bpb_totsec16;    /* Number of sectors on the volume (old 16-bit) */
    int bpb_media;       /* Media type (typically 0xf0 or 0xf8) */
    int bpb_fatsz16;     /* Number of used sectors per FAT structure */
    unsigned long bpb_totsec32;    /* Number of sectors on the volume
                                     (new 32-bit) */
    unsigned int last_word;       /* 0xAA55 */

    /**** FAT32 specific *****/
    long bpb_fatsz32;
    long bpb_rootclus;
    long bpb_fsinfo;

    /* variables for internal use */
    unsigned long fatsize;
    unsigned long totalsectors;
    unsigned long rootdirsector;
    unsigned long firstdatasector;
    unsigned long startsector;
    unsigned long dataclusters;
    struct fsinfo fsinfo;
#ifdef HAVE_FAT16SUPPORT
    int bpb_rootentcnt;  /* Number of dir entries in the root */
    /* internals for FAT16 support */
    bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
    unsigned int rootdiroffset; /* sector offset of root dir relative to start
                                 * of first pseudo cluster */
#endif /* #ifdef HAVE_FAT16SUPPORT */
#ifdef HAVE_MULTIVOLUME
    int drive; /* on which physical device is this located */
    bool mounted; /* flag if this volume is mounted */
#endif
};

static const unsigned char utf8comp[6] = 
{
    0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
};

static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */

struct mutex
{
    bool locked;
};

static struct mutex cache_mutex;

/****************************************************************************
 * Simple mutex functions
 ****************************************************************************/
void mutex_init(struct mutex *m)
{
    m->locked = false;
}

void mutex_lock(struct mutex *m)
{
    /* Wait until the lock is open... */
    while(m->locked)
    {
    }
//        sleep_thread();
//    wake_up_thread();

    /* ...and lock it */
    m->locked = true;
}

void mutex_unlock(struct mutex *m)
{
    m->locked = false;
}



static long cluster2sec( long cluster )
{
    struct bpb* fat_bpb = &fat_bpbs[0];
    long zerocluster;
    
    // NATE: This is to deal with when fat_mount sets the root cluster to negative
    if (cluster < 0)
      zerocluster = 0;
    else
      zerocluster = 2;
      

    if (cluster > (long)(fat_bpb->dataclusters + 1))
    {
      DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
        return -1;
    }

    return (cluster - zerocluster) * fat_bpb->bpb_secperclus 
           + fat_bpb->firstdatasector;
}

void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
{
#ifndef HAVE_MULTIVOLUME
    const int volume = 0;
#endif
    struct bpb* fat_bpb = &fat_bpbs[volume];
    if (size)
      *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
    if (free)
      *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
}


void fat_init(void)
{
    unsigned int i;

    mutex_init(&cache_mutex);

    /* mark the FAT cache as unused */
    for(i = 0;i < FAT_CACHE_SIZE;i++)
    {
        fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
        fat_cache[i].inuse = false;
        fat_cache[i].dirty = false;
#ifdef HAVE_MULTIVOLUME
        fat_cache[i].fat_vol = NULL;
#endif
    }
#ifdef HAVE_MULTIVOLUME
    /* mark the possible volumes as not mounted */
    for (i=0; i<NUM_VOLUMES;i++)
    {
        fat_bpbs[i].mounted = false;
    }
#endif
}

static void flush_fat_sector(struct fat_cache_entry *fce,
                             unsigned char *sectorbuf)
{
    int rc;
    long secnum;

    /* With multivolume, use only the FAT info from the cached sector! */
#ifdef HAVE_MULTIVOLUME
    secnum = fce->secnum + fce->fat_vol->startsector;
#else
    secnum = fce->secnum + fat_bpbs[0].startsector;
#endif

    /* Write to the first FAT */
    rc = rb_fat_write_sectors(IF_MV2(fce->fat_vol->drive,)
                           secnum, 1,
                           (unsigned short*)sectorbuf);
    if(rc < 0)
    {
        panicf("flush_fat_sector() - Could not write sector %ld"
               " (error %d)\n",
               secnum, rc);
    }
#ifdef HAVE_MULTIVOLUME
    if(fce->fat_vol->bpb_numfats > 1)
#else
    if(fat_bpbs[0].bpb_numfats > 1)
#endif
    {
        /* Write to the second FAT */
#ifdef HAVE_MULTIVOLUME
        secnum += fce->fat_vol->fatsize;
#else
        secnum += fat_bpbs[0].fatsize;
#endif
        rc = rb_fat_write_sectors(IF_MV2(fce->fat_vol->drive,)
                               secnum, 1, (unsigned short*)sectorbuf);
        if(rc < 0)
        {
            panicf("flush_fat_sector() - Could not write sector %ld"
                   " (error %d)\n",
                   secnum, rc);
        }
    }
    fce->dirty = false;
}

static int update_fsinfo( void )
{
    struct bpb* fat_bpb = &fat_bpbs[0];
    unsigned char fsinfo[SECTOR_SIZE];
    unsigned long* intptr;
    int rc;
    
    /* update fsinfo */
    rc = rb_fat_read_sectors( fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,(short*)fsinfo);
    if (rc < 0)
    {
        DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
        return rc * 10 - 1;
    }
    intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
    *intptr = (fat_bpb->fsinfo.freecount);

    intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
    *intptr = (fat_bpb->fsinfo.nextfree);

    rc = rb_fat_write_sectors( fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,(short*)fsinfo);
//    rc = writeLogicalSector( fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1, (short*) fsinfo);

    if (rc < 0)
    {
        DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
        return rc * 10 - 2;
    }

    return 0;
}



static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
{
    int i;
    int rc;
    unsigned char *sec;
    LDEBUGF("flush_fat()\n");

    mutex_lock(&cache_mutex);
    for(i = 0;i < FAT_CACHE_SIZE;i++)
    {
        struct fat_cache_entry *fce = &fat_cache[i];
        if(fce->inuse 
#ifdef HAVE_MULTIVOLUME
            && fce->fat_vol == fat_bpb
#endif
            && fce->dirty)
        {
            sec = fat_cache_sectors[i];
            flush_fat_sector(fce, sec);
        }
    }
    mutex_unlock(&cache_mutex);

    rc = update_fsinfo(IF_MV(fat_bpb));
    if (rc < 0)
        return rc * 10 - 3;

    return 0;
}




//static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
//                              long fatsector, bool dirty)
unsigned char* cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
                              long fatsector, bool dirty)
{
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
    int cache_index = secnum & FAT_CACHE_MASK;
    struct fat_cache_entry *fce = &fat_cache[cache_index];
    unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
    int rc;

    mutex_lock(&cache_mutex); /* make changes atomic */

    /* Delete the cache entry if it isn't the sector we want */
    if(fce->inuse && (fce->secnum != secnum
#ifdef HAVE_MULTIVOLUME
        || fce->fat_vol != fat_bpb
#endif
    ))
    {
        /* Write back if it is dirty */
        if(fce->dirty)
        {
            flush_fat_sector(fce, sectorbuf);
        }
        fce->inuse = false;
    }

    /* Load the sector if it is not cached */
    if(!fce->inuse)
    {
        rc = rb_fat_read_sectors(IF_MV2(fat_bpb->drive,)
                              secnum + fat_bpb->startsector,1,
                              (unsigned short*)sectorbuf);
        if(rc < 0)
        {
            DEBUGF( "cache_fat_sector() - Could not read sector %ld"
                    " (error %d)\n", secnum, rc);
            mutex_unlock(&cache_mutex);
            return NULL;
        }
        fce->inuse = true;

⌨️ 快捷键说明

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