📄 fatfs_supp.c
字号:
cyg_uint32 c, tentry;
int err;
if (start_cluster < 2)
c = 2;
else
c = start_cluster + 1;
*free_cluster = 0;
CYG_TRACE1(TCL, "c=%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)
{
// End of FAT check
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, "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 out of space
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;
CYG_TRACE1(TCL, "cluster=%d", cluster);
err = find_next_free_cluster(disk, cluster,
&free_cluster, opts | CO_MARK_LAST);
if (err != ENOERR)
return err;
CYG_TRACE1(TCL, "free_cluster=%d", free_cluster);
// Link clusters
err = link_cluster(disk, cluster, free_cluster);
if (err != ENOERR)
return err;
*new_cluster = free_cluster;
CYG_TRACE1(TCL, "new_cluster=%d", free_cluster);
return ENOERR;
}
// -------------------------------------------------------------------------
// find_nth_cluster0()
// Finds nth cluster in chain (ie nth cluster of file).
// Searching from given position.
static int
find_nth_cluster0(fatfs_disk_t *disk,
fatfs_data_pos_t *dpos,
cyg_uint32 n,
fatfs_tcache_t *tcache)
{
cyg_uint32 cluster, cluster_snum;
int err = ENOERR;
// Trivial case check
if (dpos->cluster_snum == n)
return ENOERR;
// First look in cache
if (NULL != tcache)
{
cyg_uint32 c, ln;
if (fatfs_tcache_get(disk, tcache, n, &c))
{
// Cluster in cache
dpos->cluster = c;
dpos->cluster_snum = n;
CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d in cache", c, n);
return ENOERR;
}
else if (fatfs_tcache_get_last(disk, tcache, &ln, &c))
{
// Cluster not in cache - get last
// in cache and search from there
dpos->cluster = c;
dpos->cluster_snum = ln;
CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d last in cache", c, ln);
}
else
{
// Empty cache - put first cluster in
fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->cluster);
}
}
cluster = dpos->cluster;
cluster_snum = dpos->cluster_snum;
CYG_TRACE4(TCL, "cluster=%d cluster_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:
// Oops early last cluster
CYG_TRACE1(TCL, "chain end 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++;
if (NULL != tcache)
fatfs_tcache_set(disk, tcache, cluster_snum, cluster);
n--;
}
out:
dpos->cluster = cluster;
dpos->cluster_snum = cluster_snum;
CYG_TRACE2(TCL, "nth cluster=%d cluster_snum=%d", cluster, cluster_snum);
return err;
}
// -------------------------------------------------------------------------
// find_nth_cluster()
// Finds nth cluster in chain (ie nth cluster of file) searching
// from given position. If the chain ends one cluster before the
// given nth cluster and the CO_EXTEND is specifide, than the
// chain is extended by one cluster.
static int
find_nth_cluster(fatfs_disk_t *disk,
fatfs_data_pos_t *dpos,
cyg_uint32 n,
fatfs_tcache_t *tcache,
cluster_opts_t opts)
{
int err;
// Find nth cluster
err = find_nth_cluster0(disk, dpos, n, tcache);
// EEOF meens that the cluster chain ended early
if ((err != EEOF) || !(opts & CO_EXTEND))
return err;
CYG_TRACE2(TCL, "cluster_snum=%d n=%d", dpos->cluster_snum, n);
// Check if one cluster short
if (dpos->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, dpos->cluster,
&new_cluster, opts);
if (err != ENOERR)
return err;
// Update position
dpos->cluster = new_cluster;
dpos->cluster_snum++;
dpos->cluster_pos = 0;
CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d",
dpos->cluster, dpos->cluster_snum);
// Update cache
if (NULL != tcache)
fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->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
// chain then the chain is extended by one cluster.
static int
get_next_cluster(fatfs_disk_t *disk,
fatfs_data_pos_t *dpos,
fatfs_tcache_t *tcache,
cluster_opts_t opts)
{
int err;
CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d",
dpos->cluster, dpos->cluster_snum);
err = find_nth_cluster(disk, dpos, dpos->cluster_snum + 1, tcache, opts);
if (err != ENOERR)
return err;
// Update position
dpos->cluster_pos = 0;
CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d",
dpos->cluster, dpos->cluster_snum);
return ENOERR;
}
// -------------------------------------------------------------------------
// get_data_position_from_off()
// Gets data position from given file offset.
// If CO_EXTEND is specified the file is extended if
// one cluster too short.
static int
get_data_position_from_off(fatfs_disk_t *disk,
cyg_uint32 first_cluster,
cyg_uint32 offset,
fatfs_data_pos_t *dpos,
fatfs_tcache_t *tcache,
cluster_opts_t opts)
{
cyg_uint32 n;
int err;
// Position inside the cluster
dpos->cluster_pos = offset & (disk->cluster_size - 1);
// Cluster seq number to be searched for
n = offset >> disk->cluster_size_log2;
// Start searching from first cluster
dpos->cluster = first_cluster;
dpos->cluster_snum = 0;
CYG_TRACE4(TCL, "off=%d first_cluster=%d cluster_pos=%d n=%d\n",
offset, first_cluster, dpos->cluster_pos, n);
err = find_nth_cluster(disk, dpos, n, tcache, opts);
// Err could be EEOF wich means that the given
// offset if out of given file (cluster chain)
return err;
}
// -------------------------------------------------------------------------
// free_cluster_chain()
// Marks all clusters FREE from given cluster to the last cluster in chain.
static int
free_cluster_chain(fatfs_disk_t *disk, cyg_uint32 start_cluster)
{
cyg_uint32 c, next_c, tentry;
bool last;
int err;
CYG_TRACE1(TCL, "start_cluster=%d", start_cluster);
c = next_c = start_cluster;
last = false;
while (!last)
{
err = read_tentry(disk, c, &tentry);
if (err != ENOERR)
return err;
switch (get_tentry_type(disk, tentry))
{
case TENTRY_LAST:
// Last cluster in chain
last = true;
break;
case TENTRY_REGULAR:
// Get next cluster in chain
next_c = get_tentry_next_cluster(disk, tentry);
break;
default:
CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x c=%d",
tentry, c);
return EIO;
}
// Set the current tentry to FREE
set_tentry_type(disk, &tentry, TENTRY_FREE);
err = write_tentry(disk, c, &tentry);
if (err != ENOERR)
return err;
// Next cluster in chain
c = next_c;
}
CYG_TRACE1(TCL, "last_cluster=%d", c);
return ENOERR;
}
//==========================================================================
// FAT dir entry functions
// -------------------------------------------------------------------------
// print_dentry()
// Prints FAT directory entry.
#if TDE
static void
print_dentry(fat_dir_entry_t* fde)
{
if (DENTRY_IS_DELETED(fde))
diag_printf("FAT: FDE name: '?%.7s'\n", &fde->name[1]);
else
diag_printf("FAT: FDE name: '%.8s'\n", fde->name);
diag_printf("FAT: FDE ext: '%.3s'\n", fde->ext);
diag_printf("FAT: FDE attr: %c%c%c%c%c%c\n",
(DENTRY_IS_RDONLY(fde) ? 'R' : '-'),
(DENTRY_IS_HIDDEN(fde) ? 'H' : '-'),
(DENTRY_IS_SYSTEM(fde) ? 'S' : '-'),
(DENTRY_IS_VOLUME(fde) ? 'V' : '-'),
(DENTRY_IS_DIR(fde) ? 'D' : '-'),
(DENTRY_IS_ARCHIVE(fde) ? 'A' : '-'));
diag_printf("FAT: FDE crt time: %u\n", fde->crt_time);
diag_printf("FAT: FDE crt date: %u\n", fde->crt_date);
diag_printf("FAT: FDE acc date: %u\n", fde->acc_date);
diag_printf("FAT: FDE wrt time: %u\n", fde->wrt_time);
diag_printf("FAT: FDE wrt date: %u\n", fde->wrt_date);
diag_printf("FAT: FDE cluster: %u\n", fde->cluster);
diag_printf("FAT: FDE size: %u\n", fde->size);
}
#endif // TDE
// -------------------------------------------------------------------------
// read_dentry()
// Reads dir entry from disk.
// If cluster is 0 reads from root dir.
static int
read_dentry(fatfs_disk_t *disk,
fatfs_data_pos_t *dpos,
fat_dir_entry_t *fde)
{
unsigned char data[DENTRY_SIZE];
cyg_uint32 apos;
int len, err;
// Check if we are reading the root directory
if (0 == dpos->cluster)
apos = disk->fat_root_dir_pos + dpos->cluster_pos;
else
apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);
CYG_TRACE3(TDE, "cluster=%d pos=%d apos=%d",
dpos->cluster, dpos->cluster_pos, apos);
len = DENTRY_SIZE;
err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, apos);
if (err != ENOERR)
return err;
GET_BYTES(data, fde->name, 8, 0x00);
GET_BYTES(data, fde->ext, 3, 0x08);
GET_BYTE(data, fde->attr, 0x0B);
GET_BYTE(data, fde->nt_reserved, 0x0C);
GET_BYTE(data, fde->crt_sec_100, 0x0D);
GET_WORD(data, fde->crt_time, 0x0E);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -