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

Pass stat buffer down through all levels of VFS_READDIR wrappers

* VFS_OP_READDIR can now provide stat information, take advantage of it
  if it's available
* is_visible_file(): optimistically expect the provided stat buffer is
  already valid
* dptr_ReadDirName(): refactor code for easier readability, functionality
  is the same
This commit is contained in:
Steven Danneman 2009-01-22 20:18:56 -08:00
parent af0e199b31
commit 25d345eb39
5 changed files with 106 additions and 98 deletions

View File

@ -6512,7 +6512,8 @@ bool get_dir_entry(TALLOC_CTX *ctx,
bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto);
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
const char *name, const char *mask, uint32 attr);
const char *ReadDirName(struct smb_Dir *dirp, long *poffset);
const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
SMB_STRUCT_STAT *sbuf);
void RewindDir(struct smb_Dir *dirp, long *poffset);
void SeekDir(struct smb_Dir *dirp, long offset);
long TellDir(struct smb_Dir *dirp);
@ -7356,7 +7357,7 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len);
int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len);
int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len);
SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n);
char *vfs_readdirname(connection_struct *conn, void *p);
char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf);
int vfs_ChDir(connection_struct *conn, const char *path);
char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn);
NTSTATUS check_reduced_name(connection_struct *conn, const char *fname);

View File

