From 97b0235d77ff4ee7c8eb5288b2a001a1d12bf707 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 16 Nov 2018 11:45:18 -0600 Subject: [PATCH] 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. --- fs/dirent/fs_opendir.c | 67 ++++++++++++++++++++++++++++++++++++++++-- fs/fat/fs_fat32.c | 3 +- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/fs/dirent/fs_opendir.c b/fs/dirent/fs_opendir.c index e8bedefff7a..874b655a2b8 100644 --- a/fs/dirent/fs_opendir.c +++ b/fs/dirent/fs_opendir.c @@ -1,7 +1,8 @@ /**************************************************************************** * 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 * * Redistribution and use in source and binary forms, with or without @@ -41,6 +42,7 @@ #include #include +#include #include #include #include @@ -230,9 +232,53 @@ FAR DIR *opendir(FAR const char *path) #ifndef CONFIG_DISABLE_MOUNTPOINT FAR const char *relpath = NULL; #endif + FAR char *alloc = NULL; bool isroot = false; + int len; 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 * request for the root inode. */ @@ -247,7 +293,7 @@ FAR DIR *opendir(FAR const char *path) } else { - /* We don't know what to do with relative pathes */ + /* We don't know what to do with relative paths */ if (*path != '/') { @@ -362,6 +408,14 @@ FAR DIR *opendir(FAR const char *path) RELEASE_SEARCH(&desc); inode_semgive(); + + /* Free any allocated string memory */ + + if (alloc != NULL) + { + kmm_free(alloc); + } + return ((FAR DIR *)dir); /* Nasty goto's make error handling simpler */ @@ -372,6 +426,15 @@ errout_with_direntry: errout_with_semaphore: RELEASE_SEARCH(&desc); inode_semgive(); + + /* Free any allocated string memory */ + + if (alloc != NULL) + { + kmm_free(alloc); + } + +errout: set_errno(ret); return NULL; } diff --git a/fs/fat/fs_fat32.c b/fs/fat/fs_fat32.c index 1a99b26cce6..566a31d0397 100644 --- a/fs/fat/fs_fat32.c +++ b/fs/fat/fs_fat32.c @@ -1622,8 +1622,7 @@ static int fat_opendir(FAR struct inode *mountpt, FAR const char *relpath, } } - fat_semgive(fs); - return OK; + ret = OK; errout_with_semaphore: fat_semgive(fs);