📄 ff.c
字号:
if (nxt == 0) break; /* Empty cluster? */
if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
res = put_cluster(fs, clst, 0); /* Mark the cluster "empty" */
if (res != FR_OK) break;
if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
fs->free_clust++;
fs->fsi_flag = 1;
}
clst = nxt; /* Next cluster */
}
}
return res;
}
#endif
/*-----------------------------------------------------------------------*/
/* Stretch or create a cluster chain */
/*-----------------------------------------------------------------------*/
#if !_FS_READONLY
static
DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
FATFS *fs, /* File system object */
DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
)
{
DWORD cs, ncl, scl, mcl;
mcl = fs->max_clust;
if (clst == 0) { /* Create new chain */
scl = fs->last_clust; /* Get suggested start point */
if (scl == 0 || scl >= mcl) scl = 1;
}
else { /* Stretch existing chain */
cs = get_cluster(fs, clst); /* Check the cluster status */
if (cs < 2) return 1; /* It is an invalid cluster */
if (cs < mcl) return cs; /* It is already followed by next cluster */
scl = clst;
}
ncl = scl; /* Start cluster */
for (;;) {
ncl++; /* Next cluster */
if (ncl >= mcl) { /* Wrap around */
ncl = 2;
if (ncl > scl) return 0; /* No free custer */
}
cs = get_cluster(fs, ncl); /* Get the cluster status */
if (cs == 0) break; /* Found a free cluster */
if (cs == 0xFFFFFFFF || cs == 1)/* An error occured */
return cs;
if (ncl == scl) return 0; /* No free custer */
}
if (put_cluster(fs, ncl, 0x0FFFFFFF)) /* Mark the new cluster "in use" */
return 0xFFFFFFFF;
if (clst != 0) { /* Link it to previous one if needed */
if (put_cluster(fs, clst, ncl))
return 0xFFFFFFFF;
}
fs->last_clust = ncl; /* Update FSINFO */
if (fs->free_clust != 0xFFFFFFFF) {
fs->free_clust--;
fs->fsi_flag = 1;
}
return ncl; /* Return new cluster number */
}
#endif /* !_FS_READONLY */
/*-----------------------------------------------------------------------*/
/* Get sector# from cluster# */
/*-----------------------------------------------------------------------*/
static
DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */
FATFS *fs, /* File system object */
DWORD clst /* Cluster# to be converted */
)
{
clst -= 2;
if (clst >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */
return clst * fs->csize + fs->database;
}
/*-----------------------------------------------------------------------*/
/* Seek directory index */
/*-----------------------------------------------------------------------*/
static
FRESULT dir_seek (
DIR *dj, /* Pointer to directory object */
WORD idx /* Directory index number */
)
{
DWORD clst;
WORD ic;
dj->index = idx;
clst = dj->sclust;
if (clst == 1 || clst >= dj->fs->max_clust) /* Check start cluster range */
return FR_INT_ERR;
if (clst == 0) { /* Static table */
if (idx >= dj->fs->n_rootdir) /* Index is out of range */
return FR_INT_ERR;
dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32);
}
else { /* Dynamic table */
ic = SS(dj->fs) / 32 * dj->fs->csize; /* Indexes per cluster */
while (idx >= ic) { /* Follow cluster chain */
clst = get_cluster(dj->fs, clst); /* Get next cluster */
if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
if (clst < 2 || clst >= dj->fs->max_clust) /* Reached to end of table or int error */
return FR_INT_ERR;
idx -= ic;
}
dj->clust = clst;
dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32);
}
dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32;
return FR_OK; /* Seek succeeded */
}
/*-----------------------------------------------------------------------*/
/* Move directory index next */
/*-----------------------------------------------------------------------*/
static
FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
DIR *dj, /* Pointer to directory object */
BOOL streach /* FALSE: Do not streach table, TRUE: Streach table if needed */
)
{
DWORD clst;
WORD i;
i = dj->index + 1;
if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
return FR_NO_FILE;
if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */
dj->sect++; /* Next sector */
if (dj->sclust == 0) { /* Static table */
if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
return FR_NO_FILE;
}
else { /* Dynamic table */
if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
clst = get_cluster(dj->fs, dj->clust); /* Get next cluster */
if (clst <= 1) return FR_INT_ERR;
if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
if (clst >= dj->fs->max_clust) { /* When it reached end of dinamic table */
#if !_FS_READONLY
BYTE c;
if (!streach) return FR_NO_FILE; /* When do not streach, report EOT */
clst = create_chain(dj->fs, dj->clust); /* Streach cluster chain */
if (clst == 0) return FR_DENIED; /* No free cluster */
if (clst == 1) return FR_INT_ERR;
if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
/* Clean-up streached table */
if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
dj->fs->wflag = 1;
if (move_window(dj->fs, 0)) return FR_DISK_ERR;
dj->fs->winsect++;
}
dj->fs->winsect -= c; /* Rewind window address */
#else
return FR_NO_FILE; /* Report EOT */
#endif
}
dj->clust = clst; /* Initialize data for new cluster */
dj->sect = clust2sect(dj->fs, clst);
}
}
}
dj->index = i;
dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Test/Pick/Fit an LFN segment from/to directory entry */
/*-----------------------------------------------------------------------*/
#if _USE_LFN
static
const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
static
BOOL test_lfn ( /* TRUE:Matched, FALSE:Not matched */
WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
BYTE *dir /* Pointer to the directory entry containing a part of LFN */
)
{
int i, s;
WCHAR wc1, wc2;
i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Offset in the LFN buffer */
s = 0;
do {
if (i >= _MAX_LFN) return FALSE; /* Out of buffer range? */
wc1 = LD_WORD(dir+LfnOfs[s]); /* Get both characters to compare */
wc2 = lfnbuf[i++];
if (IsLower(wc1)) wc1 -= 0x20; /* Compare it (ignore case) */
if (IsLower(wc2)) wc2 -= 0x20;
if (wc1 != wc2) return FALSE;
} while (++s < 13 && wc1); /* Repeat until last char or a NUL char is processed */
return TRUE; /* The LFN entry matched */
}
static
BOOL pick_lfn ( /* TRUE:Succeeded, FALSE:Buffer overflow */
WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
BYTE *dir /* Pointer to the directory entry */
)
{
int i, s;
WCHAR wchr;
i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Offset in the LFN buffer */
s = 0;
do {
wchr = LD_WORD(dir+LfnOfs[s]); /* Get an LFN char */
if (!wchr) break; /* End of LFN? */
if (i >= _MAX_LFN) return FALSE; /* Buffer overflow */
lfnbuf[i++] = wchr; /* Store it */
} while (++s < 13); /* Repeat until last char is copied */
if (dir[LDIR_Ord] & 0x40) lfnbuf[i] = 0; /* Put terminator if last LFN entry */
return TRUE;
}
#if !_FS_READONLY
static
void fit_lfn (
const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
BYTE *dir, /* Pointer to the directory entry */
BYTE ord, /* LFN order (1-20) */
BYTE sum /* SFN sum */
)
{
int i, s;
WCHAR wchr;
dir[LDIR_Chksum] = sum; /* Set check sum */
dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
dir[LDIR_Type] = 0;
ST_WORD(dir+LDIR_FstClusLO, 0);
i = (ord - 1) * 13; /* Offset in the LFN buffer */
s = wchr = 0;
do {
if (wchr != 0xFFFF) wchr = lfnbuf[i++]; /* Get an effective char */
ST_WORD(dir+LfnOfs[s], wchr); /* Put it */
if (!wchr) wchr = 0xFFFF; /* Padding chars following last char */
} while (++s < 13);
if (wchr == 0xFFFF || !lfnbuf[i]) ord |= 0x40;/* Bottom LFN part is the start of LFN sequence */
dir[LDIR_Ord] = ord; /* Set the LFN order */
}
#endif
#endif
/*-----------------------------------------------------------------------*/
/* Create numbered name */
/*-----------------------------------------------------------------------*/
#if _USE_LFN
void gen_numname (
BYTE *dst, /* Pointer to genartated SFN */
const BYTE *src, /* Pointer to source SFN to be modified */
const WCHAR *lfn, /* Pointer to LFN */
WORD num /* Sequense number */
)
{
char ns[8];
int i, j;
mem_cpy(dst, src, 11);
if (num > 5) { /* On many collisions, generate a hash number instead of sequencial number */
do num = (num >> 1) + (num << 15) + (WORD)*lfn++; while (*lfn);
}
/* itoa */
i = 7;
do {
ns[i--] = (num % 10) + '0';
num /= 10;
} while (num);
ns[i] = '~';
/* Append the number */
for (j = 0; j < i && dst[j] != ' '; j++) {
if (IsDBCS1(dst[j])) {
if (j == i - 1) break;
j++;
}
}
do {
dst[j++] = (i < 8) ? ns[i++] : ' ';
} while (j < 8);
}
#endif
/*-----------------------------------------------------------------------*/
/* Calculate sum of an SFN */
/*-----------------------------------------------------------------------*/
#if _USE_LFN
static
BYTE sum_sfn (
const BYTE *dir /* Ptr to directory entry */
)
{
BYTE sum = 0;
int n = 11;
do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
return sum;
}
#endif
/*-----------------------------------------------------------------------*/
/* Find an object in the directory */
/*-----------------------------------------------------------------------*/
static
FRESULT dir_find (
DIR *dj /* Pointer to the directory object linked to the file name */
)
{
FRESULT res;
BYTE a, c, lfen, ord, sum, *dir;
res = dir_seek(dj, 0); /* Rewind directory object */
if (res != FR_OK) return res;
ord = sum = 0xFF; lfen = *(dj->fn+11) & 1;
do {
res = move_window(dj->fs, dj->sect);
if (res != FR_OK) break;
dir = dj->dir; /* Ptr to the directory entry of current index */
c = dir[DIR_Name];
if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
a = dir[DIR_Attr] & AM_MASK;
#if _USE_LFN /* LFN configuration */
if (c == 0xE5 || c == '.' || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
ord = 0xFF;
} else {
if (a == AM_LFN) { /* An LFN entry is found */
if (dj->lfn) {
if (c & 0x40) { /* Is it start of LFN sequence? */
sum = dir[LDIR_Chksum];
c &= 0xBF; ord = c; /* LFN start order */
dj->lfn_idx = dj->index;
}
/* Check LFN validity. Compare LFN if it is out of 8.3 format */
ord = (c == ord && sum == dir[LDIR_Chksum] && (!lfen || test_lfn(dj->lfn, dir))) ? ord - 1 : 0xFF;
}
} else { /* An SFN entry is found */
if (ord || sum != sum_sfn(dir)) { /* Did not LFN match? */
dj->lfn_idx = 0xFFFF;
ord = 0xFF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -