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

📄 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 页
字号:
                            }

                            utf8 = utf16LEdecode(ptr + index + 1, utf8, 5);
                            utf8 = utf16LEdecode(ptr + index + 14, utf8, 6);
                            utf8 = utf16LEdecode(ptr + index + 28, utf8, 2);
                        }
                        *utf8 = 0;
                    }
                    done = true;
                    sectoridx = 0;
                    i++;
                    break;
                }
            }
        }

        /* save this sector, for longname use */
        if ( sectoridx )
            memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
        else
            memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
        sectoridx += SECTOR_SIZE;

    }
    return 0;
}

static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
{
#ifdef HAVE_FAT16SUPPORT
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    if (fat_bpb->is_fat16)
    {
        int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
        int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
        unsigned short* sec;

        sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
        if (!sec)
        {
            DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
            return -1;
        }

        return letoh16(sec[offset]);
    }
    else
#endif /* #ifdef HAVE_FAT16SUPPORT */
    {
        long sector = entry / CLUSTERS_PER_FAT_SECTOR;
        int offset = entry % CLUSTERS_PER_FAT_SECTOR;
        unsigned long* sec;

        sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
        if (!sec)
        {
            DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
            return -1;
        }

        return letoh32(sec[offset]) & 0x0fffffff;
    }
}



static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
{
    long next_cluster;
    long eof_mark = FAT_EOF_MARK;
    
#ifdef HAVE_FAT16SUPPORT
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    if (fat_bpb->is_fat16)
    {
        eof_mark &= 0xFFFF; /* only 16 bit */
        if (cluster < 0) /* FAT16 root dir */
            return cluster + 1; /* don't use the FAT */
    }
#endif
    next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);

    /* is this last cluster in chain? */
    if ( next_cluster >= eof_mark )
        return 0;
    else
        return next_cluster;
}

static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned long startcluster)
{
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    unsigned long sector;
    unsigned long offset;
    unsigned long i;

#ifdef HAVE_FAT16SUPPORT
    if (fat_bpb->is_fat16)
    {
        sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
        offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
    
        for (i = 0; i<fat_bpb->fatsize; i++) {
            unsigned int j;
            unsigned int nr = (i + sector) % fat_bpb->fatsize;
            unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
            if ( !fat )
                break;
            for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
                int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
                if (letoh16(fat[k]) == 0x0000) {
                    unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
                     /* Ignore the reserved clusters 0 & 1, and also
                        cluster numbers out of bounds */
                    if ( c < 2 || c > fat_bpb->dataclusters+1 )
                        continue;
                    LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
                    fat_bpb->fsinfo.nextfree = c;
                    return c;
                }
            }
            offset = 0;
        }
    }
    else
#endif /* #ifdef HAVE_FAT16SUPPORT */
    {
        sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
        offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
    
        for (i = 0; i<fat_bpb->fatsize; i++) {
            unsigned int j;
            unsigned long nr = (i + sector) % fat_bpb->fatsize;
            unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
            if ( !fat )
                break;
            for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
                int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
                if (!(letoh32(fat[k]) & 0x0fffffff)) {
                    unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
                     /* Ignore the reserved clusters 0 & 1, and also
                        cluster numbers out of bounds */
                    if ( c < 2 || c > fat_bpb->dataclusters+1 )
                        continue;
                    LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
                    fat_bpb->fsinfo.nextfree = c;
                    return c;
                }
            }
            offset = 0;
        }
    }

    LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
    return 0; /* 0 is an illegal cluster number */
}

static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) 
          unsigned long entry, 
          unsigned long val)
{
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
#ifdef HAVE_FAT16SUPPORT
    if (fat_bpb->is_fat16)
    {
        int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
        int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
        unsigned short* sec;

        val &= 0xFFFF;

        LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);

        if (entry==val)
            panicf("Creating FAT loop: %lx,%lx\n",entry,val);

        if ( entry < 2 )
            panicf("Updating reserved FAT entry %ld.\n",entry);

        sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
        if (!sec)
        {
            DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
            return -1;
        }

        if ( val ) {
            if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
                fat_bpb->fsinfo.freecount--;
        }
        else {
            if (letoh16(sec[offset]))
                fat_bpb->fsinfo.freecount++;
        }

        LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);

        sec[offset] = htole16(val);
    }
    else
#endif /* #ifdef HAVE_FAT16SUPPORT */
    {
        long sector = entry / CLUSTERS_PER_FAT_SECTOR;
        int offset = entry % CLUSTERS_PER_FAT_SECTOR;
        unsigned long* sec;

        LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);

        if (entry==val)
            panicf("Creating FAT loop: %lx,%lx\n",entry,val);

        if ( entry < 2 )
            panicf("Updating reserved FAT entry %ld.\n",entry);

        sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
        if (!sec)
        {
            DEBUGF( "update_fat_entry() - Could not cache sector %ld\n", sector);
            return -1;
        }

        if ( val ) {
            if (!(letoh32(sec[offset]) & 0x0fffffff) &&
                fat_bpb->fsinfo.freecount > 0)
                fat_bpb->fsinfo.freecount--;
        }
        else {
            if (letoh32(sec[offset]) & 0x0fffffff)
                fat_bpb->fsinfo.freecount++;
        }

        LDEBUGF("update_fat_entry: %ld free clusters\n", fat_bpb->fsinfo.freecount);

        /* don't change top 4 bits */
        sec[offset] &= htole32(0xf0000000);
        sec[offset] |= htole32(val & 0x0fffffff);
    }

    return 0;
}


static long next_write_cluster(struct fat_file* file,
                              long oldcluster,
                              long* newsector)
{
#ifdef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
#else
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    long cluster = 0;
    long sector;

    LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);

    if (oldcluster)
        cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);

    if (!cluster) {
        if (oldcluster > 0)
            cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
        else if (oldcluster == 0)
            cluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
#ifdef HAVE_FAT16SUPPORT
        else /* negative, pseudo-cluster of the root dir */
            return 0; /* impossible to append something to the root */
#endif

        if (cluster) {
            if (oldcluster)
                update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster); 
            else
                file->firstcluster = cluster;
            update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
        }
        else {
#ifdef TEST_FAT
            if (fat_bpb->fsinfo.freecount>0)
                panicf("There is free space, but find_free_cluster() "
                       "didn't find it!\n");
#endif
            DEBUGF("next_write_cluster(): Disk full!\n");
            return 0;
        }
    }
    sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
    if (sector<0)
        return 0;

    *newsector = sector;
    return cluster;
}

static int transfer(IF_MV2(struct bpb* fat_bpb,) 
                    unsigned long start, long count, char* buf, bool write )
{
#ifndef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    int rc;

    LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
        start+ fat_bpb->startsector, count, write?"write":"read");
    if (write) {
        unsigned long firstallowed;
#ifdef HAVE_FAT16SUPPORT
        if (fat_bpb->is_fat16)
            firstallowed = fat_bpb->rootdirsector;
        else
#endif
            firstallowed = fat_bpb->firstdatasector;
            
        if (start < firstallowed)
            panicf("Write %ld before data\n", firstallowed - start);
        if (start + count > fat_bpb->totalsectors)
            panicf("Write %ld after data\n",
                start + count - fat_bpb->totalsectors);
        rc = rb_fat_write_sectors(IF_MV2(fat_bpb->drive,)
                               start + fat_bpb->startsector, count, (unsigned short*)buf);
    }
    else
        rc = rb_fat_read_sectors(IF_MV2(fat_bpb->drive,)
                              start + fat_bpb->startsector, count, (unsigned short*)buf);
    if (rc < 0) {
        DEBUGF( "transfer() - Couldn't %s sector %lx"
                " (error code %d)\n", 
                write ? "write":"read", start, rc);
        return rc;
    }
    return 0;
}


long fat_readwrite( struct fat_file *file, long sectorcount,
                   void* buf, bool write )
{
#ifdef HAVE_MULTIVOLUME
    struct bpb* fat_bpb = &fat_bpbs[file->volume];
#else
    struct bpb* fat_bpb = &fat_bpbs[0];
#endif
    long cluster = file->lastcluster;
    long sector = file->lastsector;
    long clusternum = file->clusternum;
    long numsec = file->sectornum;
    bool eof = file->eof;
    long first=0, last=0;
    long i;
    int rc;

    LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
             file->firstcluster,sectorcount,(long)buf,write?"write":"read");
    LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
             sector,numsec, eof?1:0);

    if ( eof && !write)
        return 0;

    /* find sequential sectors and write them all at once */
    for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
        numsec++;
        if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
            long oldcluster = cluster;
            if (write)
                cluster = next_write_cluster(file, cluster, &sector);
            else {
                cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
                sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
            }

            clusternum++;
            numsec=1;

            if (!cluster) {
                eof = true;
                if ( write ) {
                    /* remember last cluster, in case 
                       we want to append to the file */
                    cluster = oldcluster;
                    clusternum--;
                    i = -1; /* Error code */
                    break;
                }
            }
            else
                eof = false;
        }
        else {
            if (sector)
                sector++;
            else {
                /* look up first sector of file */
                sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
                numsec=1;
#ifdef HAVE_FAT16SUPPORT
                if (file->firstcluster < 0)
                {   /* FAT16 root dir */
                    sector += fat_bpb->rootdiroffset;
                    numsec += fat_bpb->rootdiroffset;
                }
#endif
            }
        }

        if (!first)
            first = sector;

        if ( ((sector != first) && (sector != last+1)) || /* not sequential */
             (last-first+1 == 256) ) { /* max 256 sectors per ata request */
            long count = last - first + 1;
            rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
            if (rc < 0)
                return rc * 10 - 1;

            buf = (char *)buf + count * SECTOR_SIZE;
            first = sector;
        }

⌨️ 快捷键说明

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