return NT_STATUS_OK;
}
- status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
+ status = SMB_VFS_GET_NT_ACL_AT(conn,
+ dirfsp,
+ smb_fname,
(SECINFO_OWNER |
- SECINFO_GROUP |
- SECINFO_DACL), talloc_tos(), &sd);
+ SECINFO_GROUP |
+ SECINFO_DACL),
+ talloc_tos(),
+ &sd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("smbd_check_access_rights: Could not get acl "
}
NTSTATUS check_parent_access(struct connection_struct *conn,
+ struct files_struct *dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask)
{
TALLOC_CTX *frame = talloc_stackframe();
bool ok;
+ /*
+ * NB. When dirfsp != conn->cwd_fsp, we must
+ * change parent_dir to be "." for the name here.
+ */
+
+ SMB_ASSERT(dirfsp == conn->cwd_fsp);
+
ok = parent_smb_fname(frame, smb_fname, &parent_dir, NULL);
if (!ok) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
- status = SMB_VFS_GET_NT_ACL(conn,
+ status = SMB_VFS_GET_NT_ACL_AT(conn,
+ dirfsp,
parent_dir,
SECINFO_DACL,
frame,
&parent_sd);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(5,("check_parent_access: SMB_VFS_GET_NT_ACL failed for "
+ DBG_INFO("SMB_VFS_GET_NT_ACL_AT failed for "
"%s with error %s\n",
smb_fname_str_dbg(parent_dir),
- nt_errstr(status)));
+ nt_errstr(status));
goto out;
}
{
NTSTATUS status;
- status = smbd_calculate_access_mask(conn, smb_fname,
+ status = smbd_calculate_access_mask(conn,
+ conn->cwd_fsp,
+ smb_fname,
false,
access_mask,
&access_mask);
}
static int non_widelink_open(struct connection_struct *conn,
- const struct smb_filename *conn_rootdir_fname,
files_struct *fsp,
struct smb_filename *smb_fname,
int flags,
****************************************************************************/
static int process_symlink_open(struct connection_struct *conn,
- const struct smb_filename *conn_rootdir_fname,
files_struct *fsp,
struct smb_filename *smb_fname,
int flags,
mode_t mode,
unsigned int link_depth)
{
+ const char *conn_rootdir = NULL;
+ struct smb_filename conn_rootdir_fname;
int fd = -1;
char *link_target = NULL;
- struct smb_filename target_fname = {0};
int link_len = -1;
struct smb_filename *oldwd_fname = NULL;
size_t rootdir_len = 0;
bool matched = false;
int saved_errno = 0;
+ conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
+ if (conn_rootdir == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ conn_rootdir_fname = (struct smb_filename) {
+ .base_name = discard_const_p(char, conn_rootdir),
+ };
+
/*
* Ensure we don't get stuck in a symlink loop.
*/
goto out;
}
- /* Read the link target. */
+ /*
+ * Read the link target. We do this just to verify that smb_fname indeed
+ * points at a symbolic link and return the SMB_VFS_READLINKAT() errno
+ * and failure in case smb_fname is NOT a symlink.
+ *
+ * The caller needs this piece of information to distinguish two cases
+ * where open() fails with errno=ENOTDIR, cf the comment in
+ * non_widelink_open().
+ *
+ * We rely on SMB_VFS_REALPATH() to resolve the path including the
+ * symlink. Once we have SMB_VFS_STATX() or something similar in our VFS
+ * we may want to use that instead of SMB_VFS_READLINKAT().
+ */
link_len = SMB_VFS_READLINKAT(conn,
conn->cwd_fsp,
smb_fname,
goto out;
}
- /* Ensure it's at least null terminated. */
- link_target[link_len] = '\0';
- target_fname = (struct smb_filename){ .base_name = link_target };
-
/* Convert to an absolute path. */
- resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(), &target_fname);
+ resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(), smb_fname);
if (resolved_fname == NULL) {
goto out;
}
* does not end in '/'. FIXME ! Should we
* smb_assert this ?
*/
- rootdir_len = strlen(conn_rootdir_fname->base_name);
+ rootdir_len = strlen(conn_rootdir_fname.base_name);
- matched = (strncmp(conn_rootdir_fname->base_name,
+ matched = (strncmp(conn_rootdir_fname.base_name,
resolved_name,
rootdir_len) == 0);
if (!matched) {
}
/* Ensure we operate from the root of the share. */
- if (vfs_ChDir(conn, conn_rootdir_fname) == -1) {
+ if (vfs_ChDir(conn, &conn_rootdir_fname) == -1) {
goto out;
}
/* And do it all again.. */
fd = non_widelink_open(conn,
- conn_rootdir_fname,
fsp,
smb_fname,
flags,
****************************************************************************/
static int non_widelink_open(struct connection_struct *conn,
- const struct smb_filename *conn_rootdir_fname,
files_struct *fsp,
struct smb_filename *smb_fname,
int flags,
".",
smb_fname->stream_name,
&smb_fname->st,
+ smb_fname->twrp,
smb_fname->flags);
if (smb_fname_rel == NULL) {
saved_errno = errno;
* to ensure it's under the share definition.
*/
fd = process_symlink_open(conn,
- conn_rootdir_fname,
fsp,
smb_fname_rel,
flags,
fd support routines - attempt to do a dos_open.
****************************************************************************/
-NTSTATUS fd_open(struct connection_struct *conn,
- files_struct *fsp,
+NTSTATUS fd_open(files_struct *fsp,
int flags,
mode_t mode)
{
+ struct connection_struct *conn = fsp->conn;
struct smb_filename *smb_fname = fsp->fsp_name;
NTSTATUS status = NT_STATUS_OK;
- struct smb_filename *conn_rootdir_fname = NULL;
- const char *conn_rootdir;
int saved_errno = 0;
/*
flags |= O_NOFOLLOW;
}
- /* Ensure path is below share definition. */
- conn_rootdir = SMB_VFS_CONNECTPATH(conn,
- smb_fname);
-
- if (conn_rootdir == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- conn_rootdir_fname = synthetic_smb_fname(talloc_tos(),
- conn_rootdir,
- NULL,
- NULL,
- 0);
- if (conn_rootdir_fname == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
/*
* Only follow symlinks within a share
* definition.
*/
fsp->fh->fd = non_widelink_open(conn,
- conn_rootdir_fname,
fsp,
smb_fname,
flags,
if (fsp->fh->fd == -1) {
saved_errno = errno;
}
- TALLOC_FREE(conn_rootdir_fname);
if (saved_errno != 0) {
errno = saved_errno;
}
}
}
+ DBG_DEBUG("name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
+ smb_fname_str_dbg(smb_fname), flags, (int)mode,
+ fsp->fh->fd, strerror(errno));
+ return status;
}
- DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
- smb_fname_str_dbg(smb_fname), flags, (int)mode, fsp->fh->fd,
- (fsp->fh->fd == -1) ? strerror(errno) : "" ));
+ DBG_DEBUG("name %s, flags = 0%o mode = 0%o, fd = %d\n",
+ smb_fname_str_dbg(smb_fname), flags, (int)mode, fsp->fh->fd);
return status;
}
goto chdir;
}
- smb_fname_cwd = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
+ smb_fname_cwd = synthetic_smb_fname(ctx,
+ ".",
+ NULL,
+ NULL,
+ smb_dname->twrp,
+ 0);
if (smb_fname_cwd == NULL) {
status = NT_STATUS_NO_MEMORY;
goto chdir;
file was created or not.
****************************************************************************/
-static NTSTATUS fd_open_atomic(struct connection_struct *conn,
- files_struct *fsp,
- int flags,
- mode_t mode,
- bool *file_created)
+static NTSTATUS fd_open_atomic(files_struct *fsp,
+ int flags,
+ mode_t mode,
+ bool *file_created)
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
NTSTATUS retry_status;
/*
* We're not creating the file, just pass through.
*/
- status = fd_open(conn, fsp, flags, mode);
+ status = fd_open(fsp, flags, mode);
*file_created = false;
return status;
}
/*
* Fail if already exists, just pass through.
*/
- status = fd_open(conn, fsp, flags, mode);
+ status = fd_open(fsp, flags, mode);
/*
* Here we've opened with O_CREAT|O_EXCL. If that went
retry_status = NT_STATUS_OBJECT_NAME_COLLISION;
}
- status = fd_open(conn, fsp, curr_flags, mode);
+ status = fd_open(fsp, curr_flags, mode);
if (NT_STATUS_IS_OK(status)) {
*file_created = !file_existed;
return NT_STATUS_OK;
curr_flags = flags | O_EXCL;
}
- status = fd_open(conn, fsp, curr_flags, mode);
+ status = fd_open(fsp, curr_flags, mode);
}
*file_created = (NT_STATUS_IS_OK(status) && !file_existed);
****************************************************************************/
static NTSTATUS open_file(files_struct *fsp,
- connection_struct *conn,
struct smb_request *req,
struct smb_filename *parent_dir,
int flags,
uint32_t open_access_mask, /* what we're actually using in the open. */
bool *p_file_created)
{
+ connection_struct *conn = fsp->conn;
struct smb_filename *smb_fname = fsp->fsp_name;
NTSTATUS status = NT_STATUS_OK;
int accmode = (flags & O_ACCMODE);
}
status = check_parent_access(conn,
+ conn->cwd_fsp,
smb_fname,
SEC_DIR_ADD_FILE);
if (!NT_STATUS_IS_OK(status)) {
* Actually do the open - if O_TRUNC is needed handle it
* below under the share mode lock.
*/
- status = fd_open_atomic(conn, fsp, local_flags & ~O_TRUNC,
- unx_mode, p_file_created);
+ status = fd_open_atomic(fsp,
+ local_flags & ~O_TRUNC,
+ unx_mode,
+ p_file_created);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
"(flags=%d)\n", smb_fname_str_dbg(smb_fname),
Returns True if conflict, False if not.
****************************************************************************/
+static const uint32_t conflicting_access =
+ FILE_WRITE_DATA|
+ FILE_APPEND_DATA|
+ FILE_READ_DATA|
+ FILE_EXECUTE|
+ DELETE_ACCESS;
+
static bool share_conflict(uint32_t e_access_mask,
uint32_t e_share_access,
uint32_t access_mask,
uint32_t share_access)
{
- const uint32_t conflicting_access =
- FILE_WRITE_DATA|
- FILE_APPEND_DATA|
- FILE_READ_DATA|
- FILE_EXECUTE|
- DELETE_ACCESS;
bool conflict;
DBG_DEBUG("existing access_mask = 0x%"PRIx32", "
&existing_lease_type);
existing_access_mask |= access_mask;
- existing_share_mode &= share_mode;
+ if (access_mask & conflicting_access) {
+ existing_share_mode &= share_mode;
+ }
existing_lease_type |= lease_type;
ret = share_mode_flags_set(
}
access_mask = state->access_mask | e->access_mask;
- share_access = state->share_access & e->share_access;
+ share_access = state->share_access;
+ if (e->access_mask & conflicting_access) {
+ share_access &= e->share_access;
+ }
lease_type = state->lease_type | get_lease_type(e, state->fid);
if ((access_mask == state->access_mask) &&
static NTSTATUS smbd_calculate_maximum_allowed_access(
connection_struct *conn,
+ struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
bool use_privs,
uint32_t *p_access_mask)
uint32_t access_granted;
NTSTATUS status;
+ SMB_ASSERT(dirfsp == conn->cwd_fsp);
+
if (!use_privs && (get_current_uid(conn) == (uid_t)0)) {
*p_access_mask |= FILE_GENERIC_ALL;
return NT_STATUS_OK;
}
- status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
- (SECINFO_OWNER |
- SECINFO_GROUP |
- SECINFO_DACL),
- talloc_tos(), &sd);
+ status = SMB_VFS_GET_NT_ACL_AT(conn,
+ dirfsp,
+ smb_fname,
+ (SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL),
+ talloc_tos(),
+ &sd);
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
/*
}
NTSTATUS smbd_calculate_access_mask(connection_struct *conn,
- const struct smb_filename *smb_fname,
- bool use_privs,
- uint32_t access_mask,
- uint32_t *access_mask_out)
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ bool use_privs,
+ uint32_t access_mask,
+ uint32_t *access_mask_out)
{
NTSTATUS status;
uint32_t orig_access_mask = access_mask;
uint32_t rejected_share_access;
+ SMB_ASSERT(dirfsp == conn->cwd_fsp);
+
if (access_mask & SEC_MASK_INVALID) {
DBG_DEBUG("access_mask [%8x] contains invalid bits\n",
access_mask);
/* Calculate MAXIMUM_ALLOWED_ACCESS if requested. */
if (access_mask & MAXIMUM_ALLOWED_ACCESS) {
- status = smbd_calculate_maximum_allowed_access(
- conn, smb_fname, use_privs, &access_mask);
+ status = smbd_calculate_maximum_allowed_access(conn,
+ dirfsp,
+ smb_fname,
+ use_privs,
+ &access_mask);
if (!NT_STATUS_IS_OK(status)) {
return status;
bool setup_poll = false;
bool ok;
+ SMB_ASSERT(fsp->dirfsp == conn->cwd_fsp);
+
if (conn->printer) {
/*
* Printers are handled completely differently.
}
}
- status = smbd_calculate_access_mask(conn, smb_fname,
+ status = smbd_calculate_access_mask(conn,
+ conn->cwd_fsp,
+ smb_fname,
false,
access_mask,
- &access_mask);
+ &access_mask);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("open_file_ntcreate: smbd_calculate_access_mask "
"on file %s returned %s\n",
(unsigned int)unx_mode, (unsigned int)access_mask,
(unsigned int)open_access_mask));
- fsp_open = open_file(fsp, conn, req, parent_dir_fname,
- flags|flags2, unx_mode, access_mask,
- open_access_mask, &new_file_created);
-
+ fsp_open = open_file(fsp,
+ req,
+ parent_dir_fname,
+ flags|flags2,
+ unx_mode,
+ access_mask,
+ open_access_mask,
+ &new_file_created);
if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_NETWORK_BUSY)) {
if (file_existed && S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
DEBUG(10, ("FIFO busy\n"));
}
static NTSTATUS mkdir_internal(connection_struct *conn,
+ struct files_struct **dirfsp,
struct smb_filename *smb_dname,
uint32_t file_attributes)
{
int ret;
bool ok;
+ SMB_ASSERT(*dirfsp == conn->cwd_fsp);
+
if (!CAN_WRITE(conn) || (access_mask & ~(conn->share_access))) {
DEBUG(5,("mkdir_internal: failing share access "
"%s\n", lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
}
status = check_parent_access(conn,
- smb_dname,
- access_mask);
+ *dirfsp,
+ smb_dname,
+ access_mask);
if(!NT_STATUS_IS_OK(status)) {
DEBUG(5,("mkdir_internal: check_parent_access "
"on directory %s for path %s returned %s\n",
}
ret = SMB_VFS_MKDIRAT(conn,
- conn->cwd_fsp,
- smb_dname,
- mode);
+ *dirfsp,
+ smb_dname,
+ mode);
if (ret != 0) {
return map_nt_error_from_unix(errno);
}
static NTSTATUS open_directory(connection_struct *conn,
struct smb_request *req,
+ struct files_struct **dirfsp,
struct smb_filename *smb_dname,
uint32_t access_mask,
uint32_t share_access,
NTSTATUS status;
struct timespec mtimespec;
int info = 0;
+ int flags;
bool ok;
+ SMB_ASSERT(*dirfsp == conn->cwd_fsp);
+
if (is_ntfs_stream_smb_fname(smb_dname)) {
DEBUG(2, ("open_directory: %s is a stream name!\n",
smb_fname_str_dbg(smb_dname)));
create_disposition,
file_attributes);
- status = smbd_calculate_access_mask(conn, smb_dname, false,
- access_mask, &access_mask);
+ status = smbd_calculate_access_mask(conn,
+ *dirfsp,
+ smb_dname,
+ false,
+ access_mask,
+ &access_mask);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("open_directory: smbd_calculate_access_mask "
"on file %s returned %s\n",
return status;
}
- status = mkdir_internal(conn, smb_dname,
+ status = mkdir_internal(conn, dirfsp, smb_dname,
file_attributes);
if (!NT_STATUS_IS_OK(status)) {
status = NT_STATUS_OK;
info = FILE_WAS_OPENED;
} else {
- status = mkdir_internal(conn, smb_dname,
+ status = mkdir_internal(conn, dirfsp, smb_dname,
file_attributes);
if (NT_STATUS_IS_OK(status)) {
if (info == FILE_WAS_OPENED) {
status = smbd_check_access_rights(conn,
- conn->cwd_fsp,
+ *dirfsp,
smb_dname,
false,
access_mask);
return status;
}
+ if (*dirfsp == fsp->conn->cwd_fsp) {
+ fsp->dirfsp = fsp->conn->cwd_fsp;
+ } else {
+ fsp->dirfsp = talloc_move(fsp, dirfsp);
+ }
+
/* Don't store old timestamps for directory
handles in the internal database. We don't
update them in there if new objects
*/
mtimespec = make_omit_timespec();
-#ifdef O_DIRECTORY
- status = fd_open(conn, fsp, O_RDONLY|O_DIRECTORY, 0);
-#else
/* POSIX allows us to open a directory with O_RDONLY. */
- status = fd_open(conn, fsp, O_RDONLY, 0);
+ flags = O_RDONLY;
+#ifdef O_DIRECTORY
+ flags |= O_DIRECTORY;
#endif
+
+ status = fd_open(fsp, flags, 0);
if (!NT_STATUS_IS_OK(status)) {
DBG_INFO("Could not open fd for "
"%s (%s)\n",
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
req, /* req */
- 0, /* root_dir_fid */
+ &conn->cwd_fsp, /* dirfsp */
smb_dname, /* fname */
FILE_READ_ATTRIBUTES, /* access_mask */
FILE_SHARE_NONE, /* share_access */
msg->stream_name = NULL;
}
- smb_fname = synthetic_smb_fname(
- msg, msg->base_name, msg->stream_name, NULL, 0);
+ smb_fname = synthetic_smb_fname(msg,
+ msg->base_name,
+ msg->stream_name,
+ NULL,
+ 0,
+ 0);
if (smb_fname == NULL) {
DBG_DEBUG("synthetic_smb_fname failed\n");
goto out;
smb_fname->base_name,
stream_info[i].name,
NULL,
+ smb_fname->twrp,
(smb_fname->flags &
~SMB_FILENAME_POSIX_PATH));
if (smb_fname_cp == NULL) {
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
- 0, /* root_dir_fid */
+ &conn->cwd_fsp, /* dirfsp */
smb_fname_cp, /* fname */
DELETE_ACCESS, /* access_mask */
(FILE_SHARE_READ | /* share_access */
return NT_STATUS_NO_MEMORY;
}
- status = SMB_VFS_GET_NT_ACL(fsp->conn,
- parent_dir,
- (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
- frame,
- &parent_desc);
+ status = SMB_VFS_GET_NT_ACL_AT(fsp->conn,
+ fsp->conn->cwd_fsp,
+ parent_dir,
+ (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
+ frame,
+ &parent_desc);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
return status;
static NTSTATUS create_file_unixpath(connection_struct *conn,
struct smb_request *req,
+ struct files_struct **dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask,
uint32_t share_access,
files_struct *fsp = NULL;
NTSTATUS status;
+ SMB_ASSERT(*dirfsp == conn->cwd_fsp);
+
DBG_DEBUG("create_file_unixpath: access_mask = 0x%x "
"file_attributes = 0x%x, share_access = 0x%x, "
"create_disposition = 0x%x create_options = 0x%x "
smb_fname->base_name,
NULL,
NULL,
+ smb_fname->twrp,
smb_fname->flags);
if (smb_fname_base == NULL) {
status = NT_STATUS_NO_MEMORY;
base_privflags = NTCREATEX_OPTIONS_PRIVATE_STREAM_BASEOPEN;
/* Open the base file. */
- status = create_file_unixpath(conn, NULL, smb_fname_base, 0,
+ status = create_file_unixpath(conn,
+ NULL,
+ dirfsp,
+ smb_fname_base,
+ 0,
FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE,
base_create_disposition,
- 0, 0, 0, NULL, 0,
+ 0,
+ 0,
+ 0,
+ NULL,
+ 0,
base_privflags,
- NULL, NULL,
- &base_fsp, NULL);
+ NULL,
+ NULL,
+ &base_fsp,
+ NULL);
TALLOC_FREE(smb_fname_base);
if (!NT_STATUS_IS_OK(status)) {
*/
oplock_request = 0;
- status = open_directory(
- conn, req, smb_fname, access_mask, share_access,
- create_disposition, create_options, file_attributes,
- &info, &fsp);
+ status = open_directory(conn,
+ req,
+ dirfsp,
+ smb_fname,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ &info,
+ &fsp);
} else {
/*
goto fail;
}
+ if (*dirfsp == fsp->conn->cwd_fsp) {
+ fsp->dirfsp = fsp->conn->cwd_fsp;
+ } else {
+ fsp->dirfsp = talloc_move(fsp, dirfsp);
+ }
+
if (base_fsp) {
/*
* We're opening the stream element of a
}
oplock_request = 0;
- status = open_directory(
- conn, req, smb_fname, access_mask,
- share_access, create_disposition,
- create_options, file_attributes,
- &info, &fsp);
+ status = open_directory(conn,
+ req,
+ dirfsp,
+ smb_fname,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ &info,
+ &fsp);
}
}
return status;
}
-/*
- * Calculate the full path name given a relative fid.
- */
-static NTSTATUS get_relative_fid_filename(
- connection_struct *conn,
- struct smb_request *req,
- uint16_t root_dir_fid,
- const struct smb_filename *smb_fname,
- struct smb_filename **smb_fname_out)
-{
- files_struct *dir_fsp;
- char *parent_fname = NULL;
- char *new_base_name = NULL;
- uint32_t ucf_flags = ucf_flags_from_smb_request(req);
- NTSTATUS status;
-
- if (root_dir_fid == 0 || !smb_fname) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto out;
- }
-
- dir_fsp = file_fsp(req, root_dir_fid);
-
- if (dir_fsp == NULL) {
- status = NT_STATUS_INVALID_HANDLE;
- goto out;
- }
-
- if (is_ntfs_stream_smb_fname(dir_fsp->fsp_name)) {
- status = NT_STATUS_INVALID_HANDLE;
- goto out;
- }
-
- if (!dir_fsp->fsp_flags.is_directory) {
-
- /*
- * Check to see if this is a mac fork of some kind.
- */
-
- if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
- is_ntfs_stream_smb_fname(smb_fname)) {
- status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
- goto out;
- }
-
- /*
- we need to handle the case when we get a
- relative open relative to a file and the
- pathname is blank - this is a reopen!
- (hint from demyn plantenberg)
- */
-
- status = NT_STATUS_INVALID_HANDLE;
- goto out;
- }
-
- if (ISDOT(dir_fsp->fsp_name->base_name)) {
- /*
- * We're at the toplevel dir, the final file name
- * must not contain ./, as this is filtered out
- * normally by srvstr_get_path and unix_convert
- * explicitly rejects paths containing ./.
- */
- parent_fname = talloc_strdup(talloc_tos(), "");
- if (parent_fname == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
- } else {
- size_t dir_name_len = strlen(dir_fsp->fsp_name->base_name);
-
- /*
- * Copy in the base directory name.
- */
-
- parent_fname = talloc_array(talloc_tos(), char,
- dir_name_len+2);
- if (parent_fname == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
- memcpy(parent_fname, dir_fsp->fsp_name->base_name,
- dir_name_len+1);
-
- /*
- * Ensure it ends in a '/'.
- * We used TALLOC_SIZE +2 to add space for the '/'.
- */
-
- if(dir_name_len
- && (parent_fname[dir_name_len-1] != '\\')
- && (parent_fname[dir_name_len-1] != '/')) {
- parent_fname[dir_name_len] = '/';
- parent_fname[dir_name_len+1] = '\0';
- }
- }
-
- new_base_name = talloc_asprintf(talloc_tos(), "%s%s", parent_fname,
- smb_fname->base_name);
- if (new_base_name == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- status = filename_convert(req,
- conn,
- new_base_name,
- ucf_flags,
- NULL,
- NULL,
- smb_fname_out);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- out:
- TALLOC_FREE(parent_fname);
- TALLOC_FREE(new_base_name);
- return status;
-}
-
NTSTATUS create_file_default(connection_struct *conn,
struct smb_request *req,
- uint16_t root_dir_fid,
+ struct files_struct **_dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask,
uint32_t share_access,
NTSTATUS status;
bool stream_name = false;
struct smb2_create_blob *posx = NULL;
+ struct files_struct *dirfsp = *_dirfsp;
+
+ SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
DBG_DEBUG("create_file: access_mask = 0x%x "
"file_attributes = 0x%x, share_access = 0x%x, "
"create_disposition = 0x%x create_options = 0x%x "
"oplock_request = 0x%x "
"private_flags = 0x%x "
- "root_dir_fid = 0x%x, ea_list = %p, sd = %p, "
+ "ea_list = %p, sd = %p, "
+ "dirfsp = %s, "
"fname = %s\n",
(unsigned int)access_mask,
(unsigned int)file_attributes,
(unsigned int)create_options,
(unsigned int)oplock_request,
(unsigned int)private_flags,
- (unsigned int)root_dir_fid,
- ea_list, sd, smb_fname_str_dbg(smb_fname));
+ ea_list,
+ sd,
+ fsp_str_dbg(dirfsp),
+ smb_fname_str_dbg(smb_fname));
if (req != NULL) {
/*
get_deferred_open_message_state(req, &req->request_time, NULL);
}
- /*
- * Calculate the filename from the root_dir_if if necessary.
- */
-
- if (root_dir_fid != 0) {
- struct smb_filename *smb_fname_out = NULL;
- status = get_relative_fid_filename(conn, req, root_dir_fid,
- smb_fname, &smb_fname_out);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- smb_fname = smb_fname_out;
- }
-
/*
* Check to see if this is a mac fork of some kind.
*/
file_attributes = (FILE_FLAG_POSIX_SEMANTICS | mode_bits);
}
- status = create_file_unixpath(
- conn, req, smb_fname, access_mask, share_access,
- create_disposition, create_options, file_attributes,
- oplock_request, lease, allocation_size, private_flags,
- sd, ea_list,
- &fsp, &info);
-
+ status = create_file_unixpath(conn,
+ req,
+ _dirfsp,
+ smb_fname,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ oplock_request,
+ lease,
+ allocation_size,
+ private_flags,
+ sd,
+ ea_list,
+ &fsp,
+ &info);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}