static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
-static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
- connection_struct *conn,
- const struct smb_filename *smb_dname,
- const char *wcard,
- uint32_t attr);
static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
#define INVALID_DPTR_KEY (-3)
return(0);
}
-/****************************************************************************
- Get the fsp stored in a dptr->dir_hnd.
-****************************************************************************/
-
-files_struct *dptr_fsp(struct smbd_server_connection *sconn, int key)
-{
- struct dptr_struct *dptr = dptr_get(sconn, key);
- if (dptr == NULL) {
- return NULL;
- }
- if (dptr->dir_hnd == NULL) {
- return NULL;
- }
- return dptr->dir_hnd->fsp;
-}
-
-/****************************************************************************
- Close a dptr (internal func).
-****************************************************************************/
-
-static void dptr_close_internal(struct dptr_struct *dptr)
-{
- struct smbd_server_connection *sconn = dptr->conn->sconn;
-
- DEBUG(4,("closing dptr key %d\n",dptr->dnum));
-
- if (sconn == NULL) {
- goto done;
- }
-
- if (sconn->using_smb2) {
- goto done;
- }
-
- DLIST_REMOVE(sconn->searches.dirptrs, dptr);
-
- /*
- * Free the dnum in the bitmap. Remember the dnum value is always
- * biased by one with respect to the bitmap.
- */
-
- if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
- DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
- dptr->dnum ));
- }
-
- bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
-
-done:
- TALLOC_FREE(dptr->dir_hnd);
- TALLOC_FREE(dptr);
-}
-
-/****************************************************************************
- Close a dptr given a key. SMB1 *only*.
-****************************************************************************/
-
-void dptr_close(struct smbd_server_connection *sconn, int *key)
-{
- struct dptr_struct *dptr;
-
- SMB_ASSERT(!sconn->using_smb2);
-
- if(*key == INVALID_DPTR_KEY)
- return;
-
- dptr = dptr_get(sconn, *key);
-
- if (!dptr) {
- DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
- return;
- }
-
- dptr_close_internal(dptr);
-
- *key = INVALID_DPTR_KEY;
-}
-
/****************************************************************************
Close all dptrs for a cnum.
****************************************************************************/
for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
next = dptr->next;
if (dptr->conn == conn) {
- dptr_close_internal(dptr);
+ files_struct *fsp = dptr->dir_hnd->fsp;
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
}
}
}
-/****************************************************************************
- Are there any SMB1 searches active on this connection struct ?
-****************************************************************************/
-
-bool dptr_activecnum(const struct smbd_server_connection *sconn,
- const struct connection_struct *conn)
-{
- const struct dptr_struct *dptr;
-
- for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
- if (dptr->conn == conn) {
- return true;
- }
- }
- return false;
-}
-
-/****************************************************************************
- Close a dptr that matches a given path, only if it matches the spid also.
-****************************************************************************/
-
-void dptr_closepath(struct smbd_server_connection *sconn,
- char *path,uint16_t spid)
-{
- struct dptr_struct *dptr, *next;
- for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
- next = dptr->next;
- if (spid == dptr->spid &&
- strequal(dptr->smb_dname->base_name,path)) {
- dptr_close_internal(dptr);
- }
- }
-}
-
-/****************************************************************************
- Safely do an OpenDir as root, ensuring we're in the right place.
-****************************************************************************/
-
-static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
- struct smb_request *req,
- const struct smb_filename *smb_dname,
- const char *wcard,
- uint32_t attr)
-{
- struct smb_Dir *dir_hnd = NULL;
- struct smb_filename *smb_fname_cwd = NULL;
- struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
- struct privilege_paths *priv_paths = req->priv_paths;
- int ret;
-
- if (saved_dir_fname == NULL) {
- return NULL;
- }
-
- if (vfs_ChDir(conn, smb_dname) == -1) {
- return NULL;
- }
-
- /* Now check the stat value is the same. */
- smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
- ".",
- NULL,
- NULL,
- smb_dname->flags);
- if (smb_fname_cwd == NULL) {
- goto out;
- }
- ret = SMB_VFS_STAT(conn, smb_fname_cwd);
- if (ret != 0) {
- goto out;
- }
-
- if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
- DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
- "and %s\n",
- smb_dname->base_name,
- smb_fname_str_dbg(&priv_paths->parent_name)));
- goto out;
- }
-
- dir_hnd = open_dir_safely(NULL, conn, smb_fname_cwd, wcard, attr);
-
- if (dir_hnd != NULL) {
- talloc_set_destructor(dir_hnd, smb_Dir_destructor);
- }
-
- out:
-
- vfs_ChDir(conn, saved_dir_fname);
- TALLOC_FREE(saved_dir_fname);
- return dir_hnd;
-}
-
/****************************************************************************
Create a new dir ptr. If the flag old_handle is true then we must allocate
from the bitmap range 0 - 255 as old SMBsearch directory handles are only
NTSTATUS dptr_create(connection_struct *conn,
struct smb_request *req,
files_struct *fsp,
- const struct smb_filename *smb_dname,
bool old_handle,
bool expect_close,
uint16_t spid,
struct dptr_struct *dptr = NULL;
struct smb_Dir *dir_hnd;
- if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
- smb_dname = fsp->fsp_name;
- }
-
- DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
+ DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
if (sconn == NULL) {
DEBUG(0,("dptr_create: called with fake connection_struct\n"));
return NT_STATUS_INVALID_PARAMETER;
}
- if (fsp) {
- if (!(fsp->access_mask & SEC_DIR_LIST)) {
- DEBUG(5,("dptr_create: directory %s "
- "not open for LIST access\n",
- smb_dname->base_name));
- return NT_STATUS_ACCESS_DENIED;
- }
- dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
- } else {
- int ret;
- bool backup_intent = (req && req->priv_paths);
- NTSTATUS status;
- struct smb_filename *smb_dname_cp =
- cp_smb_filename(talloc_tos(), smb_dname);
-
- if (smb_dname_cp == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (req != NULL && req->posix_pathnames) {
- ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
- } else {
- ret = SMB_VFS_STAT(conn, smb_dname_cp);
- }
- if (ret == -1) {
- status = map_nt_error_from_unix(errno);
- TALLOC_FREE(smb_dname_cp);
- return status;
- }
- if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
- TALLOC_FREE(smb_dname_cp);
- return NT_STATUS_NOT_A_DIRECTORY;
- }
- status = smbd_check_access_rights(conn,
- smb_dname_cp,
- backup_intent,
- SEC_DIR_LIST);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(smb_dname_cp);
- return status;
- }
- if (backup_intent) {
- dir_hnd = open_dir_with_privilege(conn,
- req,
- smb_dname_cp,
- wcard,
- attr);
- } else {
- dir_hnd = open_dir_safely(NULL,
- conn,
- smb_dname_cp,
- wcard,
- attr);
- if (dir_hnd != NULL) {
- talloc_set_destructor(dir_hnd,
- smb_Dir_destructor);
- }
- }
-
-
- TALLOC_FREE(smb_dname_cp);
+ if (!(fsp->access_mask & SEC_DIR_LIST)) {
+ DBG_INFO("dptr_create: directory %s "
+ "not open for LIST access\n",
+ fsp_str_dbg(fsp));
+ return NT_STATUS_ACCESS_DENIED;
}
-
+ dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
if (!dir_hnd) {
return map_nt_error_from_unix(errno);
}
return NT_STATUS_NO_MEMORY;
}
- dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
- if (!dptr->smb_dname) {
+ dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
+ if (dptr->smb_dname == NULL) {
TALLOC_FREE(dptr);
TALLOC_FREE(dir_hnd);
return NT_STATUS_NO_MEMORY;
DLIST_ADD(sconn->searches.dirptrs, dptr);
done:
- DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
- dptr->dnum,
- dptr->smb_dname->base_name,
- expect_close));
+ DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
+ dptr->dnum, fsp_str_dbg(fsp), expect_close);
*dptr_ret = dptr;
void dptr_CloseDir(files_struct *fsp)
{
- if (fsp->dptr) {
+ struct smbd_server_connection *sconn = NULL;
+
+ if (fsp->dptr == NULL) {
+ return;
+ }
+ sconn = fsp->dptr->conn->sconn;
+
+ /*
+ * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
+ * now handles all resource deallocation.
+ */
+
+ DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
+
+ if (sconn != NULL && !sconn->using_smb2) {
+ DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
+
/*
- * The destructor for the struct smb_Dir
- * (fsp->dptr->dir_hnd) now handles
- * all resource deallocation.
+ * Free the dnum in the bitmap. Remember the dnum value is
+ * always biased by one with respect to the bitmap.
*/
- dptr_close_internal(fsp->dptr);
- fsp->dptr = NULL;
+
+ if (!bitmap_query(sconn->searches.dptr_bmap,
+ fsp->dptr->dnum - 1))
+ {
+ DBG_ERR("closing dnum = %d and bitmap not set !\n",
+ fsp->dptr->dnum);
+ }
+
+ bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
}
+
+ TALLOC_FREE(fsp->dptr->dir_hnd);
+ TALLOC_FREE(fsp->dptr);
}
void dptr_SeekDir(struct dptr_struct *dptr, long offset)
while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
!= NULL) {
if (is_visible_file(dptr->conn,
- dptr->smb_dname->base_name,
+ dptr->dir_hnd,
name,
pst,
true)) {
/* First check if it should be visible. */
if (!is_visible_file(dptr->conn,
- dptr->smb_dname->base_name,
+ dptr->dir_hnd,
dptr->wcard,
pst,
true)) {
}
/****************************************************************************
- Fetch the dir ptr and seek it given the 5 byte server field.
+ Return the associated fsp and seek the dir_hnd on it it given the 5 byte
+ server field.
****************************************************************************/
-struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
+files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
char *buf, int *num)
{
unsigned int key = *(unsigned char *)buf;
uint32_t wire_offset;
long seekoff;
- if (!dptr) {
+ if (dptr == NULL) {
DEBUG(3,("fetched null dirptr %d\n",key));
return(NULL);
}
SeekDir(dptr->dir_hnd,seekoff);
DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
key, dptr->smb_dname->base_name, (int)seekoff));
- return(dptr);
+ return dptr->dir_hnd->fsp;
}
/****************************************************************************
- Fetch the dir ptr.
+ Fetch the fsp associated with the dptr_num.
****************************************************************************/
-struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
+files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
int dptr_num)
{
struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
-
- if (!dptr) {
- DEBUG(3,("fetched null dirptr %d\n",dptr_num));
- return(NULL);
+ if (dptr == NULL) {
+ return NULL;
}
- DEBUG(3,("fetching dirptr %d for path %s\n",
+ DBG_NOTICE("fetching dirptr %d for path %s\n",
dptr_num,
- dptr->smb_dname->base_name));
- return(dptr);
+ dptr->smb_dname->base_name);
+ return dptr->dir_hnd->fsp;
}
static bool mangle_mask_match(connection_struct *conn,
continue;
}
- if (ask_sharemode) {
+ if (ask_sharemode && !S_ISDIR(smb_fname.st.st_ex_mode)) {
struct timespec write_time_ts;
struct file_id fileid;
fileid = vfs_file_id_from_sbuf(conn,
&smb_fname.st);
get_file_infos(fileid, 0, NULL, &write_time_ts);
- if (!null_timespec(write_time_ts)) {
+ if (!is_omit_timespec(&write_time_ts)) {
update_stat_ex_mtime(&smb_fname.st,
write_time_ts);
}
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,
+ struct smb_Dir *dir_hnd,
+ const char *name,
+ SMB_STRUCT_STAT *pst,
+ bool use_veto)
{
bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
bool hide_special = lp_hide_special_files(SNUM(conn));
int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
char *entry = NULL;
+ struct smb_filename *dir_path = dir_hnd->fsp->fsp_name;
struct smb_filename *smb_fname_base = NULL;
bool ret = false;
hide_special ||
(hide_new_files_timeout != 0))
{
- entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
+ entry = talloc_asprintf(talloc_tos(),
+ "%s/%s",
+ dir_path->base_name,
+ name);
if (!entry) {
ret = false;
goto out;
goto out;
}
/* Honour _hide unwriteable_ option */
- if (hide_unwriteable && !user_can_write_file(conn,
- smb_fname_base)) {
+ if (hide_unwriteable &&
+ !user_can_write_file(conn,
+ smb_fname_base))
+ {
DEBUG(10,("is_visible_file: file %s is unwritable.\n",
entry ));
ret = false;
static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
{
- if (dir_hnd->dir != NULL) {
- SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
- if (dir_hnd->fsp != NULL) {
- /*
- * The SMB_VFS_CLOSEDIR above
- * closes the underlying fd inside
- * dirp->fsp.
- */
- dir_hnd->fsp->fh->fd = -1;
- if (dir_hnd->fsp->dptr != NULL) {
- SMB_ASSERT(dir_hnd->fsp->dptr->dir_hnd ==
- dir_hnd);
- dir_hnd->fsp->dptr->dir_hnd = NULL;
- }
- dir_hnd->fsp = NULL;
- }
+ files_struct *fsp = dir_hnd->fsp;
+
+ SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
+ fsp->fh->fd = -1;
+ if (fsp->dptr != NULL) {
+ SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
+ fsp->dptr->dir_hnd = NULL;
}
+ dir_hnd->fsp = NULL;
return 0;
}
Open a directory.
********************************************************************/
-static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
- connection_struct *conn,
- const struct smb_filename *smb_dname,
- const char *mask,
- uint32_t attr)
+static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
{
- struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
-
- if (!dir_hnd) {
- return NULL;
- }
-
- dir_hnd->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
+ files_struct *fsp = dir_hnd->fsp;
- if (!dir_hnd->dir) {
- DEBUG(5,("OpenDir: Can't open %s. %s\n",
- smb_dname->base_name,
- strerror(errno) ));
- goto fail;
- }
-
- dir_hnd->conn = conn;
-
- if (!conn->sconn->using_smb2) {
- /*
- * The dircache is only needed for SMB1 because SMB1 uses a name
- * for the resume wheras SMB2 always continues from the next
- * position (unless it's told to restart or close-and-reopen the
- * listing).
- */
- dir_hnd->name_cache_size =
- lp_directory_name_cache_size(SNUM(conn));
- }
-
- return dir_hnd;
-
- fail:
- TALLOC_FREE(dir_hnd);
- return NULL;
+ smb_Dir_destructor(dir_hnd);
+ file_free(NULL, fsp);
+ return 0;
}
-/**
- * @brief Open a directory handle by pathname, ensuring it's under the share path.
- *
- * First stores the $cwd, then changes directory to the passed in pathname
- * uses check_name() to ensure this is under the connection struct share path,
- * then operates on a pathname of "." to ensure we're in the same place.
- *
- * The returned struct smb_Dir * should have a talloc destrctor added to
- * ensure that when the struct is freed the internal POSIX DIR * pointer
- * is closed.
- *
- * @code
- *
- * static int sample_smb_Dir_destructor(struct smb_Dir *dirp)
- * {
- * SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
- * }
- * ..
- * struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
- * conn,
- * smb_dname,
- * mask,
- * attr);
- * if (dir_hnd == NULL) {
- * return NULL;
- * }
- * talloc_set_destructor(dir_hnd, smb_Dir_destructor);
- * ..
- * @endcode
- */
-
-static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
- connection_struct *conn,
- const struct smb_filename *smb_dname,
- const char *wcard,
- uint32_t attr)
+struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const struct smb_filename *smb_dname,
+ const char *mask,
+ uint32_t attr)
{
+ struct files_struct *fsp = NULL;
struct smb_Dir *dir_hnd = NULL;
- struct smb_filename *smb_fname_cwd = NULL;
- struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
NTSTATUS status;
- if (saved_dir_fname == NULL) {
- return NULL;
- }
-
- if (vfs_ChDir(conn, smb_dname) == -1) {
- goto out;
- }
-
- smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
- ".",
- NULL,
- NULL,
- smb_dname->flags);
- if (smb_fname_cwd == NULL) {
- goto out;
- }
-
- /*
- * Now the directory is pinned, use
- * REALPATH to ensure we can access it.
- */
- status = check_name(conn, smb_fname_cwd);
+ status = open_internal_dirfsp_at(conn, conn->cwd_fsp, smb_dname, &fsp);
if (!NT_STATUS_IS_OK(status)) {
- goto out;
+ return NULL;
}
- dir_hnd = OpenDir_internal(ctx,
- conn,
- smb_fname_cwd,
- wcard,
- attr);
-
+ dir_hnd = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr);
if (dir_hnd == NULL) {
- goto out;
+ return NULL;
}
/*
- * OpenDir_internal only gets "." as the dir name.
- * Store the real dir name here.
+ * This overwrites the destructor set by smb_Dir_OpenDir_destructor(),
+ * but smb_Dir_OpenDir_destructor() calls the OpenDir_fsp() destructor.
*/
-
- dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
- if (!dir_hnd->dir_smb_fname) {
- TALLOC_FREE(dir_hnd);
- SMB_VFS_CLOSEDIR(conn, dir_hnd->dir);
- errno = ENOMEM;
- }
-
- out:
-
- vfs_ChDir(conn, saved_dir_fname);
- TALLOC_FREE(saved_dir_fname);
- return dir_hnd;
-}
-
-/*
- * Simple destructor for OpenDir() use. Don't need to
- * care about fsp back pointer as we know we have never
- * set it in the OpenDir() code path.
- */
-
-static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
-{
- SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
- return 0;
-}
-
-struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
- const struct smb_filename *smb_dname,
- const char *mask,
- uint32_t attr)
-{
- struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
- conn,
- smb_dname,
- mask,
- attr);
- if (dir_hnd == NULL) {
- return NULL;
- }
talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
return dir_hnd;
}
goto fail;
}
- if (!fsp->is_directory) {
+ if (!fsp->fsp_flags.is_directory) {
errno = EBADF;
goto fail;
}
}
dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
- if (dir_hnd->dir != NULL) {
- dir_hnd->fsp = fsp;
- } else {
- DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
- "NULL (%s)\n",
- dir_hnd->dir_smb_fname->base_name,
- strerror(errno)));
- if (errno != ENOSYS) {
- goto fail;
- }
- }
-
if (dir_hnd->dir == NULL) {
- /* FDOPENDIR is not supported. Use OPENDIR instead. */
- TALLOC_FREE(dir_hnd);
- dir_hnd = open_dir_safely(mem_ctx,
- conn,
- fsp->fsp_name,
- mask,
- attr);
- if (dir_hnd == NULL) {
- errno = ENOMEM;
- goto fail;
- }
+ goto fail;
}
+ dir_hnd->fsp = fsp;
talloc_set_destructor(dir_hnd, smb_Dir_destructor);
NTSTATUS status = NT_STATUS_OK;
long dirpos = 0;
const char *dname = NULL;
- const char *dirname = fsp->fsp_name->base_name;
char *talloced = NULL;
SMB_STRUCT_STAT st;
struct connection_struct *conn = fsp->conn;
}
}
- if (!is_visible_file(conn, dirname, dname, &st, True)) {
+ if (!is_visible_file(conn,
+ dir_hnd,
+ dname,
+ &st,
+ True)) {
TALLOC_FREE(talloced);
continue;
}