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:
parent
d4c669c1cc
commit
91c76f6514
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
Loading…
Reference in New Issue
Block a user