📄 fatfs_supp.c
字号:
else type = TENTRY_REGULAR;
}
else if (entry >= 0x0FFFFFF8) type = TENTRY_LAST;
else if (0x0FFFFFF7 == entry) type = TENTRY_BAD;
else type = TENTRY_RESERVED;
break;
default:
CYG_ASSERT(false, "Unknown FAT type");
type = TENTRY_BAD; // least likely to cause damage
}
return type;
}
// -------------------------------------------------------------------------
// set_tentry_type()
// Sets the type of FAT table entry.
static void
set_tentry_type(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
{
switch (disk->fat_type)
{
case FATFS_FAT12:
switch (type)
{
case TENTRY_FREE: *entry = 0x0000; return;
case TENTRY_LAST: *entry = 0x0FF8; return;
case TENTRY_RESERVED: *entry = 0x0FF0; return;
case TENTRY_BAD: *entry = 0x0FF7; return;
default:
CYG_ASSERT(false, "Unknown tentry type");
}
break;
case FATFS_FAT16:
switch (type)
{
case TENTRY_FREE: *entry = 0x0000; return;
case TENTRY_LAST: *entry = 0xFFF8; return;
case TENTRY_RESERVED: *entry = 0xFFF0; return;
case TENTRY_BAD: *entry = 0xFFF7; return;
default:
CYG_ASSERT(false, "Unknown tentry type");
}
break;
case FATFS_FAT32:
switch (type)
{
case TENTRY_FREE: *entry = 0x00000000; return;
case TENTRY_LAST: *entry = 0x0FFFFFF8; return;
case TENTRY_RESERVED: *entry = 0x0FFFFFF0; return;
case TENTRY_BAD: *entry = 0x0FFFFFF7; return;
default:
CYG_ASSERT(false, "Unknown tentry type");
}
break;
default:
CYG_ASSERT(false, "Unknown FAT type");
}
}
// -------------------------------------------------------------------------
// get_tentry_next_cluster()
// Gets the the next file cluster number from FAT table entry.
static __inline__ cyg_uint32
get_tentry_next_cluster(fatfs_disk_t *disk, cyg_uint32 entry)
{
return entry;
}
// -------------------------------------------------------------------------
// set_tentry_next_cluster()
// Sets the the next cluster number to FAT table entry.
static __inline__ void
set_tentry_next_cluster(fatfs_disk_t *disk,
cyg_uint32 *entry,
cyg_uint32 next_cluster)
{
*entry = next_cluster;
}
//==========================================================================
// FAT cluster functions
// -------------------------------------------------------------------------
// erase_cluster()
// Erases cluster (fills with 0x00).
static int
erase_cluster(fatfs_disk_t *disk, cyg_uint32 cluster)
{
cyg_uint8 data[32];
cyg_uint32 pos;
cyg_uint32 len;
int err, i;
pos = 0;
len = 32;
memset((void*)data, 0x00, len);
CYG_TRACE1(TCL, "erasing cluster=%d", cluster);
for (i = 0; i < (disk->cluster_size >> 5); i++)
{
err = disk_cluster_write(disk, (void*)data, &len, cluster, pos);
if (err != ENOERR)
return err;
pos += len;
}
return ENOERR;
}
// -------------------------------------------------------------------------
// mark_cluster()
// Marks cluster (sets the cluster's FAT table entry to given type).
static int
mark_cluster(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 type)
{
cyg_uint32 tentry;
set_tentry_type(disk, &tentry, type);
return write_tentry(disk, cluster, &tentry);
}
// -------------------------------------------------------------------------
// link_cluster()
// Links two clusters.
static int
link_cluster(fatfs_disk_t *disk, cyg_uint32 cluster1, cyg_uint32 cluster2)
{
cyg_uint32 tentry;
set_tentry_next_cluster(disk, &tentry, cluster2);
return write_tentry(disk, cluster1, &tentry);
}
// -------------------------------------------------------------------------
// find_next_free_cluster()
// Finds first free cluster starting from given cluster.
// If none is available free_cluster is set to 0.
// If CO_MARK_LAST is set in opts the found cluster is marked as LAST.
// If CO_ERASE_NEW is set in opts the found cluster is erased.
static int
find_next_free_cluster(fatfs_disk_t *disk,
cyg_uint32 start_cluster,
cyg_uint32 *free_cluster,
cluster_opts_t opts)
{
cyg_uint32 c, tentry;
int err;
if (start_cluster < 2) c = 2;
else c = start_cluster + 1;
*free_cluster = 0;
CYG_TRACE1(TCL, "starting at cluster=%d", c);
// Search from the starting cluster to the end of FAT and
// from start of FAT to the starting cluster
while (c != start_cluster)
{
// Check for end of FAT
if (c >= disk->fat_tbl_nents)
{
c = 2;
if (c >= start_cluster)
break;
}
err = read_tentry(disk, c, &tentry);
if (err != ENOERR)
return err;
if (TENTRY_FREE == get_tentry_type(disk, tentry))
{
CYG_TRACE1(TCL, "found free cluster=%d", c);
*free_cluster = c;
if (opts & CO_MARK_LAST)
err = mark_cluster(disk, c, TENTRY_LAST);
if ((err == ENOERR) && (opts & CO_ERASE_NEW))
err = erase_cluster(disk, c);
return err;
}
c++;
}
// No free clusters found
CYG_TRACE0(TCL, "!!! no free clusters found");
return ENOSPC;
}
// -------------------------------------------------------------------------
// find_and_append_cluster()
// Finds a free cluster on disk and appends it to the given cluster.
// New cluster is marked as LAST.
static int
find_and_append_cluster(fatfs_disk_t *disk,
cyg_uint32 cluster,
cyg_uint32 *new_cluster,
cluster_opts_t opts)
{
cyg_uint32 free_cluster;
int err;
err = find_next_free_cluster(disk, cluster,
&free_cluster, opts | CO_MARK_LAST);
if (err != ENOERR)
return err;
err = link_cluster(disk, cluster, free_cluster);
if (err != ENOERR)
return err;
*new_cluster = free_cluster;
CYG_TRACE2(TCL, "appending new cluster=%d to cluster=%d",
free_cluster, cluster);
return ENOERR;
}
// -------------------------------------------------------------------------
// find_nth_cluster0()
// Finds nth cluster in chain (ie nth cluster of file) searching
// from given position. The result is returned by the same position
// variable.
static int
find_nth_cluster0(fatfs_disk_t *disk,
fatfs_data_pos_t *pos,
cyg_uint32 n)
{
cyg_uint32 cluster, cluster_snum;
int err = ENOERR;
if (pos->cluster_snum == n)
return ENOERR;
cluster = pos->cluster;
cluster_snum = pos->cluster_snum;
CYG_TRACE4(TCL, "cluster=%d snum=%d n=%d n_to_search=%d",
cluster, cluster_snum, n, n-cluster_snum);
// Adjust the number of clusters that should be
// walked according to the given position
n -= cluster_snum;
// Walk the cluster chain for n clusters or until last cluster
while (n > 0)
{
cyg_uint32 tentry;
err = read_tentry(disk, cluster, &tentry);
if (err != ENOERR)
return err;
switch (get_tentry_type(disk, tentry))
{
case TENTRY_REGULAR:
break;
case TENTRY_LAST:
CYG_TRACE1(TCL, "chain end at n=%d", n);
err = EEOF; // File has less clusters than given n
// this err should be caught by the
// calling function
goto out;
default:
// Inconsistant FAT table state !!!
CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x n=%d",
tentry, n);
err = EIO;
goto out;
}
cluster = get_tentry_next_cluster(disk, tentry);
cluster_snum++;
n--;
}
out:
pos->cluster = cluster;
pos->cluster_snum = cluster_snum;
CYG_TRACE2(TCL, "nth cluster=%d snum=%d", cluster, cluster_snum);
return err;
}
// -------------------------------------------------------------------------
// find_nth_cluster()
// Finds nth cluster in chain (ie nth cluster of file) searching
// from given position. The result is returned by the same position
// variable. If the chain ends one cluster before the given nth cluster
// and the CO_EXTEND is specified, than the chain is extended by one cluster.
static int
find_nth_cluster(fatfs_disk_t *disk,
fatfs_data_pos_t *pos,
cyg_uint32 n,
cluster_opts_t opts)
{
int err;
// Find nth cluster
err = find_nth_cluster0(disk, pos, n);
// EEOF meens that the cluster chain ended early
if ((err != EEOF) || !(opts & CO_EXTEND))
return err;
// Check if one cluster short
if (pos->cluster_snum == (n - 1))
{
// Extend the chain for one cluster
cyg_uint32 new_cluster;
// Append new cluster to the end of chain
err = find_and_append_cluster(disk, pos->cluster, &new_cluster, opts);
if (err != ENOERR)
return err;
// Update position
pos->cluster = new_cluster;
pos->cluster_snum += 1;
pos->cluster_pos = 0;
CYG_TRACE1(TCL, "appended new cluster=%d", new_cluster);
}
return err;
}
// -------------------------------------------------------------------------
// get_next_cluster()
// Gets next cluster in chain (ie next cluster of file).
// If CO_EXTEND is specified and the current cluster is last in the
// chain then the chain is extended by one cluster.
static int
get_next_cluster(fatfs_disk_t *disk,
fatfs_data_pos_t *pos,
cluster_opts_t opts)
{
int err;
err = find_nth_cluster(disk, pos, pos->cluster_snum + 1, opts);
if (err != ENOERR)
return err;
// Reset inside cluster position
pos->cluster_pos = 0;
return ENOERR;
}
// -------------------------------------------------------------------------
// get_position_from_off()
// Gets position from given offset. The search is started from the
// given position and the result is returned by the same variable.
// If CO_EXTEND is specified the file is extended if one cluster too short.
static int
get_position_from_off(fatfs_disk_t *disk,
cyg_uint32 first_cluster,
cyg_uint32 offset,
fatfs_data_pos_t *pos,
cluster_opts_t opts)
{
fatfs_data_pos_t new_pos;
cyg_uint32 n;
int err;
// Position inside the cluster
new_pos.cluster_pos = offset & (disk->cluster_size - 1);
// Cluster seq number to be searched for
n = offset >> disk->cluster_size_log2;
if (n < pos->cluster_snum)
{
// Start searching from first cluster
new_pos.cluster = first_cluster;
new_pos.cluster_snum = 0;
}
else
{
// Start searching from the current position
new_pos.cluster = pos->cluster;
new_pos.cluster_snum = pos->cluster_snum;
}
err = find_nth_cluster(disk, &new_pos, n, opts);
// Err could be EEOF wich means that the given
// offset if out of given file (cluster chain)
if (EEOF == err)
new_pos.cluster_pos = disk->cluster_size;
*pos = new_pos;
return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -