📄 ff.c[2010-03-16-09-03-03].sfb
字号:
break;
case FS_FAT32 :
res = move_window(fs, fsect + (clst / (SS(fs) / 4)));
if (res != FR_OK) break;
ST_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)], val);
break;
default :
res = FR_INT_ERR;
}
fs->wflag = 1;
}
return res;
}
#endif /* !_FS_READONLY */
/*-----------------------------------------------------------------------*/
/* FAT handling - Remove a cluster chain */
/*-----------------------------------------------------------------------*/
#if !_FS_READONLY
static
FRESULT remove_chain (
FATFS *fs, /* File system object */
DWORD clst /* Cluster# to remove a chain from */
)
{
FRESULT res;
DWORD nxt;
if (clst < 2 || clst >= fs->max_clust) { /* Check the range of cluster# */
res = FR_INT_ERR;
} else {
res = FR_OK;
while (clst < fs->max_clust) { /* Not a last link? */
nxt = get_fat(fs, clst); /* Get cluster status */
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_fat(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
/*-----------------------------------------------------------------------*/
/* FAT handling - 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_fat(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_fat(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_fat(fs, ncl, 0x0FFFFFFF)) /* Mark the new cluster "in use" */
return 0xFFFFFFFF;
if (clst != 0) { /* Link it to the previous one if needed */
if (put_fat(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# */
/*-----------------------------------------------------------------------*/
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;
}
/*-----------------------------------------------------------------------*/
/* Directory handling - 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 && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
clst = dj->fs->dirbase;
if (clst == 0) { /* Static table */
dj->clust = clst;
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); /* Sector# */
}
else { /* Dynamic table */
ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */
while (idx >= ic) { /* Follow cluster chain */
clst = get_fat(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); /* Sector# */
}
dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */
return FR_OK; /* Seek succeeded */
}
/*-----------------------------------------------------------------------*/
/* Directory handling - 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->clust == 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_fat(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 dynamic 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;
}
/*-----------------------------------------------------------------------*/
/* LFN handling - 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 cmp_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 wc, uc;
i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */
s = 0; wc = 1;
do {
uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
if (wc) { /* Last char has not been processed */
wc = ff_wtoupper(uc); /* Convert it to upper case */
if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
return FALSE; /* Not matched */
} else {
if (uc != 0xFFFF) return FALSE; /* Check filler */
}
} while (++s < 13); /* Repeat until all chars in the entry are checked */
if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */
return FALSE;
return TRUE; /* The part of LFN 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 wc, uc;
i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
s = 0; wc = 1;
do {
uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
if (wc) { /* Last char has not been processed */
if (i >= _MAX_LFN) return FALSE; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */
} else {
if (uc != 0xFFFF) return FALSE; /* Check filler */
}
} while (++s < 13); /* Read all character in the entry */
if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */
if (i >= _MAX_LFN) return FALSE; /* Buffer overflow? */
lfnbuf[i] = 0;
}
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 wc;
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; /* Get offset in the LFN buffer */
s = wc = 0;
do {
if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
ST_WORD(dir+LfnOfs[s], wc); /* Put it */
if (!wc) wc = 0xFFFF; /* Padding chars following last char */
} while (++s < 13);
if (wc == 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -