📄 tmfat32.c
字号:
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 + -