1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

smbd: Simplify dptr_ReadDirName()

While trying to understand the ReadDirName() at the end of
dptr_ReadDirName() in a code path that was supposed to be just a
"stat"-style readdir with a non-wcard mask I came to the conclusion
that this was there to find dptr->wcard with a mangled
name. get_real_filename_at() already takes care of name mangling, so I
think I could eliminate a source of confusion by using it.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Volker Lendecke 2023-06-13 15:42:19 +02:00 committed by Jeremy Allison
parent d4c669c1cc
commit 91c76f6514

View File

@ -360,11 +360,13 @@ void dptr_RewindDir(struct dptr_struct *dptr)
{ {
long offset; long offset;
RewindDir(dptr->dir_hnd, &offset); RewindDir(dptr->dir_hnd, &offset);
dptr->did_stat = false;
} }
void dptr_SeekDir(struct dptr_struct *dptr, long offset) void dptr_SeekDir(struct dptr_struct *dptr, long offset)
{ {
SeekDir(dptr->dir_hnd, offset); SeekDir(dptr->dir_hnd, offset);
dptr->did_stat = false;
} }
long dptr_TellDir(struct dptr_struct *dptr) long dptr_TellDir(struct dptr_struct *dptr)
@ -411,19 +413,21 @@ static char *dptr_ReadDirName(TALLOC_CTX *ctx,
long *poffset, long *poffset,
SMB_STRUCT_STAT *pst) SMB_STRUCT_STAT *pst)
{ {
struct smb_Dir *dir_hnd = dptr->dir_hnd;
struct files_struct *dir_fsp = dir_hnd->fsp;
struct smb_filename *dir_name = dir_fsp->fsp_name;
struct smb_filename smb_fname_base; struct smb_filename smb_fname_base;
char *name = NULL; bool retry_scanning = false;
const char *name_temp = NULL; int ret;
char *talloced = NULL; int flags = 0;
char *pathreal = NULL;
char *found_name = NULL;
NTSTATUS status;
SET_STAT_INVALID(*pst); SET_STAT_INVALID(*pst);
if (dptr->has_wild || dptr->did_stat) { if (dptr->has_wild) {
name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, const char *name_temp = NULL;
&talloced); char *talloced = NULL;
name_temp = ReadDirName(dir_hnd, poffset, pst, &talloced);
if (name_temp == NULL) { if (name_temp == NULL) {
return NULL; return NULL;
} }
@ -433,93 +437,69 @@ static char *dptr_ReadDirName(TALLOC_CTX *ctx,
return talloc_strdup(ctx, name_temp); return talloc_strdup(ctx, name_temp);
} }
/* If poffset is -1 then we know we returned this name before and we if (dptr->did_stat) {
* have no wildcards. We're at the end of the directory. */ /*
if (*poffset == END_OF_DIRECTORY_OFFSET) { * No wildcard, this is not a real directory traverse
* but a "stat" call behind a query_directory. We've
* been here, nothing else to look at.
*/
return NULL; return NULL;
} }
/* We know the stored wcard contains no wildcard characters.
* See if we can match with a stat call. If we can't, then set
* did_stat to true to ensure we only do this once and keep
* searching. */
dptr->did_stat = true; dptr->did_stat = true;
pathreal = talloc_asprintf(ctx,
"%s/%s",
dptr->dir_hnd->dir_smb_fname->base_name,
dptr->wcard);
if (!pathreal)
return NULL;
/* Create an smb_filename with stream_name == NULL. */ /* Create an smb_filename with stream_name == NULL. */
smb_fname_base = (struct smb_filename) { smb_fname_base = (struct smb_filename){
.base_name = pathreal, .base_name = dptr->wcard,
.flags = dptr->dir_hnd->fsp->fsp_name->flags, .flags = dir_name->flags,
.twrp = dptr->dir_hnd->fsp->fsp_name->twrp, .twrp = dir_name->twrp,
}; };
if (vfs_stat(dptr->conn, &smb_fname_base) == 0) { if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
*pst = smb_fname_base.st; flags |= AT_SYMLINK_NOFOLLOW;
name = talloc_strdup(ctx, dptr->wcard);
goto clean;
} else {
/* If we get any other error than ENOENT or ENOTDIR
then the file exists we just can't stat it. */
if (errno != ENOENT && errno != ENOTDIR) {
name = talloc_strdup(ctx, dptr->wcard);
goto clean;
}
} }
/* Stat failed. We know this is authoritative if we are ret = SMB_VFS_FSTATAT(dptr->conn, dir_fsp, &smb_fname_base, pst, flags);
* providing case sensitive semantics or the underlying if (ret == 0) {
* filesystem is case sensitive. return talloc_strdup(ctx, dptr->wcard);
*/
if (dptr->dir_hnd->case_sensitive ||
!(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
{
goto clean;
} }
/* /*
* Try case-insensitive stat if the fs has the ability. This avoids * If we get any other error than ENOENT or ENOTDIR
* scanning the whole directory. * then the file exists, we just can't stat it.
*/ */
status = SMB_VFS_GET_REAL_FILENAME_AT(dptr->conn, if (errno != ENOENT && errno != ENOTDIR) {
dptr->dir_hnd->fsp, return talloc_strdup(ctx, dptr->wcard);
}
/*
* A scan will find the long version of a mangled name as
* wildcard.
*/
retry_scanning |= mangle_is_mangled(dptr->wcard, dptr->conn->params);
/*
* Also retry scanning if the client requested case
* insensitive semantics and the file system does not provide
* it.
*/
retry_scanning |=
(!dir_hnd->case_sensitive &&
(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH));
if (retry_scanning) {
char *found_name = NULL;
NTSTATUS status;
status = get_real_filename_at(dir_fsp,
dptr->wcard, dptr->wcard,
ctx, ctx,
&found_name); &found_name);
if (NT_STATUS_IS_OK(status)) { if (NT_STATUS_IS_OK(status)) {
name = found_name; return found_name;
goto clean; }
}
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
/* The case-insensitive lookup was authoritative. */
goto clean;
} }
TALLOC_FREE(pathreal); return NULL;
name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced);
if (name_temp == NULL) {
return NULL;
}
if (talloced != NULL) {
return talloc_move(ctx, &talloced);
}
return talloc_strdup(ctx, name_temp);
clean:
TALLOC_FREE(pathreal);
ret:
/* 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;
return name;
} }
/**************************************************************************** /****************************************************************************