📄 fs_fat.c
字号:
/* Check for "." and ".." name */
ch0 = *fn;
ch1 = *(fn + 1);
ch2 = *(fn + 2);
if (ch0 == '.') {
if (ch1 == 0) {
en[0] = '.';
return (__TRUE);
}
else if (ch1 == '.' && ch2 == 0) {
en[0] = '.';
en[1] = '.';
return (__TRUE);
}
}
/* Copy name part (maximum 8 characters) */
for (i = 0; i < 8; ) {
if (!(*fn)) { return (__TRUE); }
if (*fn == '.') { dot = 1; fn++; break; }
if (*fn == ' ') { fn++; continue; }
en[i] = val_char(*fn);
if (en[i] >= 'a' && en[i] <= 'z')
en[i] = en[i] & (~0x20);
i ++;
fn ++;
}
/* Copy extension part (maximum 3 characters) */
for (i = 8; i < 11; ) {
if (!(*fn)) { return (__TRUE); }
if (*fn == '.') { dot = 1; fn++; continue; }
if (*fn == ' ') { fn++; continue; }
if (dot) {
en[i] = val_char(*fn);
if (en[i] >= 'a' && en[i] <= 'z')
en[i] = en[i] & (~0x20);
i ++;
}
fn ++;
}
return (__TRUE);
}
/*--------------------------- check_lfn -------------------------------------*/
static BOOL check_lfn (const char *fn) {
/* Check if "fn" is a long name. */
BOOL dot = 0;
U8 ch, prev_ch = 0;
U32 i = 0, j = 0;
while (*fn) {
if (val_char_sn (*fn) == __FALSE) {
goto lfn;
}
/* If 'space' exists in name then it is a long name. */
if (*fn == ' ') goto lfn;
/* If '.' exists in name more then once or if there are more then 3
valid characters after '.' then it is a long name. */
if (*fn == '.') {
if (dot) goto lfn;
fn ++;
j = 0;
dot = 1;
continue;
}
/* If cases (upper or lower) of letter are different then it is a
long name. */
ch = *fn;
if ((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z')) {
if (i > 0 && ((prev_ch ^ ch) & 0x20)) {
goto lfn;
}
prev_ch = ch;
}
if (dot) {
if (j++ > 2)
goto lfn;
}
i ++;
fn ++;
}
if (i > 12) {
/* This is a long name. */
lfn: return (__TRUE);
}
/* This is a short name. */
return (__FALSE);
}
/*--------------------------- val_char --------------------------------------*/
static U8 val_char (U8 ch) {
/* Validate character 'ch' to be a valid character if not convert it
to 'X'. */
if (val_char_sn (ch) == __FALSE) {
return ('X');
}
return (ch);
}
/*--------------------------- val_char_sn -----------------------------------*/
static BOOL val_char_sn (U8 ch) {
/* Validate character 'ch' to be a valid short name character. */
if ((ch >= ' ' && ch <= '!') ||
(ch >= '#' && ch <= ')') ||
(ch == '-') ||
(ch == '.') ||
(ch >= '0' && ch <= '9') ||
(ch == '@') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '^' && ch <= '{') ||
(ch == '}') ||
(ch == '~') ) {
/* This is a valid short name character. */
return (__TRUE);
}
/* This is not a valid short name character. */
return (__FALSE);
}
/*--------------------------- val_char_ln -----------------------------------*/
#if 0
static BOOL val_char_ln (U8 ch) {
/* Validate character 'ch' to be a valid long name character. */
if (val_char_sn (ch) == __TRUE) {
/* If character is a valid short name character then it is also a valid
long name character. */
return (__TRUE);
}
if (ch == '+' ||
ch == ',' ||
ch == ';' ||
ch == '=' ||
ch == '[' ||
ch == ']' ||
ch > 127) {
/* This is a valid long name character. */
return (__TRUE);
}
/* This is not a valid long name character. */
return (__FALSE);
}
#endif
/*--------------------------- val_char_lab ----------------------------------*/
static U8 val_char_lab (U8 ch) {
/* Validate character 'ch' to be a valid disk label character. */
if ((ch >= '0' && ch <= '9') ||
(ch >= 'A' && ch <= 'Z') ||
(ch == '_') || (ch == ' ')) {
return (ch);
}
if (ch >= 'a' && ch <= 'z') {
/* Convert to uppercase. */
return (ch & ~0x20);
}
/* This is not a valid disk label character. */
return (0);
}
/*--------------------------- get_dir_name ----------------------------------*/
static BOOL get_dir_name (const char *fn, char *dn, unsigned int *sz) {
/* Return first name (dir or file) if "fn" given as path + file name, and
also calculates number of characters until the end of name (sz).
It returns __TRUE if directory name else it returns __FALSE. */
/* Example: *fn = "Some Folder\Test\Some file.txt"
*dn = "Some Folder"
sz = 12 */
U8 ch;
U32 i, j;
for (i = 0, j = 0; ; i++) {
ch = *(fn + i);
if (ch == '\\' || ch == '\"') {
dn[j] = 0;
*sz = i + 1;
return (__TRUE);
}
if (ch == 0) {
dn[j] = 0;
return (__FALSE);
}
dn[j++] = ch;
}
}
/*--------------------------- get_nt_name -----------------------------------*/
static BOOL get_nt_name (const char *fn, char *sn, int num) {
/* Create a short name in "sn" with numeric tail (with value num)
of a long name given in "fn".
It returns __TRUE if successfull else it returns __FALSE. */
/* Example: *fn = "Some file.txt"
*sn = "SOMEFI~3.TXT
num = 3 */
U8 ch, num_sz;
U32 dot_pos = 0xFFFF;
U32 val, i, j;
/* Calculate how many digits requested number has (maximum 6). */
if (num > 99999) num_sz = 6;
else if (num > 9999) num_sz = 5;
else if (num > 999) num_sz = 4;
else if (num > 99) num_sz = 3;
else if (num > 9) num_sz = 2;
else num_sz = 1;
/* Find position of last dot (.) in long name. */
for (i = 0; *(fn + i); i++) {
if (*(fn + i) == '.') dot_pos = i;
}
/* Copy first part of the name. */
for (i = 0, j = 0; (i < dot_pos) && (j < (7 - num_sz)); i++) {
ch = *(fn + i);
if ((ch == ' ') || (ch == '.')) {
continue;
}
else {
sn[j++] = val_char (ch);
}
}
sn[j++] = '~';
switch (num_sz) {
case 6:
val = num / 100000;
num -= val * 100000;
if (val > 9) val = 9;
sn[j++] = '0' + val;
case 5:
val = num / 10000;
num -= val * 10000;
sn[j++] = '0' + val;
case 4:
val = num / 1000;
num -= val * 1000;
sn[j++] = '0' + val;
case 3:
val = num / 100;
num -= val * 100;
sn[j++] = '0' + val;
case 2:
val = num / 10;
num -= val * 10;
sn[j++] = '0' + val;
case 1:
sn[j++] = '0' + num;
break;
}
sn[j++] = '.';
if (dot_pos != 0xFFFF) {
for (i = dot_pos + 1; (i < dot_pos + 4); i++) {
ch = *(fn + i);
if (!ch) {
break;
}
sn[j++] = val_char (ch);
}
}
sn[j] = 0; /* Terminate name string */
return (__TRUE);
}
/*--------------------------- get_dir_sect ---------------------------------*/
static U32 get_dir_sect (U32 clus) {
/* Calculate sector address of the cluster, and update in_root_1x flag. */
U32 sect;
in_root_1x = 0;
if (clus == 0) {
startDirClus = 0;
/* This is a ROOT folder. */
if (mmc.FatType == FS_FAT32) {
/* This is a ROOT folder on FAT32. */
sect = clus_to_sect (mmc.FAT32_RootClus);
}
else {
/* This is a ROOT folder on FAT12 or FAT16. */
sect = mmc.BootRecSec + mmc.RootDirAddr;
in_root_1x = 1;
}
}
else {
/* This is a subfolder. */
sect = clus_to_sect (clus);
}
return (sect);
}
/*--------------------------- search_for_name -------------------------------*/
static BOOL search_for_name (const char *name, IOB *fcb, U8 type, U8 keep_fcb) {
/* Search for entries with requested name and of requested type
(file or dir). */
char sen[13];
FILEREC *frec;
U8 lfn_f = 0;
U8 dir_f = (type == ENT_DIR);
U8 same_f = 1;
U8 type_f = 0;
U8 sfn_name_f = __FALSE;
U8 chksum = 0;
U8 ents = 0;
U8 name_ents = 1;
U32 clus = fcb->_firstClus;
U32 idx;
U32 first_clus = 0;
U32 first_offs = 0;
U32 sect;
U32 i;
startDirClus = fcb->_firstClus;
/* Calculate number of requested entries needed for name. */
if (check_lfn(name) == __TRUE) {
/* Add number of LFN entries. */
name_ents += ((strlen(name) + 12) / 13);
}
/* Convert name to short entry type (8.3) */
sfn_name_f = cvt_fatname (name, sen);
/* Calculate current sector address for folder. */
sect = get_dir_sect (clus);
/* Search through name entries. */
for (idx = 0; ; idx++) {
if (in_root_1x) {
if (idx == 512) {
return (__FALSE);
}
}
else {
/* Check if step to next cluster is needed. */
if (idx == mmc.EntsPerClus) {
idx = 0;
if (clus < mmc.FAT32_RootClus) {
clus = mmc.FAT32_RootClus;
}
set_next_clus (&clus);
if (is_EOC (clus)) {
/* No more entries, end of current directory. */
goto not_found;
}
sect = clus_to_sect (clus);
}
}
read_sector (sect + (idx >> 4));
frec = (FILEREC *)ca.buf + (idx & 0x0F);
if (frec->FileName[0] == 0x00) {
/* There are no allocated entries after this one. */
goto not_found;
}
if (frec->FileName[0] == 0xE5) {
/* Erased file, first character is 0xE5. */
continue;
}
if (frec->Attr == ATTR_VOLUME_ID) {
/* Skip Volume ID entry. */
continue;
}
if ((frec->Attr == ATTR_LONG_NAME) && (LFN_REC(frec)->Ordinal & ORD_LONG_NAME_LAST)) {
/* Long name last entry found. */
lfn_f = 1;
same_f = 1;
if (((LFN_REC(frec)->Ordinal & ~ORD_LONG_NAME_LAST) + 1) != name_ents) {
same_f = 0;
}
first_clus = clus;
first_offs = idx;
ents = 0;
chksum = LFN_REC(frec)->Checksum;
}
/* type_f == 1 if type of entry we are searching for is the same
one we are checking now. */
type_f = !(dir_f ^ ((frec->Attr & ATTR_DIRECTORY) == ATTR_DIRECTORY));
if (lfn_f) {
/* Long name entry found. */
ents ++;
if (frec->Attr != ATTR_LONG_NAME) {
/* If this is long name's accompanying short entry. */
lfn_f = 0;
/* Calculate short name's checksum. */
if ((same_f) && (chksum == lfn_calc_chksum(frec->FileName))) {
if (type_f) {
/* If this is the file or directory we searched for. */
if (keep_fcb) {
goto found_keep_fcb;
}
goto found;
}
}
else {
/* Check also if name is same as only short name (for checking
if short name already exists). */
goto chk_short;
}
}
if (!same_f) {
/* If this is not the entry we are searching for. */
continue;
}
if (chksum != LFN_REC(frec)->Checksum) {
/* If any of long entries does not have the same checksum
as previous ones then this name is invalid. */
same_f = 0;
continue;
}
/* Long name checking in progress. */
i = ((LFN_REC(frec)->Ordinal & 0x1F) - 1) * 13;
/* Compare 13 chars of name with 13 chars of entry name, ignore case. */
same_f = lfn_cmp_name ((U8 *)frec, (S8 *)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -