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

📄 tmfat32.c

📁 PNX1500上Fat32文件系统源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
        count = p->sectorsPerCluster;

        for (i = 0; i < p->dataNumClusters; i++)
        {
            if (flag == FULL_FLUSH)
                doit = p->dataClusterDirty[i];
            else
                doit = (cluster == p->dataCluster[i]) && p->dataClusterDirty[i];
            
            if (doit)
            {
                sec = p->dataAreaBase + 
                         (p->dataCluster[i] - p->rootDirCluster) * p->sectorsPerCluster;
                status = p->dev->Write(p->dev->Info, 
                                                    sec, 
                                                    count,
                                                    &p->dataCache[i * p->bytesPerCluster]);
                if (status != TM_OK)
                    goto done;
                p->dataClusterDirty[i] = False;
                if (flag != FULL_FLUSH)
                    break;
            }
        }
        
        // Flush root directory cache (FAT12/FAT16 only)
        
        if (p->fsType != tmFat32_FAT32)
        {
            sec = p->fatBase + p->fatSize * p->fatCount;
            
            for (i = 0; i < p->rootDirNumSectors; i++)
            {
                if (p->rootDirSectorDirty[i])
                {
                    status = p->dev->Write(p->dev->Info, 
                                           sec + i, 
                                           1,
                                           &p->rootDirCache[i * p->dev->Info->bytesPerSector]);
                    if (status != TM_OK)
                        goto done;
                    p->rootDirSectorDirty[i] = False;
                }
            }
        }
    }

done:
    if (status != TM_OK)
        SET_ERRNO(EIO);

    return status;
}

// Synchronize cached data with device media. Return 0 if OK.

static int UTIL_sync(void)
{
    tmFat32_FS_t    *p;
    
    p = GFS;

    if (UTIL_flush_cache(FAT_CACHE,  0, 0, FULL_FLUSH) != TM_OK || 
        UTIL_flush_cache(DATA_CACHE, 0, 0, FULL_FLUSH) != TM_OK)
    {
        return 1;
    }

    if ( (p->fsType == tmFat32_FAT32) && 
        ((p->nextFreeClusterIn != p->nextFreeCluster) || 
         (p->freeClustersIn != p->freeClusters)) )
    {
        UInt8           buf[DOS_DEFAULT_SECTOR_SIZE];
        tmErrorCode_t	status;

//        TMFAT_DEBUG1("UTIL_sync() updating FSI sector %d.\n", p->fsiBase);
//        TMFAT_DEBUG2("Old nextFreeCluster=%u,new nextFreeCluster=%u.\n", 
//                      p->nextFreeClusterIn, p->nextFreeCluster);
//        TMFAT_DEBUG2("Old freeClusters=%u,new freeClusters=%u.\n", 
//                      p->freeClustersIn, p->freeClusters);

        status = p->dev->Read(p->dev->Info, p->fsiBase, 1, buf);
        CHECK(p->dev->Read, status);
        
        SET32(&buf[FSI_Free_Count], p->freeClusters);
        SET32(&buf[FSI_Nxt_Free], p->nextFreeCluster);

        status = p->dev->Write(p->dev->Info, p->fsiBase, 1, buf);
        CHECK(p->dev->Write, status);
        
        // According to MS don't bother with the backup copy
        // of FSI in p->fsiBackup;

    }
    
    return 0;
}

// Fill cache so that the item is in the cache. For the FAT cache an entry
// is the sector number. For the DATA cache an entry is the data cluster number.

