#include "includes.h"
-static bool scan_directory(connection_struct *conn, const char *path,
- char *name, char **found_name);
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
connection_struct *conn,
const char *orig_path,
char *stream = NULL;
bool component_was_mangled = False;
bool name_has_wildcard = False;
+ bool posix_pathnames = false;
NTSTATUS result;
+ int ret = -1;
SET_STAT_INVALID(*pst);
*pp_conv_path = NULL;
return result;
}
+ if (!(name = talloc_strdup(ctx, orig_path))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Large directory fix normalization. If we're case sensitive, and
+ * the case preserving parameters are set to "no", normalize the case of
+ * the incoming filename from the client WHETHER IT EXISTS OR NOT !
+ * This is in conflict with the current (3.0.20) man page, but is
+ * what people expect from the "large directory howto". I'll update
+ * the man page. Thanks to jht@samba.org for finding this. JRA.
+ */
+
+ if (conn->case_sensitive && !conn->case_preserve &&
+ !conn->short_case_preserve) {
+ strnorm(name, lp_defaultcase(SNUM(conn)));
+ }
+
/*
* Ensure saved_last_component is valid even if file exists.
*/
if(pp_saved_last_component) {
- end = strrchr_m(orig_path, '/');
+ end = strrchr_m(name, '/');
if (end) {
*pp_saved_last_component = talloc_strdup(ctx, end + 1);
} else {
*pp_saved_last_component = talloc_strdup(ctx,
- orig_path);
+ name);
}
}
- if (!(name = talloc_strdup(ctx, orig_path))) {
- DEBUG(0, ("talloc_strdup failed\n"));
- return NT_STATUS_NO_MEMORY;
- }
+ posix_pathnames = lp_posix_pathnames();
- if (!lp_posix_pathnames()) {
+ if (!posix_pathnames) {
stream = strchr_m(name, ':');
if (stream != NULL) {
}
}
- /*
- * Large directory fix normalization. If we're case sensitive, and
- * the case preserving parameters are set to "no", normalize the case of
- * the incoming filename from the client WHETHER IT EXISTS OR NOT !
- * This is in conflict with the current (3.0.20) man page, but is
- * what people expect from the "large directory howto". I'll update
- * the man page. Thanks to jht@samba.org for finding this. JRA.
- */
-
- if (conn->case_sensitive && !conn->case_preserve &&
- !conn->short_case_preserve) {
- strnorm(name, lp_defaultcase(SNUM(conn)));
- }
-
start = name;
/* If we're providing case insentive semantics or
return NT_STATUS_NO_MEMORY;
}
- /*
- * stat the name - if it exists then we are all done!
- */
+ name_has_wildcard = ms_has_wild(name);
- if (SMB_VFS_STAT(conn,name,&st) == 0) {
- /* Ensure we catch all names with in "/."
- this is disallowed under Windows. */
- const char *p = strstr(name, "/."); /* mb safe. */
- if (p) {
- if (p[2] == '/') {
- /* Error code within a pathname. */
- result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
- goto fail;
- } else if (p[2] == '\0') {
- /* Error code at the end of a pathname. */
- result = NT_STATUS_OBJECT_NAME_INVALID;
- goto fail;
+ /* Wildcard not valid anywhere. */
+ if (name_has_wildcard && !allow_wcard_last_component) {
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
+ }
+
+ if (!name_has_wildcard) {
+ /*
+ * stat the name - if it exists then we are all done!
+ */
+
+ if (posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn,name,&st);
+ } else {
+ ret = SMB_VFS_STAT(conn,name,&st);
+ }
+
+ if (ret == 0) {
+ /* Ensure we catch all names with in "/."
+ this is disallowed under Windows. */
+ const char *p = strstr(name, "/."); /* mb safe. */
+ if (p) {
+ if (p[2] == '/') {
+ /* Error code within a pathname. */
+ result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ goto fail;
+ } else if (p[2] == '\0') {
+ /* Error code at the end of a pathname. */
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
+ }
}
+ stat_cache_add(orig_path, name, conn->case_sensitive);
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ *pst = st;
+ goto done;
}
- stat_cache_add(orig_path, name, conn->case_sensitive);
- DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
- *pst = st;
- goto done;
}
DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
name_has_wildcard = ms_has_wild(start);
- /* Wildcard not valid anywhere. */
- if (name_has_wildcard && !allow_wcard_last_component) {
- result = NT_STATUS_OBJECT_NAME_INVALID;
- goto fail;
- }
-
/* Wildcards never valid within a pathname. */
if (name_has_wildcard && end) {
result = NT_STATUS_OBJECT_NAME_INVALID;
* Check if the name exists up to this point.
*/
- if (SMB_VFS_STAT(conn,name, &st) == 0) {
+ if (posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn,name, &st);
+ } else {
+ ret = SMB_VFS_STAT(conn,name, &st);
+ }
+
+ if (ret == 0) {
/*
* It exists. it must either be a directory or this must
* be the last part of the path for it to be OK.
*/
- if (end && !(st.st_mode & S_IFDIR)) {
+ if (end && !S_ISDIR(st.st_ex_mode)) {
/*
* An intermediate part of the name isn't
* a directory.
*/
if (name_has_wildcard ||
- !scan_directory(conn, dirpath,
- start, &found_name)) {
+ (get_real_filename(conn, dirpath, start,
+ talloc_tos(),
+ &found_name) == -1)) {
char *unmangled;
if (end) {
goto fail;
}
- /* ENOENT is the only valid error here. */
- if ((errno != 0) && (errno != ENOENT)) {
+ /*
+ * ENOENT/EACCESS are the only valid errors
+ * here. EACCESS needs handling here for
+ * "dropboxes", i.e. directories where users
+ * can only put stuff with permission -wx.
+ */
+ if ((errno != 0) && (errno != ENOENT)
+ && (errno != EACCES)) {
/*
* ENOTDIR and ELOOP both map to
* NT_STATUS_OBJECT_PATH_NOT_FOUND
errno == ELOOP) {
result =
NT_STATUS_OBJECT_PATH_NOT_FOUND;
- }
- else {
+ } else {
result =
map_nt_error_from_unix(errno);
}
* if it exists. JRA.
*/
- if (SMB_VFS_STAT(conn,name, &st) == 0) {
+ if (posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn,name, &st);
+ } else {
+ ret = SMB_VFS_STAT(conn,name, &st);
+ }
+
+ if (ret == 0) {
*pst = st;
} else {
SET_STAT_INVALID(st);
If the name looks like a mangled name then try via the mangling functions
****************************************************************************/
-static bool scan_directory(connection_struct *conn, const char *path,
- char *name, char **found_name)
+static int get_real_filename_full_scan(connection_struct *conn,
+ const char *path, const char *name,
+ bool mangled,
+ TALLOC_CTX *mem_ctx, char **found_name)
{
struct smb_Dir *cur_dir;
const char *dname;
- bool mangled;
char *unmangled_name = NULL;
long curpos;
- TALLOC_CTX *ctx = talloc_tos();
-
- mangled = mangle_is_mangled(name, conn->params);
/* handle null paths */
if ((path == NULL) || (*path == 0)) {
*/
if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
errno = ENOENT;
- return False;
+ return -1;
}
/*
*/
if (mangled && !conn->case_sensitive) {
- mangled = !mangle_lookup_name_from_8_3(ctx,
- name,
- &unmangled_name,
- conn->params);
+ mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
+ &unmangled_name,
+ conn->params);
if (!mangled) {
/* Name is now unmangled. */
name = unmangled_name;
if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
DEBUG(3,("scan dir didn't open dir [%s]\n",path));
TALLOC_FREE(unmangled_name);
- return(False);
+ return -1;
}
/* now scan for matching names */
curpos = 0;
- while ((dname = ReadDirName(cur_dir, &curpos))) {
+ while ((dname = ReadDirName(cur_dir, &curpos, NULL))) {
/* Is it dot or dot dot. */
if (ISDOT(dname) || ISDOTDOT(dname)) {
if ((mangled && mangled_equal(name,dname,conn->params)) ||
fname_equal(name, dname, conn->case_sensitive)) {
/* we've found the file, change it's name and return */
- *found_name = talloc_strdup(ctx,dname);
+ *found_name = talloc_strdup(mem_ctx, dname);
TALLOC_FREE(unmangled_name);
TALLOC_FREE(cur_dir);
if (!*found_name) {
errno = ENOMEM;
- return False;
+ return -1;
}
- return(True);
+ return 0;
}
}
TALLOC_FREE(unmangled_name);
TALLOC_FREE(cur_dir);
errno = ENOENT;
- return False;
+ 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;
+ bool mangled;
+
+ mangled = mangle_is_mangled(name, conn->params);
+
+ if (mangled) {
+ return get_real_filename_full_scan(conn, path, name, mangled,
+ mem_ctx, found_name);
+ }
+
+ /* 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;
+ }
+
+ return get_real_filename_full_scan(conn, path, name, mangled, mem_ctx,
+ found_name);
}
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,