[PATCH] [SAMBA3] Improve handling of lookups in unsearchable directories.

James Peach jpeach at apple.com
Tue Feb 5 17:44:19 GMT 2008


This change allows us to hold open a directory iterator that is not
backed by a real open directory handle as long as we are not intending
to iterate or search for a wildcard. This means that clients using
FindFirst to lookup filenames do not require search privileges
unless we end up needing to do a case-matching search.

---
  source/smbd/dir.c |   62 ++++++++++++++++++++++++++++++++++++++++++++ 
++------
  1 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index ca6f8bf..885e9f5 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -170,10 +170,8 @@ static void dptr_idleoldest(void)
  	 */

  	for(; dptr; dptr = dptr->prev) {
-		if (dptr->dir_hnd) {
-			dptr_idle(dptr);
-			return;
-		}
+		dptr_idle(dptr);
+		return;
  	}
  }

@@ -328,8 +326,9 @@ void dptr_idlecnum(connection_struct *conn)
  {
  	struct dptr_struct *dptr;
  	for(dptr = dirptrs; dptr; dptr = dptr->next) {
-		if (dptr->conn == conn && dptr->dir_hnd)
+		if (dptr->conn == conn) {
  			dptr_idle(dptr);
+		}
  	}
  }

@@ -342,8 +341,9 @@ void dptr_closepath(char *path,uint16 spid)
  	struct dptr_struct *dptr, *next;
  	for(dptr = dirptrs; dptr; dptr = next) {
  		next = dptr->next;
-		if (spid == dptr->spid && strequal(dptr->path,path))
+		if (spid == dptr->spid && strequal(dptr->path,path)) {
  			dptr_close_internal(dptr);
+		}
  	}
  }

@@ -659,6 +659,22 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx,
  			return NULL;
  		}
  	}
+
+	/* We can get here if we were searching for a filename (not a  
wildcard)
+	 * but we weren't able to open the containing directory. We have no
+	 * hope of iterating, so we can only return NULL here.
+	 */
+	if (dptr->dir_hnd->dir == NULL) {
+		/* XXX What we should be doing here is saving the errno from
+		 * when we originally failed to open the directory. We need to
+		 * return an NT_STATUS at this point so we can faithfully tell
+		 * the client that we couldn't search for the file (distinct
+		 * from the file not being found).
+		 */
+		dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+		return NULL;
+	}
+
  	return dptr_normal_ReadDirName(dptr, poffset, pst);
  }

@@ -1148,8 +1164,27 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx,  
connection_struct *conn,

  	dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
  	if (!dirp->dir) {
-		DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
-			 strerror(errno) ));
+		/* Unless we will be doing a wildcard search, iterating over
+		 * the whole directory, or the path isn't a directory,
+		 * we can try to muddle on without a directory handle.
+		 *
+		 * Note that we might still have to do a case-matching search
+		 * if the filesystem is case sensitive and the client hasn't
+		 * asked for the correct case. This will fail.
+		 */
+		if (errno == ENOENT || errno == ENOTDIR ||
+		    mask == NULL || ms_has_wild(mask)) {
+		        DEBUG(5, ("OpenDir: can't open directory '%s': %s\n",
+		                dirp->dir_path, strerror(errno) ));
+		        goto fail;
+		}
+
+		/* We now have a directory handle that is not backed by an open
+		 * directory. The only valid operation is to close or to read
+		 * the (non-wildcard) name.
+		 */
+		DEBUG(5, ("OpenDir: can't open directory '%s': %s, "
+			"continuing\n", dirp->dir_path, strerror(errno) ));
  		goto fail;
  	}

@@ -1170,6 +1205,8 @@ const char *ReadDirName(struct smb_Dir *dirp,  
long *poffset)
  	const char *n;
  	connection_struct *conn = dirp->conn;

+	SMB_ASSERT(dirp->dir != NULL);
+
  	/* Cheat to allow . and .. to be the first entries returned. */
  	if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset ==  
DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
  		if (dirp->file_number == 0) {
@@ -1210,7 +1247,10 @@ const char *ReadDirName(struct smb_Dir *dirp,  
long *poffset)

  void RewindDir(struct smb_Dir *dirp, long *poffset)
  {
+	SMB_ASSERT(dirp->dir != NULL);
+
  	SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
+
  	dirp->file_number = 0;
  	dirp->offset = START_OF_DIRECTORY_OFFSET;
  	*poffset = START_OF_DIRECTORY_OFFSET;
@@ -1222,6 +1262,7 @@ void RewindDir(struct smb_Dir *dirp, long  
*poffset)

  void SeekDir(struct smb_Dir *dirp, long offset)
  {
+	SMB_ASSERT(dirp->dir != NULL);
  	if (offset != dirp->offset) {
  		if (offset == START_OF_DIRECTORY_OFFSET) {
  			RewindDir(dirp, &offset);
@@ -1298,6 +1339,11 @@ bool SearchDir(struct smb_Dir *dirp, const char  
*name, long *poffset)
  	const char *entry;
  	connection_struct *conn = dirp->conn;

+	/* Search is only valid for wildcards and we must have an open
+	 * directory for those.
+	 */
+	SMB_ASSERT(dirp->dir != NULL);
+
  	/* Search back in the name cache. */
  	if (dirp->name_cache_size && dirp->name_cache) {
  		for (i = dirp->name_cache_index; i >= 0; i--) {
-- 
1.5.3.4




More information about the samba-technical mailing list