diff --git a/fs/fat/fs_fat32dirent.c b/fs/fat/fs_fat32dirent.c index 5c595074831..abb17575bf3 100644 --- a/fs/fat/fs_fat32dirent.c +++ b/fs/fat/fs_fat32dirent.c @@ -369,8 +369,19 @@ static inline int fat_parsesfname(FAR const char **path, node++; } - *terminator = ch; - *path = node; + if (terminator != NULL) + { + /* Don't update the variables if terminator is NULL + * + * Call with terminator == NULL is used to obtain short + * file name from already given long file name that fits + * into 8.3 format + */ + + *terminator = ch; + *path = node; + } + return OK; } @@ -1109,6 +1120,12 @@ static inline int fat_uniquealias(FAR struct fat_mountpt_s *fs, * Description: Convert a user filename into a properly formatted FAT * (short 8.3) filename as it would appear in a directory entry. * + * Long file name is returned if CONFIG_FAT_LFN is defined. This applies + * even for entries that would fit standard short 8.3 format. These have + * both long file name and short file name filled. This is done mainly + * because of compatibility with Linux that creates long file name entries + * even if the file name fits into 8.3 format. + * ****************************************************************************/ static int fat_path2dirname(FAR const char **path, @@ -1121,17 +1138,35 @@ static int fat_path2dirname(FAR const char **path, /* Assume no long file name */ dirinfo->fd_lfname[0] = '\0'; + dirinfo->fd_name[0] = '\0'; - /* Then parse the (assumed) 8+3 short file name */ + /* Parse long file name */ - ret = fat_parsesfname(path, dirinfo, terminator); + ret = fat_parselfname(path, dirinfo, terminator); if (ret < 0) { - /* No, the name is not a valid short 8+3 file name. Try parsing - * the long file name. + return ret; + } + else + { + /* Does the long file name fit into short file name? This means + * this is actually a short file name. + * + * There are following possibilities: + * - file was created on Linux and is written as long file name + * - file was created on Windows and is written as short file name + * - we are creating file on NuttX -> write it as short file name */ - ret = fat_parselfname(path, dirinfo, terminator); + if (strlen((FAR const char *)dirinfo->fd_lfname) <= DIR_MAXFNAME) + { + /* Get short file name for given path */ + + char name[DIR_MAXFNAME]; + memcpy(name, dirinfo->fd_lfname, DIR_MAXFNAME); + FAR const char *tmp = (FAR const char *)name; + fat_parsesfname(&tmp, dirinfo, NULL); + } } return ret; @@ -2609,20 +2644,25 @@ int fat_finddirentry(FAR struct fat_mountpt_s *fs, return ret; } - /* Is this a path segment a long or a short file. Was a long file - * name parsed? - */ - #ifdef CONFIG_FAT_LFN if (dirinfo->fd_lfname[0] != '\0') { - /* Yes.. Search for the sequence of long file name directory - * entries. NOTE: As a side effect, this function returns with - * the sector containing the short file name directory entry - * in the cache. + /* We have to check for both LFN and SFN entry because of + * Linux/Windows differences + * + * - file created on Linux is written as LFN even if it fits 8.3 + * - file created on Windows is written as SFN if it fits 8.3 */ + struct fat_dirinfo_s d = *dirinfo; ret = fat_findlfnentry(fs, dirinfo); + if (ret < 0) + { + /* There is no LFN entry for given file -> check SFN */ + + *dirinfo = d; + ret = fat_findsfnentry(fs, dirinfo); + } } else #endif @@ -2752,7 +2792,7 @@ int fat_allocatedirentry(FAR struct fat_mountpt_s *fs, */ #ifdef CONFIG_FAT_LFN - if (dirinfo->fd_lfname[0] != '\0') + if (dirinfo->fd_lfname[0] != '\0' && dirinfo->fd_name[0] == '\0') { /* Yes.. Allocate for the sequence of long file name directory * entries plus a short file name directory entry. @@ -3008,7 +3048,7 @@ int fat_dirnamewrite(FAR struct fat_mountpt_s *fs, /* Is this a long file name? */ - if (dirinfo->fd_lfname[0] != '\0') + if (dirinfo->fd_lfname[0] != '\0' && dirinfo->fd_name[0] == '\0') { /* Write the sequence of long file name directory entries (this * function also creates the short file name alias). @@ -3054,7 +3094,7 @@ int fat_dirwrite(FAR struct fat_mountpt_s *fs, /* Does this directory entry have a long file name? */ - if (dirinfo->fd_lfname[0] != '\0') + if (dirinfo->fd_lfname[0] != '\0' && dirinfo->fd_name[0] == '\0') { /* Write the sequence of long file name directory entries (this * function also creates the short file name alias).