return NT_STATUS_NO_MEMORY;
}
+ name_has_wildcard = ms_has_wild(name);
+
+ /* Wildcard not valid anywhere. */
+ if (name_has_wildcard && !allow_wcard_last_component) {
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
+ }
+
/*
* stat the name - if it exists then we are all done!
*/
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;
* 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 ||
- (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) {
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 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,
+ 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;
- mangled = mangle_is_mangled(name, conn->params);
-
/* handle null paths */
if ((path == NULL) || (*path == 0)) {
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;
+ 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,
connection_struct *conn,
const char *orig_path,