mirror of
https://github.com/apache/nuttx.git
synced 2026-05-28 11:56:10 +08:00
s/dirent: Corrects a problem with opendir() noted by Petteri Aimonen in Bitbucket Issue 132: "opendir() fails for FAT filesystem with trailing slash in path":
I see the following behaviour on NuttX 7.26, where I have SD card mounted on /flash and a directory called "frm" on it:
opendir("/flash") returns (DIR *) 0x1000c580
opendir("/flash/") returns (DIR *) 0x1000c5d0
opendir("/flash/frm") returns (DIR *) 0x1000c620
opendir("/flash/frm/") returns (DIR *) 0x0
From POSIX specs for opendir(): "A pathname ... that ends with one or more trailing slashes shall be resolved as if a single dot character ( '.' ) were appended to the pathname."
So for mount points, opendir() works correctly, but for FAT32 filesystem it fails to open directory if the path has a trailing slash. I'm not quite sure how to cleanly fix this. Stripping the trailing slash in opendir() would require allocating a separate buffer, while fixing it in the FAT32 code seems somewhat complex due to the short/long filename logic.
It is not a big issue for me, I'm just going to fix it on the application side. But still a small portability and standards compliance issue.
NOTE: You would not see this problem if you call opendir() indirectly in NSH (like 'ls -R /') because NSH contains logic to remove trailing '/' characters from paths.
This commit is contained in:
+65
-2
@@ -1,7 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* fs/dirent/fs_opendir.c
|
* fs/dirent/fs_opendir.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009, 2011, 2013-2014, 2017 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2011, 2013-2014, 2017-2018 Gregory Nutt. All
|
||||||
|
* rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -230,9 +232,53 @@ FAR DIR *opendir(FAR const char *path)
|
|||||||
#ifndef CONFIG_DISABLE_MOUNTPOINT
|
#ifndef CONFIG_DISABLE_MOUNTPOINT
|
||||||
FAR const char *relpath = NULL;
|
FAR const char *relpath = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
FAR char *alloc = NULL;
|
||||||
bool isroot = false;
|
bool isroot = false;
|
||||||
|
int len;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Strip off any trailing whitespace or '/' characters. In this case we
|
||||||
|
* must make a copy of the user string so we can chop off bytes on the
|
||||||
|
* 'right' without modifying the user's const string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (path != NULL)
|
||||||
|
{
|
||||||
|
/* Length of the string excludes NUL terminator */
|
||||||
|
|
||||||
|
len = strlen(path);
|
||||||
|
|
||||||
|
/* Check for whitespace or a dangling '/' at the end of the string.
|
||||||
|
* But don't muck with the string any further if it has been reduced
|
||||||
|
* to "/"
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (len > 0 && strcmp(path, "/") != 0 &&
|
||||||
|
(isspace(path[len - 1]) || path[len - 1] == '/'))
|
||||||
|
{
|
||||||
|
/* Have we already allocated memory for the modified string? */
|
||||||
|
|
||||||
|
if (alloc == NULL)
|
||||||
|
{
|
||||||
|
alloc = strdup(path); /* Allocates one too many bytes */
|
||||||
|
if (alloc == NULL)
|
||||||
|
{
|
||||||
|
ret = ENOMEM;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the cloned, writable string instead of the user string */
|
||||||
|
|
||||||
|
path = alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chop off the final character */
|
||||||
|
|
||||||
|
len--;
|
||||||
|
alloc[len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we are given 'nothing' then we will interpret this as
|
/* If we are given 'nothing' then we will interpret this as
|
||||||
* request for the root inode.
|
* request for the root inode.
|
||||||
*/
|
*/
|
||||||
@@ -247,7 +293,7 @@ FAR DIR *opendir(FAR const char *path)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We don't know what to do with relative pathes */
|
/* We don't know what to do with relative paths */
|
||||||
|
|
||||||
if (*path != '/')
|
if (*path != '/')
|
||||||
{
|
{
|
||||||
@@ -362,6 +408,14 @@ FAR DIR *opendir(FAR const char *path)
|
|||||||
|
|
||||||
RELEASE_SEARCH(&desc);
|
RELEASE_SEARCH(&desc);
|
||||||
inode_semgive();
|
inode_semgive();
|
||||||
|
|
||||||
|
/* Free any allocated string memory */
|
||||||
|
|
||||||
|
if (alloc != NULL)
|
||||||
|
{
|
||||||
|
kmm_free(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
return ((FAR DIR *)dir);
|
return ((FAR DIR *)dir);
|
||||||
|
|
||||||
/* Nasty goto's make error handling simpler */
|
/* Nasty goto's make error handling simpler */
|
||||||
@@ -372,6 +426,15 @@ errout_with_direntry:
|
|||||||
errout_with_semaphore:
|
errout_with_semaphore:
|
||||||
RELEASE_SEARCH(&desc);
|
RELEASE_SEARCH(&desc);
|
||||||
inode_semgive();
|
inode_semgive();
|
||||||
|
|
||||||
|
/* Free any allocated string memory */
|
||||||
|
|
||||||
|
if (alloc != NULL)
|
||||||
|
{
|
||||||
|
kmm_free(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
errout:
|
||||||
set_errno(ret);
|
set_errno(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1622,8 +1622,7 @@ static int fat_opendir(FAR struct inode *mountpt, FAR const char *relpath,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fat_semgive(fs);
|
ret = OK;
|
||||||
return OK;
|
|
||||||
|
|
||||||
errout_with_semaphore:
|
errout_with_semaphore:
|
||||||
fat_semgive(fs);
|
fat_semgive(fs);
|
||||||
|
|||||||
Reference in New Issue
Block a user