static tmErrorCode_t UTIL_fill_cache(int which, UInt32 cluster, UInt64 sector)
{
    tmErrorCode_t   status = TM_OK;
    ptmFat32_FS_t   p = GFS;
    UInt64          sec;
    UInt32          index;
    UInt32          next;
    
//    TMFAT_DEBUG3("+UTIL_fill_cache(%s,%d,%llu)\n",
//                 (which == FAT_CACHE) ? "FAT" : "DATA", cluster, sector);

    if (which == FAT_CACHE)
    {
        next = p->fatCacheNext;

        // Write it if it changed  
        if (p->fatSectorDirty[next])
        {
            status = UTIL_flush_cache(FAT_CACHE, 0, p->fatSector[next], PARTIAL_FLUSH);
            CHECK(UTIL_flush_cache, status);
        }
        
        index = next * (p->dev->Info->bytesPerSector / sizeof(UInt32));

        status = p->dev->Read(p->dev->Info, 
                                           sector, 
                                           1, 
                                           (UInt8 *) &p->fatCache[index]);
        CHECK(p->dev->Read, status);
        
        p->fatSector[next] = sector;
        p->fatSectorDirty[next] = False;
        
        next++;
        if (next >= p->fatNumSectors)
            next = p->fatLockSectors;
        p->fatCacheNext = next;
        
    }
    else
    {
        next = p->dataCacheNext;
        
        // Write it if it changed  
        if (p->dataClusterDirty[next])
        {
            status = UTIL_flush_cache(DATA_CACHE, p->dataCluster[next], 0, PARTIAL_FLUSH);
            CHECK(UTIL_flush_cache, status);
        }
        
        sec = p->dataAreaBase + 
                 (cluster - p->rootDirCluster) * p->sectorsPerCluster;
        status = p->dev->Read(p->dev->Info, 
                                           sec, 
                                           p->sectorsPerCluster, 
                                           &p->dataCache[next * p->bytesPerCluster]);
        CHECK(p->dev->Read, status);
        
        p->dataCluster[next] = cluster;
        p->dataClusterDirty[next] = False;
        
        next++;
        if (next >= p->dataNumClusters)
            next = p->dataLockClusters;
        p->dataCacheNext = next;
    }

//    TMFAT_DEBUG1("-UTIL_fill_cache() returning %d\n", status);

    return status;
}

/*
    Get information about the current and next cluster from the FAT.
    On error return -1, probably because it failed to read the FAT.
    On disk full return 1 and do not modify *next or *last. If OK
    return 0. 'cluster' is the current cluster. If the current
    cluster is not allocated *next will be set to 0, otherwise
    it will be set to the next cluster number. If the current
    cluster is the last in the chain *last will be set to True
    and *next will be set to 0, otherwise *last will be set to
    False and *next will be set to the next cluster in the chain.
*/

static int UTIL_get_fat_info(UInt32 cluster, UInt32 *next, Bool *last)
{
    ptmFat32_FS_t   p = GFS;
    UInt32          temp;
    Bool            lastCluster = False;

    if (p->freeClusters == 0)
        return 1;

    if (UTIL_fat_content(GET_FAT_ENTRY, cluster, 0, &temp))
    {
        TMFAT_DEBUG0("UTIL_get_fat_info: doing UTIL_fat_content failed.\n");    
        return -1;
    }
    
    if (p->fsType == tmFat32_FAT32)
    {
        cluster = temp & FAT32_CLUSTER_MASK;
        if (cluster >= FAT32_EOC)
            lastCluster = True;
    }
    else if (p->fsType == tmFat32_FAT16)
    {
        cluster = temp & FAT16_CLUSTER_MASK;
        if (cluster >= FAT16_EOC)
            lastCluster = True;
    }
    else
    {
        cluster = temp & FAT12_CLUSTER_MASK;
        if (cluster >= FAT12_EOC)
            lastCluster = True;
    }
    
    *last = lastCluster;
    if (lastCluster)
        *next = 0;
    else
        *next = cluster;

    return 0;
}

/*
    Examine the FAT to determine how many consecutive clusters we can
    write and where they will start.

    On entry:
        nbyte       Number of bytes we want to write. Must be a multiple
                    of cluster size.
        clus        Current cluster we're writing.
        off         Offset into current cluster we're writing. If off is
                    the size of the cluster we may have to allocate new
                    clusters. off must be either 0 or cluster size.

    On exit:
        clus        Cluster number we'll be writing to after we write
                    the consecutive clusters.
        off         Offset into clus after we write the consecutive
                    clusters.
        numWhole    Number of consecutive cluster we can write
        firstClus   First cluster we'll write
        diskF       If True disk will be full after the clusters will
                    be written.
*/

static int UTIL_write_lookahead(UInt32 nbyte, UInt32 *clus, UInt32 *off,
                                UInt32 *numWhole, UInt32 *firstClus, Bool *diskF)
{
    ptmFat32_FS_t   p = GFS;
    UInt32          cluster = *clus;
    UInt32          offset = *off;
    UInt32          numWholeClusters = 0;
    UInt32          firstCluster;
    UInt32          numWantClusters;
    UInt32          temp;
    UInt32          start;
    Bool            diskFull = False;
    Bool            lastCluster = False;
    int             info_status = 0;

    // Writing whole clusters aligned on a cluster boundary
    
    numWantClusters = nbyte / p->bytesPerCluster;

    // Do we really have to allocate new clusters?

    if (offset == p->bytesPerCluster)
    {
        info_status = UTIL_get_fat_info(cluster, &temp, &lastCluster);
//        TMFAT_DEBUG3("CHK: cluster=%u,temp=%u,lastCluster=%d\n", cluster, temp, lastCluster);
        if (info_status < 0)
            goto bail;
        else if (1 == info_status)
        {
            TMFAT_DEBUG0("UTIL_write_lookahead: disk is full.\n");
            goto bail; 
        }
        else
        {
            if ((cluster + 1) == temp)
            {
                // No, the next cluster is adjacent, start there.
                cluster = temp;
                offset = 0;
            }
            else if (lastCluster)
            {
                // Yes, current cluster is the last cluster
            }
            else
            {
                // No, next cluster is not adjacent, start there.
                cluster = temp;
                offset = 0;
                TMFAT_ASSERT (temp < p->maxCluster);
            }
        }
    }

    if (offset == p->bytesPerCluster)
    {
//        UInt32  prev;

        // Case (1): Writing newly allocated clusters at end of file.

        info_status = 0;
//        TMFAT_DEBUG3("NEW: numWantClusters=%u,cluster=%u,maxCluster=%u\n", 
//                      numWantClusters, cluster, p->maxCluster);
        while (numWantClusters > 0)
        {
            if ((info_status = UTIL_get_fat_info(cluster, &temp, &lastCluster)))
            {
                if (1 == info_status)
                {
                    TMFAT_DEBUG0("UTIL_write_lookahead: disk full.\n");
                    diskFull = True;
                }
                break;
            }
//            TMFAT_DEBUG3("CHK NEW: cluster=%u,temp=%u,lastCluster=%d\n", cluster, temp, lastCluster);
            if (temp)
            {
                // Cluster is not free
                break;
            }
            temp = cluster;
            if (UTIL_allocate_cluster(&cluster, temp, False))
            {
                TMFAT_DEBUG1("NEW: UTIL_allocate_cluster failed temp=%u\n", temp);
                cluster = temp;
                break;
            }
            numWantClusters--;
            numWholeClusters++;
            if (1 == numWholeClusters)
            {
                firstCluster = cluster;
            }
            // We may wrap around the last cluster
            if (cluster == p->maxCluster)
                break;
        }
    }
    else
    {
        // Case (2): We're on a cluster boundary (offset is 0) and
        // we're writing over old allocated clusters. Determine
        // how many contiguous clusters we have.

        TMFAT_ASSERT (offset == 0);

        start = cluster;
        firstCluster = cluster;
//        TMFAT_DEBUG3("OLD: numWantClusters=%u,cluster=%u,maxCluster=%u\n", 
//                      numWantClusters, cluster, p->maxCluster);
        while (numWantClusters > 0)
        {
            // Don't look beyond the last cluster
            if (start > p->maxCluster)
            {
                if (numWantClusters == 0)
                {
                    TMFAT_DEBUG1("Have no clusters and start=%u\n", start);
                    TMFAT_ASSERT (numWantClusters != 0);
                }
                break; 
            }
            
            if (UTIL_get_fat_info(start, &temp, &lastCluster))
            {
                // Should not fail because we're writing over existing
                // clusters.
                TMFAT_DEBUG0("UTIL_get_fat_info failed doing FAT look ahead.\n");    
                goto bail;
            }
            
            numWholeClusters++;
            numWantClusters--;

            if (lastCluster)
            {
                // Need to allocate next time
                cluster = start;
                offset = p->bytesPerCluster;
                break;
            }
            else if ((start + 1) != temp)
            {
                if (temp)
                {
                    cluster = temp;
                }
                else
                {
                    TMFAT_DEBUG0("Got unallocated cluster in a pool of allocated clusters.\n");    
                    TMFAT_ASSERT (temp != 0);
                }
                // We reached end of allocation chain or if no longer contiguous
                break;

⌨️ 快捷键说明

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