From 596018455af0d80add90215689a80d336157429c Mon Sep 17 00:00:00 2001 From: James Peach Date: Sat, 22 Dec 2007 14:55:37 -0800 Subject: Use filesystem capabilities to support case-insensitive filesystems. If we know the underlying filesystem is case-insensitive, then we know that it won't help to search for case variations of the requested name. Jeremy, please review (and revert if you disagree). (This used to be commit 9e8b8f8c16612d8a08b55802f4fd9afca5498a7c) --- source3/smbd/dir.c | 38 +++++++++++++++++++++----------------- source3/smbd/filename.c | 9 +++++++++ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 05679ee0ee..ccf91fe57d 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -646,10 +646,13 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx, TALLOC_FREE(pathreal); - /* In case sensitive mode we don't search - we know if it doesn't exist - with a stat we will fail. */ + /* Stat failed. We know this is authoratiative if we are + * providing case sensitive semantics or the underlying + * filesystem is case sensitive. + */ - if (dptr->conn->case_sensitive) { + if (dptr->conn->case_sensitive || + !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) { /* We need to set the underlying dir_hnd offset to -1 also as this function is usually called with the output from TellDir. */ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET; @@ -924,12 +927,7 @@ static bool user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S return True; } - /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) { - DEBUG(10,("user_can_read_file: SMB_VFS_STAT failed for file %s with error %s\n", - name, strerror(errno) )); - return False; - } + SMB_ASSERT(VALID_STAT(*pst)); /* Pseudo-open the file (note - no fd's created). */ @@ -987,10 +985,7 @@ static bool user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ return True; } - /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) { - return False; - } + SMB_ASSERT(VALID_STAT(*pst)); /* Pseudo-open the file */ @@ -1039,9 +1034,7 @@ static bool file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT if (conn->admin_user) return False; - /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) - return True; + SMB_ASSERT(VALID_STAT(*pst)); if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode)) return False; @@ -1050,7 +1043,9 @@ static bool file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT } /******************************************************************* - Should the file be seen by the client ? + Should the file be seen by the client ? NOTE: A successful return + is no guarantee of the file's existence ... you also have to check + whether pst is valid. ********************************************************************/ bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto) @@ -1086,6 +1081,15 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, const char * return True; } + /* If the file name does not exist, there's no point checking + * the configuration options. We succeed, on the basis that the + * checks *might* have passed if the file was present. + */ + if (SMB_VFS_STAT(conn, entry, pst) != 0) { + SAFE_FREE(entry); + return True; + } + /* Honour _hide unreadable_ option */ if (hide_unreadable && !user_can_read_file(conn, entry, pst)) { DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry )); diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index dc733d4568..f0d036b82b 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -735,6 +735,15 @@ static bool scan_directory(connection_struct *conn, const char *path, path = "."; } + /* If we have a case-sensitive filesystem, it doesn't do us any + * good to search for a name. If a case variation of the name was + * there, then the original stat(2) would have found it. + */ + if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) { + errno = ENOENT; + return False; + } + /* * The incoming name can be mangled, and if we de-mangle it * here it will not compare correctly against the filename (name2) -- cgit