📄 ff.c[2010-03-16-09-03-03].sfb
字号:
/*-----------------------------------------------------------------------*/
/* 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
/*-----------------------------------------------------------------------*/
/* Directory handling - 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 c, *dir;
#if _USE_LFN
BYTE a, ord, sum;
#endif
res = dir_seek(dj, 0); /* Rewind directory object */
if (res != FR_OK) return res;
#if _USE_LFN
ord = sum = 0xFF;
#endif
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 */
#if _USE_LFN /* LFN configuration */
a = dir[DIR_Attr] & AM_MASK;
if (c == 0xE5 || ((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 validity of the LFN entry and compare it with given name */
ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
}
} else { /* An SFN entry is found */
if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
}
}
#else /* Non LFN configuration */
if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
break;
#endif
res = dir_next(dj, FALSE); /* Next entry */
} while (res == FR_OK);
return res;
}
/*-----------------------------------------------------------------------*/
/* Read an object from the directory */
/*-----------------------------------------------------------------------*/
#if _FS_MINIMIZE <= 1
static
FRESULT dir_read (
DIR *dj /* Pointer to the directory object that pointing the entry to be read */
)
{
FRESULT res;
BYTE c, *dir;
#if _USE_LFN
BYTE a, ord = 0xFF, sum = 0xFF;
#endif
res = FR_NO_FILE;
while (dj->sect) {
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 */
#if _USE_LFN /* LFN configuration */
a = dir[DIR_Attr] & AM_MASK;
if (c == 0xE5 || (!_FS_RPATH && 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 (c & 0x40) { /* Is it start of LFN sequence? */
sum = dir[LDIR_Chksum];
c &= 0xBF; ord = c;
dj->lfn_idx = dj->index;
}
/* Check LFN validity and capture it */
ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
} else { /* An SFN entry is found */
if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
dj->lfn_idx = 0xFFFF; /* It has no LFN. */
break;
}
}
#else /* Non LFN configuration */
if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
break;
#endif
res = dir_next(dj, FALSE); /* Next entry */
if (res != FR_OK) break;
}
if (res != FR_OK) dj->sect = 0;
return res;
}
#endif
/*-----------------------------------------------------------------------*/
/* Register an object to the directory */
/*-----------------------------------------------------------------------*/
#if !_FS_READONLY
static
FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
DIR *dj /* Target directory with object name to be created */
)
{
FRESULT res;
BYTE c, *dir;
#if _USE_LFN /* LFN configuration */
WORD n, ne, is;
BYTE sn[12], *fn, sum;
WCHAR *lfn;
fn = dj->fn; lfn = dj->lfn;
mem_cpy(sn, fn, 12);
if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME; /* Cannot create dot entry */
if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
fn[NS] = 0; dj->lfn = NULL; /* Find only SFN */
for (n = 1; n < 100; n++) {
gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
res = dir_find(dj); /* Check if the name collides with existing SFN */
if (res != FR_OK) break;
}
if (n == 100) return FR_DENIED; /* Abort if too many collisions */
if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
fn[NS] = sn[NS]; dj->lfn = lfn;
}
if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve reserve an SFN + LFN entries. */
for (ne = 0; lfn[ne]; ne++) ;
ne = (ne + 25) / 13;
} else { /* Otherwise reserve only an SFN entry. */
ne = 1;
}
/* Reserve contiguous entries */
res = dir_seek(dj, 0);
if (res != FR_OK) return res;
n = is = 0;
do {
res = move_window(dj->fs, dj->sect);
if (res != FR_OK) break;
c = *dj->dir; /* Check the entry status */
if (c == 0xE5 || c == 0) { /* Is it a blank entry? */
if (n == 0) is = dj->index; /* First index of the contigulus entry */
if (++n == ne) break; /* A contiguous entry that requiered count is found */
} else {
n = 0; /* Not a blank entry. Restart to search */
}
res = dir_next(dj, TRUE); /* Next entry with table streach */
} while (res == FR_OK);
if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
res = dir_seek(dj, is);
if (res == FR_OK) {
sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
ne--;
do { /* Store LFN entries in bottom first */
res = move_window(dj->fs, dj->sect);
if (res != FR_OK) break;
fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
dj->fs->wflag = 1;
res = dir_next(dj, FALSE); /* Next entry */
} while (res == FR_OK && --ne);
}
}
#else /* Non LFN configuration */
res = dir_seek(dj, 0);
if (res == FR_OK) {
do { /* Find a blank entry for the SFN */
res = move_window(dj->fs, dj->sect);
if (res != FR_OK) break;
c = *dj->dir;
if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */
res = dir_next(dj, TRUE); /* Next entry with table streach */
} while (res == FR_OK);
}
#endif
if (res == FR_OK) { /* Initialize the SFN entry */
res = move_window(dj->fs, dj->sect);
if (res == FR_OK) {
dir = dj->dir;
mem_set(dir, 0, 32); /* Clean the entry */
mem_cpy(dir, dj->fn, 11); /* Put SFN */
dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
dj->fs->wflag = 1;
}
}
return res;
}
#endif /* !_FS_READONLY */
/*-----------------------------------------------------------------------*/
/* Remove an object from the directory */
/*-----------------------------------------------------------------------*/
#if !_FS_READONLY && !_FS_MINIMIZE
static
FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
DIR *dj /* Directory object pointing the entry to be removed */
)
{
FRESULT res;
#if _USE_LFN /* LFN configuration */
WORD i;
i = dj->index; /* SFN index */
res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
if (res == FR_OK) {
do {
res = move_window(dj->fs, dj->sect);
if (res != FR_OK) break;
*dj->dir = 0xE5; /* Mark the entry "deleted" */
dj->fs->wflag = 1;
if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
res = dir_next(dj, FALSE); /* Next entry */
} while (res == FR_OK);
if (res == FR_NO_FILE) res = FR_INT_ERR;
}
#else /* Non LFN configuration */
res = dir_seek(dj, dj->index);
if (res == FR_OK) {
res = move_window(dj->fs, dj->sect);
if (res == FR_OK) {
*dj->dir = 0xE5; /* Mark the entry "deleted" */
dj->fs->wflag = 1;
}
}
#endif
return res;
}
#endif /* !_FS_READONLY */
/*-----------------------------------------------------------------------*/
/* Pick a segment and create the object name in directory form */
/*-----------------------------------------------------------------------*/
static
FRESULT create_name (
DIR *dj, /* Pointer to the directory object */
const XCHAR **path /* Pointer to pointer to the segment in the path string */
)
{
#ifdef _EXCVT
static const BYTE cvt[] = _EXCVT;
#endif
#if _USE_LFN /* LFN configuration */
BYTE b, cf;
WCHAR w, *lfn;
int i, ni, si, di;
const XCHAR *p;
/* Create LFN in Unicode */
si = di = 0;
p = *path;
lfn = dj->lfn;
for (;;) {
w = p[si++]; /* Get a character */
if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
if (di >= _MAX_LFN) /* Reject too long name */
return FR_INVALID_NAME;
#if !_LFN_UNICODE
w &= 0xFF;
if (IsDBCS1(w)) { /* If it is a DBC 1st byte */
b = p[si++]; /* Get 2nd byte */
if (!IsDBCS2(b)) /* Reject invalid code for DBC */
return FR_INVALID_NAME;
w = (w << 8) + b;
}
w = ff_convert(w, 1); /* Convert OEM to Unicode */
if (!w) return FR_INVALID_NAME; /* Reject invalid code */
#endif
if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
return FR_INVALID_NAME;
lfn[di++] = w; /* Store the Unicode char */
}
*path = &p[si]; /* Rerurn pointer to the next segment */
cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
#if _FS_RPATH
if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
lfn[di] = 0;
for (i = 0; i < 11; i++)
dj->fn[i] = (i < di) ? '.' : ' ';
dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
return FR_OK;
}
#endif
while (di) { /* Strip trailing spaces and dots */
w = lfn[di - 1];
if (w != ' ' && w != '.') break;
di--;
}
if (!di) return FR_INVALID_NAME; /* Reject null string */
lfn[di] = 0; /* LFN is created */
/* Create SFN in directory form */
mem_set(dj->fn, ' ', 11);
for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
if (si) cf |= NS_LOSS | NS_LFN;
while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
b = i = 0; ni = 8;
for (;;) {
w = lfn[si++]; /* Get an LFN char */
if (!w) break; /* Break on enf of the LFN */
if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
cf |= NS_LOSS | NS_LFN; continue;
}
if (i >= ni || si == di) { /* Extension or end of SFN */
if (ni == 11) { /* Long extension */
cf |= NS_LOSS | NS_LFN; break;
}
if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
if (si > di) break; /* No extension */
si = di; i = 8; ni = 11; /* Enter extension section */
b <<= 2; continue;
}
if (w >= 0x80) { /* Non ASCII char */
#ifdef _EXCVT
w = ff_convert(w, 0); /* Unicode -> OEM code */
if (w) w = cvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
#else
w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
#endif
cf |= NS_LFN; /* Force create LFN entry */
}
if (_DF1S && w >= 0x100) { /* Double byte char */
if (i >= ni - 1) {
cf |= NS_LOSS | NS_LFN; i = ni; continue;
}
dj->fn[i++] = (BYTE)(w >> 8);
} else { /* Single byte char */
if (!w || chk_chr("+,;[=]", w)) { /* Replace illegal chars for SFN */
w = '_'; cf |= NS_LOSS | NS_LFN; /* Lossy conversion */
} else {
if (IsUpper(w)) { /* ASCII large capital */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -