📄 tmfat32.c
字号:
}
else
{
// Keep looking
start++;
cluster = start;
}
}
}
// An error if we can't write anything
if (0 == numWholeClusters)
goto bail;
// TMFAT_DEBUG5("numWholeClusters=%u,firstCluster=%u,cluster=%u,offset=%u,diskFull=%d\n",
// numWholeClusters,firstCluster,cluster,offset,diskFull);
*clus = cluster;
*off = offset;
*numWhole = numWholeClusters;
*firstClus = firstCluster;
*diskF = diskFull;
return 0;
bail:
return 1;
}
// Get or set cluster content through the DATA cache. Return the number of
// bytes actually read or written. Return -1 if there is an error. Since
// the number of bytes read or written may span several clusters return the
// final cluster number and offset into that cluster. Writing may update
// the cluster chain in the FAT and it may run out of space on the disk.
// Reading/writing in the root directory for FAT12 or FAT16 is a special
// case because it is of fixed size and cached separately from the DATA
// cache. Returned offset can be bytesPerCluster. In that case:
//
// reading -- we read the last byte in the last cluster
// writing -- we wrote the last byte in the last cluster and any
// subsequent writes will need to allocate a new cluster.
static Int32 UTIL_cluster_content(int op, UInt32 *clus, UInt32 *off, UInt8 *data, UInt32 nbyte)
{
ptmFat32_FS_t p = GFS;
UInt8 *src;
UInt8 *dst;
Int32 actual = 0;
UInt32 cluster;
UInt32 temp;
UInt32 offset;
UInt32 size = 0;
UInt32 i;
UInt32 j;
Bool lastCluster;
// Check parameter values
TMFAT_ASSERT (data != Null);
TMFAT_ASSERT (clus != Null);
TMFAT_ASSERT (off != Null);
cluster = *clus;
offset = *off;
if (nbyte == 0)
return 0;
if (p->fsType == tmFat32_FAT32)
{
if (cluster < p->rootDirCluster || cluster > p->maxCluster)
{
TMFAT_DEBUG3("UTIL_cluster_content: cluster %u is out of range (%u,%u)\n",
cluster, p->rootDirCluster, p->maxCluster);
return -1;
}
}
else
{
if (cluster > p->maxCluster)
{
TMFAT_DEBUG3("UTIL_cluster_content: cluster %u is out of range (%u,%u)\n",
cluster, p->rootDirCluster, p->maxCluster);
return -1;
}
}
if (offset > p->bytesPerCluster)
{
TMFAT_DEBUG2("UTIL_cluster_content: offset %u >= %u.\n", offset, p->bytesPerCluster);
return -1;
}
if (op == GET_CLUSTER_CONTENT)
{
if (offset == p->bytesPerCluster)
{
TMFAT_DEBUG2("GET_CLUSTER_CONTENT offset == p->bytesPerCluster, offset=%u, cluster=%u\n",
offset, cluster);
return -1;
}
// Data comes from data cache, not from the media directly.
// We can retrieve at most a cluster's worth of data at a
// time since that is the biggest allocation unit.
dst = data;
// Special case: reading from FAT12/FAT16 root directory
if (p->fsType != tmFat32_FAT32 && cluster == 0)
{
src = p->rootDirCache;
if (nbyte > p->rootDirNumSectors * p->dev->Info->bytesPerSector - offset)
{
TMFAT_DEBUG0("UTIL_cluster_content: Attemping to read beyond root directory.\n");
goto done;
}
memcpy(dst, &src[offset], nbyte);
actual = nbyte;
offset += nbyte;
goto done;
}
while (nbyte > 0)
{
if (!(src = UTIL_get_cluster_address(cluster)))
{
TMFAT_DEBUG1("GET_CLUSTER_CONTENT: UTIL_get_cluster_address(%d) failed.\n", cluster);
goto done;
}
size = TMFAT_MIN(p->bytesPerCluster - offset, nbyte);
memcpy(dst, &src[offset], size);
nbyte -= size;
actual += size;
dst += size;
offset += size;
// Do we need to jump to the next cluster?
if (offset == p->bytesPerCluster)
{
lastCluster = False;
i = cluster;
if (UTIL_fat_content(GET_FAT_ENTRY, cluster, 0, &temp))
{
TMFAT_DEBUG1("GET_CLUSTER_CONTENT: UTIL_fat_content(%d) failed.\n", cluster);
goto done;
}
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;
}
if (lastCluster) // At end of file and file size is a multiple of cluster size
{
cluster = i;
break;
}
else // At the beginning of a cluster
offset = 0;
}
}
}
else
{
src = data;
// Special case: writing to FAT12/FAT16 root directory
if (p->fsType != tmFat32_FAT32 && cluster == 0)
{
UInt32 first;
UInt32 last;
if (offset == p->bytesPerCluster)
{
TMFAT_DEBUG2("Not FAT32 and SET_CLUSTER_CONTENT offset == p->bytesPerCluster, offset=%u, cluster=%u\n",
offset, cluster);
return -1;
}
dst = p->rootDirCache;
if (nbyte > p->rootDirNumSectors * p->dev->Info->bytesPerSector - offset)
{
TMFAT_DEBUG0("UTIL_cluster_content: Attemping to write beyond root directory.\n");
goto done;
}
memcpy(&dst[offset], src, nbyte);
actual = nbyte;
offset += nbyte;
// Mark the affected sectors are dirty.
first = offset / p->dev->Info->bytesPerSector;
last = (offset + nbyte) / p->dev->Info->bytesPerSector;
for (i = first; i <= last; i++)
p->rootDirSectorDirty[i] = True;
goto done;
}
if (op == SET_CLUSTER_CONTENT_NOCACHE)
{
// Avoid the cache, if possible. We may have to go through partial cluster
// writes. Faster, but more complicated.
tmErrorCode_t status;
UInt64 sec;
Bool diskFull;
UInt32 numWholeClusters; // Number of whole clusters to write
UInt32 firstCluster; // First cluster written
UInt8 *src_data = src;
/* Write as many sequential clusters at a time as possible. There are three
cases when sequential clusters are available:
(1) Allocate new clusters, e.g., when writing past end of file.
(2) We're re-writing already allocated sequential clusters, e.g., a file
opened as O_RDWR and entire write is before end of file.
(3) Combination of (1) and (2). E.g., the write starts in the middle of
the file on clusters already allocated and we'll write past the end
of file allocating new clusters.
We only handle cases (1) and (2). Case (3) is rare. It's equivalent to doing
a write twice -- the first part as case (1) and the second part as case (2)
so it's not a signifcant performance loss to break it up into two steps.
*/
// TMFAT_DEBUG3("NOCACHE: cluster=%d,nbyte=%d,offset=%d\n", cluster, nbyte, offset);
while (nbyte > 0)
{
if (UTIL_write_lookahead(nbyte, &cluster, &offset, &numWholeClusters,
&firstCluster, &diskFull))
{
TMFAT_DEBUG0("UTIL_write_lookahead failed.\n");
goto done;
}
if (!numWholeClusters)
{
TMFAT_DEBUG0("No whole clusters to write.\n");
TMFAT_ASSERT (numWholeClusters != 0);
}
// Determine starting sector
sec = p->dataAreaBase + (firstCluster - p->rootDirCluster) * p->sectorsPerCluster;
// Clusters have been allocated. Now write them.
size = numWholeClusters * p->bytesPerCluster;
src_data = src; // Where we're writing from
status = p->dev->Write(p->dev->Info,
sec, // Starting sector
numWholeClusters * p->sectorsPerCluster, // Number of sectors
src);
if (status != TM_OK)
{
TMFAT_DEBUG0("UTIL_cluster_content: cache-less write failed.\n");
goto done;
}
// Because we didn't write through the DATA cache its contents no longer
// match what's on disk. Make it the same.
for (j = 0; j < numWholeClusters; j++)
{
for (i = 0; i < p->dataNumClusters; i++)
{
if ((firstCluster + j) == p->dataCluster[i])
{
memcpy(UTIL_get_cluster_address(firstCluster + j), // Destination
&src_data[j * p->bytesPerCluster], // Source
p->bytesPerCluster); // Bytes
// Since it's already been written to disk it's no longer dirty.
p->dataClusterDirty[i] = False;
}
}
}
nbyte -= size;
actual += size;
src += size;
// A full disk is not an error. We just report what we were able to write.
if (diskFull)
goto done;
}
}
else
{
// Write through the DATA cache, one cluster at a time. Simpler, but slower.
while (nbyte > 0)
{
// Do we need to allocate another cluster? Clusters allocated for directories
// must be cleared before writing to them. Do not allocate another cluster
// if there is no more data to write.
if (offset == p->bytesPerCluster)
{
UInt32 cur_cluster = cluster;
if (UTIL_allocate_cluster(&cluster, cur_cluster, (op == SET_CLUSTER_CONTENT_CLEAR)))
goto done;
offset = 0;
}
if (!(dst = UTIL_get_cluster_address(cluster)))
{
TMFAT_DEBUG1("UTIL_cluster_content: UTIL_get_cluster_address(%d) failed.\n", cluster);
goto done;
}
size = TMFAT_MIN(p->bytesPerCluster - offset, nbyte);
memcpy(&dst[offset], src, size);
nbyte -= size;
actual += size;
src += size;
offset += size;
// Mark it dirty
for (i = 0; i < p->dataNumClusters; i++)
{
if (cluster == p->dataCluster[i])
{
p->dataClusterDirty[i] = True;
break;
}
}
}
}
}
done:
if (actual >= 0)
{
*clus = cluster;
*off = offset;
}
return actual;
}
// Get or set a FAT entry. Return 0 on success.
static int UTIL_fat_content(int op, UInt32 entry, UInt32 value, UInt32 *result)
{
tmErrorCode_t status = TM_OK;
ptmFat32_FS_t p = GFS;
UInt32 i;
UInt64 sector = 0;
UInt32 offset = 0;
UInt32 index = 0;
UInt32 entries_per_sector;
UInt64 fatBase;
UInt16 *pfat;
UInt16 temp;
if (entry > p->maxCluster)
{
TMFAT_DEBUG2("UTIL_fat_content: entry %d > %d.\n", entry, p->maxCluster);
return 1;
}
if (op == GET_FAT_ENTRY)
{
TMFAT_ASSERT (result != Null);
}
fatBase = p->fatBase + p->activeFat * p->fatSize;
if (p->fsType == tmFat32_FAT32)
entries_per_sector = p->dev->Info->bytesPerSector / sizeof(UInt32);
else if (p->fsType == tmFat32_FAT16)
entries_per_sector = p->dev->Info->bytesPerSector / sizeof(UInt16);
else
{
// FAT12 is entirely cached
goto done;
}
sector = fatBase + entry / entries_per_sector;
index = sector - fatBase;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -