summaryrefslogtreecommitdiff
path: root/source3/smbd/filename.c
diff options
context:
space:
mode:
authortprouty <tprouty@b72e2a10-2d34-0410-9a71-d3beadf02b57>2009-05-02 00:28:38 +0000
committerTim Prouty <tprouty@samba.org>2009-05-05 16:43:53 -0700
commit69d61453df6019caef4e7960fa78c6a3c51f3d2a (patch)
tree406d028c81bc1bf0f33507c00c5f0da7a83cf984 /source3/smbd/filename.c
parente091fdc5658e65be290ebb3b62a1bdf517781a65 (diff)
downloadsamba-69d61453df6019caef4e7960fa78c6a3c51f3d2a.tar.gz
samba-69d61453df6019caef4e7960fa78c6a3c51f3d2a.tar.bz2
samba-69d61453df6019caef4e7960fa78c6a3c51f3d2a.zip
s3: Fix trans2 path to use case-insensitive stat optimization
Often times before creating a file, a client will first query to see if it already exists. Since some systems have a case-insensitive stat that is called from unix_convert, we can definitively return STATUS_NO_SUCH_FILE to the client without scanning the whole directory. This code path is taken from trans2querypathinfo, but trans2findfirst still does a full directory scan even though the get_real_filename (the case-insensitive stat vfs call) can prevent this. This patch adds the get_real_filename call to the trans2find* path, and also changes the vfs_default behavior for SMB_VFS_GET_REAL_FILENAME. Previously, in the absence of a get_real_filename implementation, we would fallback to the full directory scan. The default behavior now returns -1 and sets errno to EOPNOTSUPP. This allows SMB_VFS_GET_REALFILENAME to be called from trans2* and unix_convert.
Diffstat (limited to 'source3/smbd/filename.c')
-rw-r--r--source3/smbd/filename.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 80722a7cd0..774ab27a74 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -447,9 +447,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
*/
if (name_has_wildcard ||
- (SMB_VFS_GET_REAL_FILENAME(
- conn, dirpath, start,
- talloc_tos(), &found_name) == -1)) {
+ (get_real_filename(conn, dirpath, start,
+ talloc_tos(),
+ &found_name) == -1)) {
char *unmangled;
if (end) {
@@ -789,9 +789,9 @@ static bool fname_equal(const char *name1, const char *name2,
If the name looks like a mangled name then try via the mangling functions
****************************************************************************/
-int get_real_filename(connection_struct *conn, const char *path,
- const char *name, TALLOC_CTX *mem_ctx,
- char **found_name)
+static int get_real_filename_full_scan(connection_struct *conn,
+ const char *path, const char *name,
+ TALLOC_CTX *mem_ctx, char **found_name)
{
struct smb_Dir *cur_dir;
const char *dname;
@@ -887,6 +887,34 @@ int get_real_filename(connection_struct *conn, const char *path,
return -1;
}
+/****************************************************************************
+ Wrapper around the vfs get_real_filename and the full directory scan
+ fallback.
+****************************************************************************/
+
+int get_real_filename(connection_struct *conn, const char *path,
+ const char *name, TALLOC_CTX *mem_ctx,
+ char **found_name)
+{
+ int ret;
+
+ /* Try the vfs first to take advantage of case-insensitive stat. */
+ ret = SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name);
+
+ /*
+ * If the case-insensitive stat was successful, or returned an error
+ * other than EOPNOTSUPP then there is no need to fall back on the
+ * full directory scan.
+ */
+ if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
+ return ret;
+ }
+
+ ret = get_real_filename_full_scan(conn, path, name, mem_ctx,
+ found_name);
+ return ret;
+}
+
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
connection_struct *conn,
const char *orig_path,