@ -552,11 +552,12 @@ int dptr_dnum(struct dptr_struct *dptr)
Return the next visible file name, skipping veto'd and invisible files.
****************************************************************************/
static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
long *poffset, SMB_STRUCT_STAT *pst)
{
/* Normal search for the next file. */
const char *name;
while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
while ((name = ReadDirName(dptr->dir_hnd, poffset, pst)) != NULL) {
if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
return name;
}
@ -573,85 +574,84 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx,
long *poffset,
SMB_STRUCT_STAT *pst)
{
char *name = NULL;
char *pathreal = NULL;
SET_STAT_INVALID(*pst);
if (dptr->has_wild) {
if (dptr->has_wild || dptr->did_stat) {
return dptr_normal_ReadDirName(dptr, poffset, pst);
}
/* If poffset is -1 then we know we returned this name before and we have
no wildcards. We're at the end of the directory. */
/* If poffset is -1 then we know we returned this name before and we
* have no wildcards. We're at the end of the directory. */
if (*poffset == END_OF_DIRECTORY_OFFSET) {
return NULL;
}
if (!dptr->did_stat) {
char *pathreal = 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. */
/* 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;
/* First check if it should be visible. */
if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
pst, true))
{
/* This only returns false if the file was found, but
is explicitly not visible. Set us to end of
directory, but return NULL as we know we can't ever
find it. */
goto ret;
}
/* First check if it should be visible. */
if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
/* This only returns False if the file was found, but
is explicitly not visible. Set us to end of directory,
but return NULL as we know we can't ever find it. */
dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
return NULL;
}
if (VALID_STAT(*pst)) {
name = dptr->wcard;
goto ret;
}
if (VALID_STAT(*pst)) {
/* 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 dptr->wcard;
}
pathreal = talloc_asprintf(ctx,
"%s/%s",
dptr->path,
dptr->wcard);
if (!pathreal)
return NULL;
pathreal = talloc_asprintf(ctx,
"%s/%s",
dptr->path,
dptr->wcard);
if (!pathreal) {
return NULL;
}
if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
/* 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;
TALLOC_FREE(pathreal);
return dptr->wcard;
} 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) {
/* We need to set the underlying dir_hdn offset to -1 also as
this function is usually called with the output from TellDir. */
dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
TALLOC_FREE(pathreal);
return dptr->wcard;
}
}
TALLOC_FREE(pathreal);
/* Stat failed. We know this is authoratiative if we are
* providing case sensitive semantics or the underlying
* filesystem is case sensitive.
*/
if (dptr->conn->case_sensitive ||
!(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
/* 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 NULL;
if (SMB_VFS_STAT(dptr->conn, pathreal, pst) == 0) {
name = 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 = dptr->wcard;
goto clean;
}
}
/* Stat failed. We know this is authoratiative if we are
* providing case sensitive semantics or the underlying
* filesystem is case sensitive.
*/
if (dptr->conn->case_sensitive ||
!(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
{
goto clean;
}
TALLOC_FREE(pathreal);
return dptr_normal_ReadDirName(dptr, poffset, pst);
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;
}
/****************************************************************************
@ -981,19 +981,17 @@ static bool file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT
}
/*******************************************************************
Should the file be seen by the client ? NOTE: A successful return
is no guarantee of the file's existence ... you also have to check
whether pst is valid.
Should the file be seen by the client?
NOTE: A successful return is no guarantee of the file's existence.
********************************************************************/
bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
bool is_visible_file(connection_struct *conn, const char *dir_path,
const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
{
bool hide_unreadable = lp_hideunreadable(SNUM(conn));
bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
bool hide_special = lp_hide_special_files(SNUM(conn));
SET_STAT_INVALID(*pst);
if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
return True; /* . and .. are always visible. */
}
@ -1023,26 +1021,30 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, const char *
* the configuration options. We succeed, on the basis that the
* checks *might* have passed if the file was present.
*/
if (SMB_VFS_STAT(conn, entry, pst) != 0) {
if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, entry, pst) != 0))
{
SAFE_FREE(entry);
return True;
}
/* Honour _hide unreadable_ option */
if (hide_unreadable && !user_can_read_file(conn, entry)) {
DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry ));
DEBUG(10,("is_visible_file: file %s is unreadable.\n",
entry ));
SAFE_FREE(entry);
return False;
}
/* Honour _hide unwriteable_ option */
if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry ));
DEBUG(10,("is_visible_file: file %s is unwritable.\n",
entry ));
SAFE_FREE(entry);
return False;
}
/* Honour _hide_special_ option */
if (hide_special && file_is_special(conn, entry, pst)) {
DEBUG(10,("is_visible_file: file %s is special.\n", entry ));
DEBUG(10,("is_visible_file: file %s is special.\n",
entry ));
SAFE_FREE(entry);
return False;
}
@ -1100,17 +1102,21 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
}
/*******************************************************************
Read from a directory. Also return current offset.
Read from a directory.
Return directory entry, current offset, and optional stat information.
Don't check for veto or invisible files.
********************************************************************/
const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
SMB_STRUCT_STAT *sbuf)
{
const char *n;
connection_struct *conn = dirp->conn;
/* Cheat to allow . and .. to be the first entries returned. */
if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
(*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
{
if (dirp->file_number == 0) {
n = ".";
*poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
@ -1128,7 +1134,7 @@ const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
SeekDir(dirp, *poffset);
}
while ((n = vfs_readdirname(conn, dirp->dir))) {
while ((n = vfs_readdirname(conn, dirp->dir, sbuf))) {
/* Ignore . and .. - we've already returned them. */
if (*n == '.') {
if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
@ -1261,7 +1267,7 @@ bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
SMB_VFS_REWINDDIR(conn, dirp->dir);
dirp->file_number = 0;
*poffset = START_OF_DIRECTORY_OFFSET;
while ((entry = ReadDirName(dirp, poffset))) {
while ((entry = ReadDirName(dirp, poffset, NULL))) {
if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
return True;
}
@ -1279,6 +1285,7 @@ NTSTATUS can_delete_directory(struct connection_struct *conn,
NTSTATUS status = NT_STATUS_OK;
long dirpos = 0;
const char *dname;
SMB_STRUCT_STAT st;
struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname,
NULL, 0);
@ -1286,9 +1293,7 @@ NTSTATUS can_delete_directory(struct connection_struct *conn,
return map_nt_error_from_unix(errno);
}
while ((dname = ReadDirName(dir_hnd,&dirpos))) {
SMB_STRUCT_STAT st;
while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
/* Quick check for "." and ".." */
if (dname[0] == '.') {
if (!dname[1] || (dname[1] == '.' && !dname[2])) {
@ -1300,7 +1305,8 @@ NTSTATUS can_delete_directory(struct connection_struct *conn,
continue;
}
DEBUG(10,("can_delete_directory: got name %s - can't delete\n", dname ));
DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
dname ));
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
break;
}

View File

@ -849,7 +849,7 @@ int get_real_filename(connection_struct *conn, const char *path,
/* 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)) {

View File

@ -1485,7 +1485,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum)
goto out;
}
while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
if (is_msdfs_link(conn,
dname,
NULL)) {
@ -1585,7 +1585,7 @@ static int form_junctions(TALLOC_CTX *ctx,
goto out;
}
while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
char *link_target = NULL;
if (cnt >= jn_remain) {
DEBUG(2, ("form_junctions: ran out of MSDFS "

View File

@ -2368,7 +2368,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
char *p = NULL;
int count=0;
NTSTATUS status = NT_STATUS_OK;
SMB_STRUCT_STAT sbuf;
SMB_STRUCT_STAT sbuf, st;
TALLOC_CTX *ctx = talloc_tos();
status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf);
@ -2464,11 +2464,12 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
status = NT_STATUS_NO_SUCH_FILE;
while ((dname = ReadDirName(dir_hnd, &offset))) {
SMB_STRUCT_STAT st;
while ((dname = ReadDirName(dir_hnd, &offset, &st))) {
char *fname = NULL;
if (!is_visible_file(conn, directory, dname, &st, True)) {
if (!is_visible_file(conn, directory, dname, &st,
true))
{
continue;
}
@ -5005,15 +5006,15 @@ static bool recursive_rmdir(TALLOC_CTX *ctx,
const char *dname = NULL;
bool ret = True;
long offset = 0;
SMB_STRUCT_STAT st;
struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory,
NULL, 0);
if(dir_hnd == NULL)
return False;
while((dname = ReadDirName(dir_hnd, &offset))) {
while((dname = ReadDirName(dir_hnd, &offset, &st))) {
char *fullname = NULL;
SMB_STRUCT_STAT st;
if (ISDOT(dname) || ISDOTDOT(dname)) {
continue;
@ -5110,7 +5111,7 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
goto err;
}
while ((dname = ReadDirName(dir_hnd,&dirpos))) {
while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
continue;
if (!is_visible_file(conn, directory, dname, &st, False))
@ -5133,7 +5134,7 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
/* Do a recursive delete. */
RewindDir(dir_hnd,&dirpos);
while ((dname = ReadDirName(dir_hnd,&dirpos))) {
while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
char *fullname = NULL;
if (ISDOT(dname) || ISDOTDOT(dname)) {
@ -5911,7 +5912,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
* - gentest fix. JRA
*/
while ((dname = ReadDirName(dir_hnd, &offset))) {
while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) {
files_struct *fsp = NULL;
char *fname = NULL;
char *destname = NULL;
@ -6513,7 +6514,7 @@ void reply_copy(struct smb_request *req)
error = ERRbadfile;
while ((dname = ReadDirName(dir_hnd, &offset))) {
while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) {
char *destname = NULL;
char *fname = NULL;