Add long file name parsing logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3781 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
95e415d274
commit
fb32eed2ee
@ -12,7 +12,7 @@
|
||||
<h1><big><font color="#3c34ec">
|
||||
<i>NuttX RTOS Porting Guide</i>
|
||||
</font></big></h1>
|
||||
<p>Last Updated: July 12, 2011</p>
|
||||
<p>Last Updated: July 13, 2011</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -3763,6 +3763,19 @@ build
|
||||
<li>
|
||||
<code>CONFIG_FAT_SECTORSIZE</code>: Max supported sector size.
|
||||
</li>
|
||||
<li>
|
||||
<code>CONFIG_FAT_LCNAME</code>: Enable use of the NT-style upper/lower case 8.3 file name support.
|
||||
</li>
|
||||
<li>
|
||||
<code>CONFIG_FAT_LFN</code>: Enable FAT long file names.
|
||||
NOTE: Microsoft claims patents on FAT long file name technology.
|
||||
Please read the disclaimer in the top-level COPYING file and only enable this feature if you understand these issues.
|
||||
</li>
|
||||
<li>
|
||||
<code>CONFIG_FAT_MAXFNAME</code>: If <code>CONFIG_FAT_LFN</code> is defined, then the default, maximum long file name is 255 bytes.
|
||||
This can eat up a lot of memory (especially stack space).
|
||||
If you are willing to live with some non-standard, short long file names, then define this value.
|
||||
</li>
|
||||
<li>
|
||||
<code>CONFIG_FS_NXFFS</code>: Enable NuttX FLASH file system (NXFF) support.
|
||||
</li>
|
||||
|
@ -564,6 +564,17 @@ defconfig -- This is a configuration file similar to the Linux
|
||||
Filesystem configuration
|
||||
CONFIG_FS_FAT - Enable FAT filesystem support
|
||||
CONFIG_FAT_SECTORSIZE - Max supported sector size
|
||||
CONFIG_FAT_LCNAME - Enable use of the NT-style upper/lower case 8.3
|
||||
file name support.
|
||||
CONFIG_FAT_LFN - Enable FAT long file names. NOTE: Microsoft claims
|
||||
patents on FAT long file name technology. Please read the
|
||||
disclaimer in the top-level COPYING file and only enable this
|
||||
feature if you understand these issues.
|
||||
CONFIG_FAT_MAXFNAME - If CONFIG_FAT_LFN is defined, then the
|
||||
default, maximum long file name is 255 bytes. This can eat up
|
||||
a lot of memory (especially stack space). If you are willing
|
||||
to live with some non-standard, short long file names, then
|
||||
define this value.
|
||||
CONFIG_FS_NXFFS: Enable NuttX FLASH file system (NXFF) support.
|
||||
CONFIG_NXFFS_ERASEDSTATE: The erased state of FLASH.
|
||||
This must have one of the values of 0xff or 0x00.
|
||||
|
@ -732,9 +732,9 @@ struct fat_dirinfo_s
|
||||
/* The file/directory name */
|
||||
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
uint8_t fd_lfname[LDIR_MAXFNAME]; /* Long filename */
|
||||
uint8_t fd_lfname[LDIR_MAXFNAME+1]; /* Long filename with terminator */
|
||||
#endif
|
||||
uint8_t fd_name[DIR_MAXFNAME]; /* Short 8.3 alias filename */
|
||||
uint8_t fd_name[DIR_MAXFNAME]; /* Short 8.3 alias filename (no terminator) */
|
||||
|
||||
/* NT flags are not used */
|
||||
|
||||
|
@ -94,6 +94,13 @@
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
enum fat_case_e
|
||||
{
|
||||
FATCASE_UNKNOWN = 0,
|
||||
FATCASE_UPPER,
|
||||
FATCASE_LOWER
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
@ -111,19 +118,21 @@
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_path2dirname
|
||||
* Name: fat_parsesfname
|
||||
*
|
||||
* Desciption: Convert a user filename into a properly formatted FAT
|
||||
* (short) filname as it would appear in a directory entry. Here are the
|
||||
* rules for the 11 byte name in the directory:
|
||||
* (short 8.3) filename as it would appear in a directory entry. Here are
|
||||
* the rules for the 8+3 short file name in the directory:
|
||||
*
|
||||
* The first byte:
|
||||
* - 0xe5 = The directory is free
|
||||
* - 0x00 = This directory and all following directories are free
|
||||
* - 0x05 = Really 0xe5
|
||||
* - 0x20 = May NOT be ' '
|
||||
*
|
||||
* Any bytes
|
||||
* 0xe5 = The directory is free
|
||||
* 0x00 = This directory and all following directories are free
|
||||
* 0x05 = Really 0xe5
|
||||
* 0x20 = May NOT be ' '
|
||||
*
|
||||
* Other characters may be any characters except for the following:
|
||||
*
|
||||
* 0x00-0x1f = (except for 0x00 and 0x05 in the first byte)
|
||||
* 0x22 = '"'
|
||||
* 0x2a-0x2c = '*', '+', ','
|
||||
@ -132,152 +141,627 @@
|
||||
* 0x5b-0x5d = '[', '\\', ;]'
|
||||
* 0x7c = '|'
|
||||
*
|
||||
* Upper case characters are not allowed in directory names (without some
|
||||
* poorly documented operatgions on the NTRes directory byte). Lower case
|
||||
* '.' May only occur once within string and only within the first 9
|
||||
* bytes. The '.' is not save in the directory, but is implicit in
|
||||
* 8+3 format.
|
||||
*
|
||||
* Lower case characters are not allowed in directory names (without some
|
||||
* poorly documented operations on the NTRes directory byte). Lower case
|
||||
* codes may represent different characters in other character sets ("DOS
|
||||
* code pages". The logic below does not, at present, support any other
|
||||
* character sets.
|
||||
*
|
||||
* Returned value:
|
||||
* OK - The path refers to a valid 8.3 FAT file name and has been properly
|
||||
* converted and stored in dirinfo.
|
||||
* <0 - Otherwise an negated error is returned meaning that the string is
|
||||
* not a valid 8+3 because:
|
||||
*
|
||||
* 1. Contains characters not in the printable character set,
|
||||
* 2. Contains forbidden characters or multiple '.' characters
|
||||
* 3. File name or extension is too long.
|
||||
*
|
||||
* If CONFIG_FAT_LFN is defined and CONFIG_FAT_LCNAMES is NOT
|
||||
* defined, then:
|
||||
*
|
||||
* 4a. File name or extension contains lower case characters.
|
||||
*
|
||||
* If CONFIG_FAT_LFN is defined and CONFIG_FAT_LCNAMES is defined,
|
||||
* then:
|
||||
*
|
||||
* 4b. File name or extension is not all the same case.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int fat_path2dirname(const char **path, struct fat_dirinfo_s *dirinfo,
|
||||
static inline int fat_parsesfname(const char **path,
|
||||
struct fat_dirinfo_s *dirinfo,
|
||||
char *terminator)
|
||||
{
|
||||
#ifdef CONFIG_FAT_LCNAMES
|
||||
unsigned int ntlcenable = FATNTRES_LCNAME | FATNTRES_LCEXT;
|
||||
unsigned int ntlcfound = 0;
|
||||
unsigned int ntlcenable = FATNTRES_LCNAME | FATNTRES_LCEXT;
|
||||
unsigned int ntlcfound = 0;
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
enum fat_case_e namecase = FATCASE_UNKNOWN;
|
||||
enum fat_case_e extcase = FATCASE_UNKNOWN;
|
||||
#endif
|
||||
const char *node = *path;
|
||||
int endndx;
|
||||
uint8_t ch;
|
||||
int ndx = 0;
|
||||
#endif
|
||||
const char *node = *path;
|
||||
int endndx;
|
||||
uint8_t ch;
|
||||
int ndx = 0;
|
||||
|
||||
/* Initialized the name with all spaces */
|
||||
/* Initialized the name with all spaces */
|
||||
|
||||
memset(dirinfo->fd_name, ' ', DIR_MAXFNAME);
|
||||
memset(dirinfo->fd_name, ' ', DIR_MAXFNAME);
|
||||
|
||||
/* Loop until the name is successfully parsed or an error occurs */
|
||||
/* Loop until the name is successfully parsed or an error occurs */
|
||||
|
||||
endndx = 8;
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next byte from the path */
|
||||
endndx = 8;
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next byte from the path */
|
||||
|
||||
ch = *node++;
|
||||
ch = *node++;
|
||||
|
||||
/* Check if this the last byte in this node of the name */
|
||||
/* Check if this the last byte in this node of the name */
|
||||
|
||||
if ((ch == '\0' || ch == '/') && ndx != 0 )
|
||||
{
|
||||
/* Return the accumulated NT flags and the terminating character */
|
||||
|
||||
if ((ch == '\0' || ch == '/') && ndx != 0 )
|
||||
{
|
||||
/* Return the accumulated NT flags and the terminating character */
|
||||
#ifdef CONFIG_FAT_LCNAMES
|
||||
dirinfo->fd_ntflags = ntlcfound & ntlcenable;
|
||||
dirinfo->fd_ntflags = ntlcfound & ntlcenable;
|
||||
#endif
|
||||
*terminator = ch;
|
||||
*path = node;
|
||||
return OK;
|
||||
}
|
||||
*terminator = ch;
|
||||
*path = node;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Accept only the printable character set. Note the first byte
|
||||
* of the name could be 0x05 meaning that is it 0xe5, but this is
|
||||
* not a printable character in this character in either case.
|
||||
*/
|
||||
/* Accept only the printable character set. Note the first byte
|
||||
* of the name could be 0x05 meaning that is it 0xe5, but this is
|
||||
* not a printable character in this character in either case.
|
||||
*/
|
||||
|
||||
else if (!isgraph(ch))
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
else if (!isgraph(ch))
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Check for transition from name to extension */
|
||||
/* Check for transition from name to extension. Only one '.' is
|
||||
* permitted and it must be within first 9 characters
|
||||
*/
|
||||
|
||||
else if (ch == '.')
|
||||
{
|
||||
/* Starting the extension */
|
||||
else if (ch == '.' && endndx == 8)
|
||||
{
|
||||
/* Starting the extension */
|
||||
|
||||
ndx = 8;
|
||||
endndx = 11;
|
||||
continue;
|
||||
}
|
||||
ndx = 8;
|
||||
endndx = 11;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reject printable characters forbidden by FAT */
|
||||
/* Reject printable characters forbidden by FAT */
|
||||
|
||||
else if (ch == '"' || (ch >= '*' && ch <= ',') ||
|
||||
ch == '.' || ch == '/' ||
|
||||
(ch >= ':' && ch <= '?') ||
|
||||
(ch >= '[' && ch <= ']') ||
|
||||
(ch == '|'))
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
else if (ch == '"' || (ch >= '*' && ch <= ',') ||
|
||||
ch == '.' || ch == '/' ||
|
||||
(ch >= ':' && ch <= '?') ||
|
||||
(ch >= '[' && ch <= ']') ||
|
||||
(ch == '|'))
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Check for upper case charaters */
|
||||
/* Check for upper case characters */
|
||||
|
||||
#ifdef CONFIG_FAT_LCNAMES
|
||||
else if (isupper(ch))
|
||||
{
|
||||
/* Some or all of the characters in the name or extension
|
||||
* are upper case. Force all of the characters to be interpreted
|
||||
* as upper case.
|
||||
*/
|
||||
else if (isupper(ch))
|
||||
{
|
||||
/* Some or all of the characters in the name or extension
|
||||
* are upper case. Force all of the characters to be interpreted
|
||||
* as upper case.
|
||||
*/
|
||||
|
||||
if ( endndx == 8)
|
||||
if (endndx == 8)
|
||||
{
|
||||
/* Is there mixed case in the name? */
|
||||
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
if (namecase == FATCASE_LOWER)
|
||||
{
|
||||
/* Clear lower case name bit in mask*/
|
||||
ntlcenable &= FATNTRES_LCNAME;
|
||||
/* Mixed case in the name -- use the long file name */
|
||||
|
||||
goto errout;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear lower case extension in mask */
|
||||
ntlcenable &= FATNTRES_LCNAME;
|
||||
}
|
||||
}
|
||||
|
||||
/* So far, only upper case in the name*/
|
||||
|
||||
namecase = FATCASE_UPPER;
|
||||
#endif
|
||||
|
||||
/* Check for lower case characters */
|
||||
/* Clear lower case name bit in mask*/
|
||||
|
||||
else if (islower(ch))
|
||||
{
|
||||
/* Convert the character to upper case */
|
||||
ntlcenable &= FATNTRES_LCNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Is there mixed case in the extension? */
|
||||
|
||||
ch = toupper(ch);
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
if (extcase == FATCASE_LOWER)
|
||||
{
|
||||
/* Mixed case in the extension -- use the long file name */
|
||||
|
||||
/* Some or all of the characters in the name or extension
|
||||
* are lower case. They can be interpreted as lower case if
|
||||
* only if all of the characters in the name or extension are
|
||||
* lower case.
|
||||
*/
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* So far, only upper case in the extension*/
|
||||
|
||||
extcase = FATCASE_UPPER;
|
||||
#endif
|
||||
|
||||
/* Clear lower case extension in mask */
|
||||
|
||||
ntlcenable &= FATNTRES_LCNAME;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for lower case characters */
|
||||
|
||||
else if (islower(ch))
|
||||
{
|
||||
#if defined(CONFIG_FAT_LFN) && !defined(CONFIG_FAT_LCNAMES)
|
||||
/* If lower case characters are present, then a long file
|
||||
* name will be constructed.
|
||||
*/
|
||||
|
||||
goto errout;
|
||||
#else
|
||||
/* Convert the character to upper case */
|
||||
|
||||
ch = toupper(ch);
|
||||
|
||||
/* Some or all of the characters in the name or extension
|
||||
* are lower case. They can be interpreted as lower case if
|
||||
* only if all of the characters in the name or extension are
|
||||
* lower case.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FAT_LCNAMES
|
||||
if ( endndx == 8)
|
||||
{
|
||||
/* Set lower case name bit */
|
||||
ntlcfound |= FATNTRES_LCNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set lower case extension bit */
|
||||
ntlcfound |= FATNTRES_LCNAME;
|
||||
}
|
||||
if (endndx == 8)
|
||||
{
|
||||
/* Is there mixed case in the name? */
|
||||
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
if (namecase == FATCASE_UPPER)
|
||||
{
|
||||
/* Mixed case in the name -- use the long file name */
|
||||
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* So far, only lower case in the name*/
|
||||
|
||||
namecase = FATCASE_LOWER;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if the file name exceeds the size permitted (without
|
||||
* long file name support
|
||||
*/
|
||||
/* Set lower case name bit */
|
||||
|
||||
if (ndx >= endndx)
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
ntlcfound |= FATNTRES_LCNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Is there mixed case in the extension? */
|
||||
|
||||
/* Save next character in the accumulated name */
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
if (extcase == FATCASE_UPPER)
|
||||
{
|
||||
/* Mixed case in the extension -- use the long file name */
|
||||
|
||||
dirinfo->fd_name[ndx++] = ch;
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* So far, only lower case in the extension*/
|
||||
|
||||
extcase = FATCASE_LOWER;
|
||||
#endif
|
||||
|
||||
/* Set lower case extension bit */
|
||||
|
||||
ntlcfound |= FATNTRES_LCNAME;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_FAT_LFN && !CONFIG_FAT_LCNAMES */
|
||||
}
|
||||
|
||||
/* Check if the file name exceeds the size permitted (without
|
||||
* long file name support).
|
||||
*/
|
||||
|
||||
if (ndx >= endndx)
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Save next character in the accumulated name */
|
||||
|
||||
dirinfo->fd_name[ndx++] = ch;
|
||||
}
|
||||
|
||||
errout:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_parselfname
|
||||
*
|
||||
* Desciption: Convert a user filename into a properly formatted FAT
|
||||
* long filename as it would appear in a directory entry. Here are
|
||||
* the rules for the long file name in the directory:
|
||||
*
|
||||
* Valid characters are the same as for short file names EXCEPT:
|
||||
*
|
||||
* 1. '+', ',', ';', '=', '[', and ']' are accepted in the file name
|
||||
* 2. '.' (dot) can occur more than once in a filename. Extension is
|
||||
* the substring after the last dot.
|
||||
*
|
||||
* Returned value:
|
||||
* OK - The path refers to a valid long file name and has been properly
|
||||
* stored in dirinfo.
|
||||
* <0 - Otherwise an negated error is returned meaning that the string is
|
||||
* not a valid long file name:
|
||||
*
|
||||
* 1. Contains characters not in the printable character set,
|
||||
* 2. Contains forbidden characters
|
||||
* 3. File name is too long.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
static inline int fat_parselfname(const char **path,
|
||||
struct fat_dirinfo_s *dirinfo,
|
||||
char *terminator)
|
||||
{
|
||||
const char *node = *path;
|
||||
uint8_t ch;
|
||||
int ndx = 0;
|
||||
|
||||
/* Loop until the name is successfully parsed or an error occurs */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next byte from the path */
|
||||
|
||||
ch = *node++;
|
||||
|
||||
/* Check if this the last byte in this node of the name */
|
||||
|
||||
if ((ch == '\0' || ch == '/') && ndx != 0 )
|
||||
{
|
||||
/* Null terminate the string */
|
||||
|
||||
dirinfo->fd_lfname[ndx] = '\0';
|
||||
|
||||
/* Return the remaining sub-string and the terminating character. */
|
||||
|
||||
*terminator = ch;
|
||||
*path = node;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Accept only the printable character set */
|
||||
|
||||
else if (!isgraph(ch))
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Reject printable characters forbidden by FAT */
|
||||
|
||||
else if (ch == '"' || ch == '*' || ch == '/' || ch == ':' ||
|
||||
ch == '<' || ch == '>' || ch == '?' || ch == '\\' ||
|
||||
ch == '|')
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Check if the file name exceeds the size permitted. */
|
||||
|
||||
if (ndx >= LDIR_MAXFNAME)
|
||||
{
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Save next character in the accumulated name */
|
||||
|
||||
dirinfo->fd_lfname[ndx++] = ch;
|
||||
}
|
||||
|
||||
errout:
|
||||
dirinfo->fd_lfname[0] = '\0';
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_createalias
|
||||
*
|
||||
* Desciption: Given a valid long file name, create a short filename alias.
|
||||
* Here are the rules for creation of the alias:
|
||||
*
|
||||
* 1. All uppercase
|
||||
* 2. All dots except the last deleted
|
||||
* 3. First 6 (uppercase) characters used as a base
|
||||
* 4. Then ~1. The number is increased if the file already exists in the
|
||||
* directory. If the number exeeds >10, then character stripped off the
|
||||
* base.
|
||||
* 5. The extension is the first 3 uppercase chars of extension.
|
||||
*
|
||||
* Returned value:
|
||||
* OK - The alias was created correctly.
|
||||
* <0 - Otherwise an negated error is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
static inline int fat_createalias(const char **path,
|
||||
struct fat_dirinfo_s *dirinfo)
|
||||
{
|
||||
uint8_t ch; /* Current character being processed */
|
||||
char *ext; /* Pointer to the extension substring */
|
||||
char *ptr; /* Working pointer */
|
||||
int len; /* Total length of the long file name */
|
||||
int namechars; /* Number of characters available in long name */
|
||||
int extchars; /* Number of characters available in long name extension */
|
||||
int endndx; /* Maximum index into the short name array */
|
||||
int ndx; /* Index to store next character */
|
||||
|
||||
/* First, let's decide what is name and what is extension */
|
||||
|
||||
len = strlen(dirinfo.fd_lfname);
|
||||
ext = strrchr(dirinfo.fd_lfname, '.');
|
||||
if (ext)
|
||||
{
|
||||
ptrdiff_t tmp;
|
||||
|
||||
/* ext points to the final '.'. The difference in bytes from the
|
||||
* beginning of the string is then the name length.
|
||||
*/
|
||||
|
||||
tmp = ext - dirinfo.fd_lfname;
|
||||
namechars = tmp;
|
||||
|
||||
/* And the rest, exluding the '.' is the extension. */
|
||||
|
||||
extchars = len - namechars - 1;
|
||||
ext++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No '.' found. It is all name and no extension. */
|
||||
|
||||
namechars = len;
|
||||
extchars = 0;
|
||||
}
|
||||
|
||||
/* Alias are always all upper case */
|
||||
|
||||
#ifdef CONFIG_FAT_LCNAMES
|
||||
dirinfo->fd_ntflags = 0;
|
||||
#endif
|
||||
|
||||
/* Initialized the short name with all spaces */
|
||||
|
||||
memset(dirinfo->fd_name, ' ', DIR_MAXFNAME);
|
||||
|
||||
/* Handle a special case where there is no name. Windows seems to use
|
||||
* the extension plus random stuff then ~1 to pat to 8 bytes. Some
|
||||
* examples:
|
||||
*
|
||||
* a.b -> a.b No long name
|
||||
* a., -> A26BE~1._ Padded name to make unique, _ replaces ,
|
||||
* .b -> B1DD2~1 Extension used as name
|
||||
* .bbbbbbb -> BBBBBB~1 Extension used as name
|
||||
* a.bbbbbbb -> AAD39~1.BBB Padded name to make unique.
|
||||
* aaa.bbbbbbb -> AAA~1.BBBB Not padded, already unique?
|
||||
* ,.bbbbbbb -> _82AF~1.BBB _ replaces ,
|
||||
* +[],.bbbbbbb -> ____~1.BBB _ replaces +[],
|
||||
*/
|
||||
|
||||
if (namechars < 1)
|
||||
{
|
||||
/* Use the extension as the name */
|
||||
|
||||
DEBUGASSERT(ext && extchars > 0);
|
||||
ptr = ext;
|
||||
ext = NULL;
|
||||
namechar = extchars;
|
||||
extchars = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = dirinfo.fd_ldname;
|
||||
}
|
||||
|
||||
/* Then copy the name and extension, handling upper case conversions and
|
||||
* excluding forbidden characters.
|
||||
*/
|
||||
|
||||
ndx = 0; /* Position to write the next name character */
|
||||
endndx = 6; /* Maximum index before we write ~! and switch to the extension */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next byte from the path. Break out of the loop if we
|
||||
* encounter the end of null-terminated the long file name string.
|
||||
*/
|
||||
|
||||
ch = *ptr++;
|
||||
if (ch == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Exclude those few characters included in long file names, but
|
||||
* excluded in short file name: '+', ',', ';', '=', '[', ']', and '.'
|
||||
*/
|
||||
|
||||
if (ch == '+' || ch == ',' || ch == '.' || ch == ';' ||
|
||||
ch == '=' || ch == '[' || ch == ']' || ch == '|')
|
||||
{
|
||||
/* Use the underbar character instead */
|
||||
|
||||
ch = '_';
|
||||
}
|
||||
|
||||
/* Handle lower case characters */
|
||||
|
||||
ch = toupper(ch);
|
||||
|
||||
/* We now have a valid character to add to the name or extension. */
|
||||
|
||||
dirinfo->fd_name[ndx++] = ch;
|
||||
|
||||
/* Did we just add a character to the name? */
|
||||
|
||||
if (endndx == 6)
|
||||
{
|
||||
/* Decrement the number of characters available in the name
|
||||
* portion of the long name.
|
||||
*/
|
||||
|
||||
namechars--;
|
||||
|
||||
/* Is it time to add ~1 to the string? Will will do that if
|
||||
* either (1) we have already added the maximum number of
|
||||
* characters to the short name, or (2) if there are no further
|
||||
* characters available in the name portion of the long name.
|
||||
*/
|
||||
|
||||
if (namechars < 1 || ndx == 6)
|
||||
{
|
||||
/* Write the ~1 at the end of the name */
|
||||
|
||||
dirinfo->fd_name[ndx++] = '~';
|
||||
dirinfo->fd_name[ndx++] = '1';
|
||||
|
||||
/* Then switch to the extension (if there is one) */
|
||||
|
||||
if (!ext || extchars < 1)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
ndx = 8;
|
||||
endndx = 11;
|
||||
ptr = ext;
|
||||
}
|
||||
}
|
||||
|
||||
/* No.. we just added a character to the extension */
|
||||
|
||||
else
|
||||
{
|
||||
/* Decrement the number of characters available in the name
|
||||
* portion of the long name
|
||||
*/
|
||||
|
||||
extchars--;
|
||||
|
||||
/* Is the extension complete? */
|
||||
|
||||
if (extchars < 1 || ndx == 11)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_uniquealias
|
||||
*
|
||||
* Desciption: Make sure that the short alias for the long file name is
|
||||
* unique. Modify the alias as necessary to assure uniqueness.
|
||||
*
|
||||
* Returned value:
|
||||
* OK - The alias is unique.
|
||||
* <0 - Otherwise an negated error is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
static inline int fat_uniquealias(const char **path,
|
||||
struct fat_dirinfo_s *dirinfo)
|
||||
{
|
||||
#warning "Missing alias alias uniqueness logic"
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_path2dirname
|
||||
*
|
||||
* Desciption: Convert a user filename into a properly formatted FAT
|
||||
* (short 8.3) filename as it would appear in a directory entry.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int fat_path2dirname(const char **path, struct fat_dirinfo_s *dirinfo,
|
||||
char *terminator)
|
||||
{
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
int ret;
|
||||
|
||||
/* Assume no long file name */
|
||||
|
||||
dirinfo->fd_lfname[0] = '\0';
|
||||
|
||||
/* Then parse the (assumed) 8+3 short file name */
|
||||
|
||||
ret = fat_parsesfname(path, dirinfo, terminator);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* No, the name is not a valid short 8+3 file name. Try parsing
|
||||
* the long file name.
|
||||
*/
|
||||
|
||||
ret = fat_parselfname(path, dirinfo, terminator);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Not a valid long file name */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* It is a valid long file name, create a quick short file name
|
||||
* alias.
|
||||
*/
|
||||
|
||||
ret = fat_createalias(path, dirinfo);
|
||||
DEBUGASSERT(ret == OK); /* This should never fail */
|
||||
|
||||
/* Make sure that the alias is unique */
|
||||
|
||||
ret = fat_uniquealias(path, dirinfo);
|
||||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
/* Only short, 8+3 filenames supported */
|
||||
|
||||
return fat_parsesfname(path, dirinfo, terminator);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_checkname
|
||||
*
|
||||
* Desciption: Given a path to something that may or may not be in the file
|
||||
* system, return the directory entry of the item.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
Loading…
Reference in New Issue
Block a user