static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
{
+ bool bval;
+
handle->conn->have_proc_fds = sys_have_proc_fds();
+#ifdef DISABLE_PROC_FDS
+ handle->conn->have_proc_fds = false;
+#endif
+
+ /*
+ * assume the kernel will support openat2(),
+ * it will be reset on the first ENOSYS.
+ *
+ * Note that libreplace will always provide openat2(),
+ * but return -1/errno = ENOSYS...
+ *
+ * The option is only there to test the fallback code.
+ */
+ bval = lp_parm_bool(SNUM(handle->conn),
+ "vfs_default",
+ "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
+ true);
+ if (bval) {
+ handle->conn->open_how_resolve |=
+ VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+ }
+#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
+ handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+#endif
+
return 0; /* Return >= 0 for success */
}
}
static int vfswrap_statvfs(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- vfs_statvfs_struct *statbuf)
+ const struct smb_filename *smb_fname,
+ struct vfs_statvfs_struct *statbuf)
{
return sys_statvfs(smb_fname->base_name, statbuf);
}
*p_ts_res = TIMESTAMP_SET_SECONDS;
#endif
- DEBUG(10,("vfswrap_fs_capabilities: timestamp "
+ DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
"resolution of %s "
"available on share %s, directory %s\n",
*p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
lp_servicename(talloc_tos(), lp_sub, conn->params->service),
- conn->connectpath ));
+ conn->connectpath );
}
TALLOC_FREE(smb_fname_cpath);
return caps;
struct dfs_GetDFSReferral *r)
{
struct junction_map *junction = NULL;
- int consumedcnt = 0;
+ size_t consumedcnt = 0;
bool self_referral = false;
char *pathnamep = NULL;
char *local_dfs_path = NULL;
size_t i;
uint16_t max_referral_level = r->in.req.max_referral_level;
- if (DEBUGLVL(10)) {
+ if (DEBUGLVL(DBGLVL_DEBUG)) {
NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
}
pathnamep,
handle->conn->sconn->remote_address,
handle->conn->sconn->local_address,
- !handle->conn->sconn->using_smb2,
junction, &consumedcnt, &self_referral);
if (!NT_STATUS_IS_OK(status)) {
struct smb_filename connectpath_fname = {
if (!self_referral) {
pathnamep[consumedcnt] = '\0';
- if (DEBUGLVL(3)) {
+ if (DEBUGLVL(DBGLVL_INFO)) {
dbgtext("Path %s to alternate path(s):",
pathnamep);
for (i=0; i < junction->referral_count; i++) {
}
break;
default:
- DEBUG(0,("Invalid dfs referral version: %d\n",
- max_referral_level));
+ DBG_ERR("Invalid dfs referral version: %d\n",
+ max_referral_level);
return NT_STATUS_INVALID_LEVEL;
}
- if (DEBUGLVL(10)) {
+ if (DEBUGLVL(DBGLVL_DEBUG)) {
NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
}
#endif
int ret;
- SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
if (is_named_stream(smb_fname)) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto err;
}
}
- referral_len = readlinkat(fsp_get_io_fd(dirfsp),
+ referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
smb_fname->base_name,
link_target,
bufsize - 1);
goto err;
}
- ret = sys_lstat(smb_fname->base_name,
- &smb_fname->st,
- lp_fake_directory_create_times(SNUM(handle->conn)));
+ ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
+ smb_fname->base_name,
+ &smb_fname->st,
+ AT_SYMLINK_NOFOLLOW,
+ lp_fake_directory_create_times(SNUM(handle->conn)));
if (ret < 0) {
status = map_nt_error_from_unix(errno);
goto err;
return result;
}
-
static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
struct files_struct *dirfsp,
- DIR *dirp,
- SMB_STRUCT_STAT *sbuf)
+ DIR *dirp)
{
struct dirent *result;
- bool do_stat = false;
- bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
- int flags = AT_SYMLINK_NOFOLLOW;
- struct stat st;
- int ret;
START_PROFILE(syscall_readdir);
-#if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
- do_stat = true;
-#endif
-
result = readdir(dirp);
END_PROFILE(syscall_readdir);
- if (sbuf == NULL) {
- return result;
- }
- if (result == NULL) {
- return NULL;
- }
-
- /*
- * Default Posix readdir() does not give us stat info.
- * Set to invalid to indicate we didn't return this info.
- */
- SET_STAT_INVALID(*sbuf);
-
- /* See if we can efficiently return this. */
- if (!do_stat) {
- return result;
- }
-
- ret = fstatat(dirfd(dirp),
- result->d_name,
- &st,
- flags);
- if (ret != 0) {
- return result;
- }
-
- /*
- * As this is an optimization, ignore it if we stat'ed a
- * symlink for non-POSIX context. Make the caller do it again
- * as we don't know if they wanted the link info, or its
- * target info.
- */
- if (S_ISLNK(st.st_mode) &&
- !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
- {
- return result;
- }
- init_stat_ex_from_stat(sbuf, &st, fake_ctime);
-
return result;
}
return NT_STATUS_NOT_SUPPORTED;
}
-static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
-{
- START_PROFILE(syscall_seekdir);
- seekdir(dirp, offset);
- END_PROFILE(syscall_seekdir);
-}
-
-static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
-{
- long result;
- START_PROFILE(syscall_telldir);
- result = telldir(dirp);
- END_PROFILE(syscall_telldir);
- return result;
-}
-
static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
{
START_PROFILE(syscall_rewinddir);
const struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
files_struct *fsp,
- int flags,
- mode_t mode)
+ const struct vfs_open_how *how)
{
+ int flags = how->flags;
+ mode_t mode = how->mode;
bool have_opath = false;
bool became_root = false;
int result;
START_PROFILE(syscall_openat);
- if (is_named_stream(smb_fname)) {
- errno = ENOENT;
+ if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
+ VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
+ errno = ENOSYS;
result = -1;
goto out;
}
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
#ifdef O_PATH
have_opath = true;
if (fsp->fsp_flags.is_pathref) {
flags |= O_PATH;
}
+ if (flags & O_PATH) {
+ /*
+ * From "man 2 openat":
+ *
+ * When O_PATH is specified in flags, flag bits other than
+ * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
+ *
+ * From "man 2 openat2":
+ *
+ * Whereas openat(2) ignores unknown bits in its flags
+ * argument, openat2() returns an error if unknown or
+ * conflicting flags are specified in how.flags.
+ *
+ * So we better clear ignored/invalid flags
+ * and only keep the expected ones.
+ */
+ flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
+ }
#endif
+ if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
+ struct open_how linux_how = {
+ .flags = flags,
+ .mode = mode,
+ .resolve = RESOLVE_NO_SYMLINKS,
+ };
+
+ result = openat2(fsp_get_pathref_fd(dirfsp),
+ smb_fname->base_name,
+ &linux_how,
+ sizeof(linux_how));
+ if (result == -1) {
+ if (errno == ENOSYS) {
+ /*
+ * The kernel doesn't support
+ * openat2(), so indicate to
+ * the callers that
+ * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
+ * would just be a waste of time.
+ */
+ fsp->conn->open_how_resolve &=
+ ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+ }
+ goto out;
+ }
+
+ goto done;
+ }
+
if (fsp->fsp_flags.is_pathref && !have_opath) {
become_root();
became_root = true;
mode);
if (became_root) {
+ int err = errno;
unbecome_root();
+ errno = err;
}
- fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
+done:
+ if (result >= 0) {
+ fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
+ } else {
+ /*
+ * "/proc/self/fd/-1" never exists. Indicate to upper
+ * layers that for this fsp a possible name-based
+ * fallback is the only way to go.
+ */
+ fsp->fsp_flags.have_proc_fds = false;
+ }
out:
END_PROFILE(syscall_openat);
}
static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
struct smb_request *req,
+ struct files_struct *dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask,
uint32_t share_access,
const struct smb2_create_blobs *in_context_blobs,
struct smb2_create_blobs *out_context_blobs)
{
- return create_file_default(handle->conn, req, smb_fname,
+ return create_file_default(handle->conn, req, dirfsp, smb_fname,
access_mask, share_access,
create_disposition, create_options,
file_attributes, oplock_request, lease,
START_PROFILE(syscall_renameat);
- if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) {
- errno = ENOENT;
- goto out;
- }
+ SMB_ASSERT(!is_named_stream(smb_fname_src));
+ SMB_ASSERT(!is_named_stream(smb_fname_dst));
result = renameat(fsp_get_pathref_fd(srcfsp),
smb_fname_src->base_name,
fsp_get_pathref_fd(dstfsp),
smb_fname_dst->base_name);
- out:
END_PROFILE(syscall_renameat);
return result;
}
START_PROFILE(syscall_stat);
- if (is_named_stream(smb_fname)) {
- errno = ENOENT;
- goto out;
- }
+ SMB_ASSERT(!is_named_stream(smb_fname));
result = sys_stat(smb_fname->base_name, &smb_fname->st,
lp_fake_directory_create_times(SNUM(handle->conn)));
- out:
+
END_PROFILE(syscall_stat);
return result;
}
START_PROFILE(syscall_lstat);
- if (is_named_stream(smb_fname)) {
- errno = ENOENT;
- goto out;
- }
+ SMB_ASSERT(!is_named_stream(smb_fname));
result = sys_lstat(smb_fname->base_name, &smb_fname->st,
lp_fake_directory_create_times(SNUM(handle->conn)));
- out:
+
END_PROFILE(syscall_lstat);
return result;
}
+static int vfswrap_fstatat(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ SMB_STRUCT_STAT *sbuf,
+ int flags)
+{
+ int result = -1;
+
+ START_PROFILE(syscall_fstatat);
+
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
+ result = sys_fstatat(
+ fsp_get_pathref_fd(dirfsp),
+ smb_fname->base_name,
+ sbuf,
+ flags,
+ lp_fake_directory_create_times(SNUM(handle->conn)));
+
+ END_PROFILE(syscall_fstatat);
+ return result;
+}
+
static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
const char *name,
enum vfs_translate_direction direction,
/**
* Return allocated parent directory and basename of path
*
- * Note: if requesting name, it is returned as talloc child of the
+ * Note: if requesting atname, it is returned as talloc child of the
* parent. Freeing the parent is thus sufficient to free both.
*/
static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
struct smb_filename **parent_dir_out,
struct smb_filename **atname_out)
{
- TALLOC_CTX *frame = talloc_stackframe();
struct smb_filename *parent = NULL;
struct smb_filename *name = NULL;
char *p = NULL;
- parent = cp_smb_filename(frame, smb_fname_in);
+ parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
if (parent == NULL) {
- TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
- TALLOC_FREE(parent->stream_name);
SET_STAT_INVALID(parent->st);
p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
TALLOC_FREE(parent->base_name);
parent->base_name = talloc_strdup(parent, ".");
if (parent->base_name == NULL) {
- TALLOC_FREE(frame);
+ TALLOC_FREE(parent);
return NT_STATUS_NO_MEMORY;
}
p = smb_fname_in->base_name;
}
if (atname_out == NULL) {
- *parent_dir_out = talloc_move(mem_ctx, &parent);
- TALLOC_FREE(frame);
+ *parent_dir_out = parent;
return NT_STATUS_OK;
}
- name = cp_smb_filename(frame, smb_fname_in);
+ name = synthetic_smb_fname(
+ parent,
+ p,
+ smb_fname_in->stream_name,
+ &smb_fname_in->st,
+ smb_fname_in->twrp,
+ smb_fname_in->flags);
if (name == NULL) {
- TALLOC_FREE(frame);
- return NT_STATUS_NO_MEMORY;
- }
- TALLOC_FREE(name->base_name);
-
- name->base_name = talloc_strdup(name, p);
- if (name->base_name == NULL) {
- TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
- *parent_dir_out = talloc_move(mem_ctx, &parent);
- *atname_out = talloc_move(*parent_dir_out, &name);
- TALLOC_FREE(frame);
+ *parent_dir_out = parent;
+ *atname_out = name;
return NT_STATUS_OK;
}
char **out_data = (char **)_out_data;
NTSTATUS status;
+ /*
+ * Currently all fsctls operate on the base
+ * file if given an alternate data stream.
+ * Revisit this if we implement fsctls later
+ * that need access to the ADS handle.
+ */
+ fsp = metadata_fsp(fsp);
+
switch (function) {
case FSCTL_SET_SPARSE:
{
case FSCTL_CREATE_OR_GET_OBJECT_ID:
{
unsigned char objid[16];
- char *return_data = NULL;
+ uint8_t *return_data = NULL;
/* This should return the object-id on this file.
* I think I'll make this be the inode+dev. JRA.
*/
- DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
- fsp_fnum_dbg(fsp)));
+ DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
+ fsp_fnum_dbg(fsp));
*out_len = MIN(max_out_len, 64);
/* Hmmm, will this cause problems if less data asked for? */
- return_data = talloc_array(ctx, char, 64);
+ return_data = talloc_array(ctx, uint8_t, 64);
if (return_data == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* For backwards compatibility only store the dev/inode. */
push_file_id_16(return_data, &fsp->file_id);
memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
- push_file_id_16(return_data+32, &fsp->file_id);
+ push_file_id_16(return_data + 32, &fsp->file_id);
memset(return_data+48, 0, 16);
- *out_data = return_data;
+ *_out_data = return_data;
return NT_STATUS_OK;
}
case FSCTL_GET_REPARSE_POINT:
{
+ uint32_t tag;
status = fsctl_get_reparse_point(
- fsp, ctx, out_data, max_out_len, out_len);
+ fsp, ctx, &tag, _out_data, max_out_len, out_len);
return status;
}
char *cur_pdata = NULL;
if (max_out_len < 16) {
- DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
- max_out_len));
+ DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
+ max_out_len);
return NT_STATUS_INVALID_PARAMETER;
}
shadow_data = talloc_zero(ctx, struct shadow_copy_data);
if (shadow_data == NULL) {
- DEBUG(0,("TALLOC_ZERO() failed!\n"));
+ DBG_ERR("TALLOC_ZERO() failed!\n");
return NT_STATUS_NO_MEMORY;
}
* Call the VFS routine to actually do the work.
*/
if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
- int log_lev = 0;
+ int log_lev = DBGLVL_ERR;
if (errno == 0) {
/* broken module didn't set errno on error */
status = NT_STATUS_UNSUCCESSFUL;
status = map_nt_error_from_unix(errno);
if (NT_STATUS_EQUAL(status,
NT_STATUS_NOT_SUPPORTED)) {
- log_lev = 5;
+ log_lev = DBGLVL_INFO;
}
}
DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
}
if (max_out_len < *out_len) {
- DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
- max_out_len, *out_len));
+ DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
+ max_out_len, *out_len);
TALLOC_FREE(shadow_data);
return NT_STATUS_BUFFER_TOO_SMALL;
}
cur_pdata += 12;
- DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
- shadow_data->num_volumes, fsp_str_dbg(fsp)));
+ DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
+ shadow_data->num_volumes, fsp_str_dbg(fsp));
if (labels && shadow_data->labels) {
for (i=0; i<shadow_data->num_volumes; i++) {
size_t len = 0;
return status;
}
cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
- DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
+ DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
}
}
uid_t uid;
size_t sid_len;
- DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
- fsp_fnum_dbg(fsp)));
+ DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
+ fsp_fnum_dbg(fsp));
if (in_len < 8) {
/* NT_STATUS_BUFFER_TOO_SMALL maybe? */
if (ret == -1) {
return NT_STATUS_INVALID_PARAMETER;
}
- DEBUGADD(10, ("for SID: %s\n",
+ DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
dom_sid_str_buf(&sid, &buf)));
if (!sid_to_uid(&sid, &uid)) {
- DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
+ DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
dom_sid_str_buf(&sid, &buf),
- (unsigned long)sid_len));
+ (unsigned long)sid_len);
uid = (-1);
}
char *out_data_tmp = NULL;
if (in_len != 16) {
- DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
- in_len));
+ DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
+ in_len);
return NT_STATUS_INVALID_PARAMETER;
}
if (max_out_len < 16) {
- DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
- max_out_len));
+ DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
+ max_out_len);
return NT_STATUS_INVALID_PARAMETER;
}
*out_len = 16;
out_data_tmp = talloc_array(ctx, char, *out_len);
if (out_data_tmp == NULL) {
- DEBUG(10, ("unable to allocate memory for response\n"));
+ DBG_DEBUG("unable to allocate memory for response\n");
return NT_STATUS_NO_MEMORY;
}
case FSCTL_IS_VOLUME_DIRTY:
{
- DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
- "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
+ DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
+ "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
/*
* http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
* says we have to respond with NT_STATUS_INVALID_PARAMETER
*/
if (!vfswrap_logged_ioctl_message) {
vfswrap_logged_ioctl_message = true;
- DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
- __func__, function));
+ DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
+ __func__, function);
}
}
struct tevent_req *subreq = NULL;
struct vfswrap_get_dos_attributes_state *state = NULL;
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
req = tevent_req_create(mem_ctx, &state,
struct vfswrap_get_dos_attributes_state);
if (req == NULL) {
.smb_fname = smb_fname,
};
+ if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
+ DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
+ "\"store dos attributes\" is disabled\n",
+ dir_fsp->conn->connectpath);
+ tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+ return tevent_req_post(req, ev);
+ }
+
subreq = SMB_VFS_GETXATTRAT_SEND(state,
ev,
dir_fsp,
{
bool offline;
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
if (offline) {
*dosmode |= FILE_ATTRIBUTE_OFFLINE;
struct files_struct *fsp,
uint32_t dosmode)
{
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
}
static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
+ uint32_t *flags,
+ uint64_t *xferlen,
DATA_BLOB *token)
{
struct vfswrap_offload_read_state *state = tevent_req_data(
return status;
}
+ *flags = 0;
+ *xferlen = 0;
token->length = state->token.length;
token->data = talloc_move(mem_ctx, &state->token.data);
state->dst_fsp = NULL;
}
+static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
static struct tevent_req *vfswrap_offload_write_send(
return tevent_req_post(req, ev);
}
+ status = vfswrap_offload_copy_file_range(req);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
state->buf = talloc_array(state, uint8_t, num);
if (tevent_req_nomem(state->buf, req)) {
return tevent_req_post(req, ev);
return req;
}
+static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
+{
+ struct vfswrap_offload_write_state *state = tevent_req_data(
+ req, struct vfswrap_offload_write_state);
+ struct lock_struct lck;
+ ssize_t nwritten;
+ NTSTATUS status;
+ bool same_file;
+ bool ok;
+ static bool try_copy_file_range = true;
+
+ if (!try_copy_file_range) {
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ same_file = file_id_equal(&state->src_fsp->file_id,
+ &state->dst_fsp->file_id);
+ if (same_file &&
+ sys_io_ranges_overlap(state->remaining,
+ state->src_off,
+ state->remaining,
+ state->dst_off))
+ {
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ if (fsp_is_alternate_stream(state->src_fsp) ||
+ fsp_is_alternate_stream(state->dst_fsp))
+ {
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ init_strict_lock_struct(state->src_fsp,
+ state->src_fsp->op->global->open_persistent_id,
+ state->src_off,
+ state->remaining,
+ READ_LOCK,
+ lp_posix_cifsu_locktype(state->src_fsp),
+ &lck);
+
+ ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
+ state->src_fsp,
+ &lck);
+ if (!ok) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ ok = change_to_user_and_service_by_fsp(state->dst_fsp);
+ if (!ok) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ init_strict_lock_struct(state->dst_fsp,
+ state->dst_fsp->op->global->open_persistent_id,
+ state->dst_off,
+ state->remaining,
+ WRITE_LOCK,
+ lp_posix_cifsu_locktype(state->dst_fsp),
+ &lck);
+
+ ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
+ state->dst_fsp,
+ &lck);
+ if (!ok) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ while (state->remaining > 0) {
+ nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
+ &state->src_off,
+ fsp_get_io_fd(state->dst_fsp),
+ &state->dst_off,
+ state->remaining,
+ 0);
+ if (nwritten == -1) {
+ DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
+ "n [%jd] failed: %s\n",
+ fsp_str_dbg(state->src_fsp),
+ (intmax_t)state->src_off,
+ fsp_str_dbg(state->dst_fsp),
+ (intmax_t)state->dst_off,
+ (intmax_t)state->remaining,
+ strerror(errno));
+ switch (errno) {
+ case EOPNOTSUPP:
+ case ENOSYS:
+ try_copy_file_range = false;
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ break;
+ case EXDEV:
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ break;
+ default:
+ status = map_nt_error_from_unix(errno);
+ if (NT_STATUS_EQUAL(
+ status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
+ /* Avoid triggering the fallback */
+ status = NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+ }
+ return status;
+ }
+
+ if (state->remaining < nwritten) {
+ DBG_DEBUG("copy_file_range src [%s] dst [%s] "
+ "n [%jd] remaining [%jd]\n",
+ fsp_str_dbg(state->src_fsp),
+ fsp_str_dbg(state->dst_fsp),
+ (intmax_t)nwritten,
+ (intmax_t)state->remaining);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (nwritten == 0) {
+ break;
+ }
+ state->copied += nwritten;
+ state->remaining -= nwritten;
+ }
+
+ /*
+ * Tell the req cleanup function there's no need to call
+ * change_to_user_and_service_by_fsp() on the dst handle.
+ */
+ state->dst_fsp = NULL;
+ return NT_STATUS_OK;
+}
+
static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
state->src_off,
state->next_io_size,
READ_LOCK,
+ lp_posix_cifsu_locktype(state->src_fsp),
&read_lck);
ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
state->dst_off,
state->next_io_size,
WRITE_LOCK,
+ lp_posix_cifsu_locktype(state->dst_fsp),
&write_lck);
ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
START_PROFILE(syscall_unlinkat);
- if (is_named_stream(smb_fname)) {
- errno = ENOENT;
- goto out;
- }
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
result = unlinkat(fsp_get_pathref_fd(dirfsp),
smb_fname->base_name,
flags);
- out:
END_PROFILE(syscall_unlinkat);
return result;
}
if (fsp->fsp_flags.have_proc_fds) {
int fd = fsp_get_pathref_fd(fsp);
- const char *p = NULL;
- char buf[PATH_MAX];
+ struct sys_proc_fd_path_buf buf;
+
+ result = chmod(sys_proc_fd_path(fd, &buf), mode);
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p != NULL) {
- result = chmod(p, mode);
- } else {
- result = -1;
- }
END_PROFILE(syscall_fchmod);
return result;
}
if (fsp->fsp_flags.have_proc_fds) {
int fd = fsp_get_pathref_fd(fsp);
- const char *p = NULL;
- char buf[PATH_MAX];
+ struct sys_proc_fd_path_buf buf;
+
+ result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p != NULL) {
- result = chown(p, uid, gid);
- } else {
- result = -1;
- }
END_PROFILE(syscall_fchown);
return result;
}
START_PROFILE(syscall_fntimes);
- if (is_named_stream(fsp->fsp_name)) {
+ if (fsp_is_alternate_stream(fsp)) {
errno = ENOENT;
goto out;
}
if (fsp->fsp_flags.have_proc_fds) {
int fd = fsp_get_pathref_fd(fsp);
- const char *p = NULL;
- char buf[PATH_MAX];
+ struct sys_proc_fd_path_buf buf;
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p != NULL) {
- /*
- * The dirfd argument of utimensat is ignored when
- * pathname is an absolute path
- */
- result = utimensat(AT_FDCWD, p, times, 0);
- } else {
- result = -1;
- }
+ result = utimensat(AT_FDCWD,
+ sys_proc_fd_path(fd, &buf),
+ times,
+ 0);
goto out;
}
if (ret == 0) {
return 0;
}
- DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
- "error %d. Falling back to slow manual allocation\n", errno));
+ DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
+ "error %d. Falling back to slow manual allocation\n", errno);
/* available disk space is enough or not? */
space_avail =
return result;
}
-static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
- uint32_t share_access, uint32_t access_mask)
+static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
+ files_struct *fsp,
+ uint32_t share_access,
+ uint32_t access_mask)
{
- START_PROFILE(syscall_kernel_flock);
- kernel_flock(fsp_get_io_fd(fsp), share_access, access_mask);
- END_PROFILE(syscall_kernel_flock);
- return 0;
+ errno = ENOTSUP;
+ return -1;
}
static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
START_PROFILE(syscall_linux_setlease);
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
#ifdef HAVE_KERNEL_OPLOCKS_LINUX
result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
#else
START_PROFILE(syscall_symlinkat);
+ SMB_ASSERT(!is_named_stream(new_smb_fname));
+
result = symlinkat(link_target->base_name,
fsp_get_pathref_fd(dirfsp),
new_smb_fname->base_name);
START_PROFILE(syscall_readlinkat);
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
result = readlinkat(fsp_get_pathref_fd(dirfsp),
smb_fname->base_name,
buf,
START_PROFILE(syscall_linkat);
+ SMB_ASSERT(!is_named_stream(old_smb_fname));
+ SMB_ASSERT(!is_named_stream(new_smb_fname));
+
result = linkat(fsp_get_pathref_fd(srcfsp),
old_smb_fname->base_name,
fsp_get_pathref_fd(dstfsp),
START_PROFILE(syscall_mknodat);
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
smb_fname->base_name,
mode,
#ifdef HAVE_FCHFLAGS
int fd = fsp_get_pathref_fd(fsp);
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
if (!fsp->fsp_flags.is_pathref) {
return fchflags(fd, flags);
}
if (fsp->fsp_flags.have_proc_fds) {
- const char *p = NULL;
- char buf[PATH_MAX];
-
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p == NULL) {
- return -1;
- }
+ struct sys_proc_fd_path_buf buf;
- return chflags(p, flags);
+ return chflags(sys_proc_fd_path(fd, &buf), flags);
}
/*
{
uint64_t file_id;
- if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
- return psbuf->st_ex_file_id;
- }
-
if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
return (uint64_t)psbuf->st_ex_ino;
}
struct stream_struct *streams = *pstreams;
NTSTATUS status;
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
if (fsp->fsp_flags.is_directory) {
/*
* No default streams on directories
return NT_STATUS_OK;
}
-static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
- const struct smb_filename *path,
- const char *name,
- TALLOC_CTX *mem_ctx,
- char **found_name)
+static NTSTATUS vfswrap_get_real_filename_at(
+ struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const char *name,
+ TALLOC_CTX *mem_ctx,
+ char **found_name)
{
/*
* Don't fall back to get_real_filename so callers can differentiate
* between a full directory scan and an actual case-insensitive stat.
*/
- errno = EOPNOTSUPP;
- return -1;
+ return NT_STATUS_NOT_SUPPORTED;
}
static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
const struct smb_filename *smb_fname)
{
return handle->conn->connectpath;
NTSTATUS result;
START_PROFILE(fget_nt_acl);
+
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
result = posix_fget_nt_acl(fsp, security_info,
mem_ctx, ppdesc);
END_PROFILE(fget_nt_acl);
NTSTATUS result;
START_PROFILE(fset_nt_acl);
+
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
result = set_nt_acl(fsp, security_info_sent, psd);
END_PROFILE(fset_nt_acl);
return result;
SMB_ACL_TYPE_T type,
TALLOC_CTX *mem_ctx)
{
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
return sys_acl_get_fd(handle, fsp, type, mem_ctx);
}
SMB_ACL_TYPE_T type,
SMB_ACL_T theacl)
{
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
return sys_acl_set_fd(handle, fsp, type, theacl);
}
static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
files_struct *fsp)
{
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
return sys_acl_delete_def_fd(handle, fsp);
}
Extended attribute operations.
*****************************************************************/
-static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- const char *name,
- void *value,
- size_t size)
+static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name,
+ void *value,
+ size_t size)
{
- return getxattr(smb_fname->base_name, name, value, size);
+ int fd = fsp_get_pathref_fd(fsp);
+
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+ if (!fsp->fsp_flags.is_pathref) {
+ return fgetxattr(fd, name, value, size);
+ }
+
+ if (fsp->fsp_flags.have_proc_fds) {
+ struct sys_proc_fd_path_buf buf;
+
+ return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
+ }
+
+ /*
+ * This is no longer a handle based call.
+ */
+ return getxattr(fsp->fsp_name->base_name, name, value, size);
}
struct vfswrap_getxattrat_state {
struct tevent_context *ev;
+ struct vfs_handle_struct *handle;
files_struct *dir_fsp;
const struct smb_filename *smb_fname;
bool have_per_thread_creds = false;
bool do_async = false;
+ SMB_ASSERT(!is_named_stream(smb_fname));
+
req = tevent_req_create(mem_ctx, &state,
struct vfswrap_getxattrat_state);
if (req == NULL) {
}
*state = (struct vfswrap_getxattrat_state) {
.ev = ev,
+ .handle = handle,
.dir_fsp = dir_fsp,
.smb_fname = smb_fname,
};
/*
* Now allocate all parameters from a memory context that won't go away
- * no matter what. These paremeters will get used in threads and we
+ * no matter what. These parameters will get used in threads and we
* can't reliably cancel threads, so all buffers passed to the threads
* must not be freed before all referencing threads terminate.
*/
{
struct vfswrap_getxattrat_state *state = tevent_req_data(
req, struct vfswrap_getxattrat_state);
- char *path = NULL;
- char *tofree = NULL;
- char pathbuf[PATH_MAX+1];
- ssize_t pathlen;
- int err;
-
- pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
- state->smb_fname->base_name,
- pathbuf,
- sizeof(pathbuf),
- &path,
- &tofree);
- if (pathlen == -1) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- state->xattr_size = getxattr(path,
- state->xattr_name,
- state->xattr_value,
- talloc_array_length(state->xattr_value));
- err = errno;
- TALLOC_FREE(tofree);
+ state->xattr_size = vfswrap_fgetxattr(state->handle,
+ state->smb_fname->fsp,
+ state->xattr_name,
+ state->xattr_value,
+ talloc_array_length(state->xattr_value));
if (state->xattr_size == -1) {
- tevent_req_error(req, err);
+ tevent_req_error(req, errno);
return;
}
goto end_profile;
}
- ret = fchdir(fsp_get_pathref_fd(state->dir_fsp));
- if (ret == -1) {
- state->xattr_size = -1;
- state->vfs_aio_state.error = errno;
- goto end_profile;
- }
-
- state->xattr_size = getxattr(state->name,
- state->xattr_name,
- state->xattr_value,
- talloc_array_length(state->xattr_value));
+ state->xattr_size = vfswrap_fgetxattr(state->handle,
+ state->smb_fname->fsp,
+ state->xattr_name,
+ state->xattr_value,
+ talloc_array_length(state->xattr_value));
if (state->xattr_size == -1) {
state->vfs_aio_state.error = errno;
}
return xattr_size;
}
-static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp,
- const char *name,
- void *value,
- size_t size)
-{
- int fd = fsp_get_pathref_fd(fsp);
-
- if (!fsp->fsp_flags.is_pathref) {
- return fgetxattr(fd, name, value, size);
- }
-
- if (fsp->fsp_flags.have_proc_fds) {
- const char *p = NULL;
- char buf[PATH_MAX];
-
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p == NULL) {
- return -1;
- }
-
- return getxattr(p, name, value, size);
- }
-
- /*
- * This is no longer a handle based call.
- */
- return getxattr(fsp->fsp_name->base_name, name, value, size);
-}
-
static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
{
int fd = fsp_get_pathref_fd(fsp);
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
if (!fsp->fsp_flags.is_pathref) {
return flistxattr(fd, list, size);
}
if (fsp->fsp_flags.have_proc_fds) {
- const char *p = NULL;
- char buf[PATH_MAX];
-
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p == NULL) {
- return -1;
- }
+ struct sys_proc_fd_path_buf buf;
- return listxattr(p, list, size);
+ return listxattr(sys_proc_fd_path(fd, &buf), list, size);
}
/*
{
int fd = fsp_get_pathref_fd(fsp);
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
if (!fsp->fsp_flags.is_pathref) {
return fremovexattr(fd, name);
}
if (fsp->fsp_flags.have_proc_fds) {
- const char *p = NULL;
- char buf[PATH_MAX];
+ struct sys_proc_fd_path_buf buf;
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p == NULL) {
- return -1;
- }
-
- return removexattr(p, name);
+ return removexattr(sys_proc_fd_path(fd, &buf), name);
}
/*
{
int fd = fsp_get_pathref_fd(fsp);
+ SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
if (!fsp->fsp_flags.is_pathref) {
return fsetxattr(fd, name, value, size, flags);
}
if (fsp->fsp_flags.have_proc_fds) {
- const char *p = NULL;
- char buf[PATH_MAX];
-
- p = sys_proc_fd_path(fd, buf, sizeof(buf));
- if (p == NULL) {
- return -1;
- }
+ struct sys_proc_fd_path_buf buf;
- return setxattr(p, name, value, size, flags);
+ return setxattr(sys_proc_fd_path(fd, &buf),
+ name,
+ value,
+ size,
+ flags);
}
/*
.fdopendir_fn = vfswrap_fdopendir,
.readdir_fn = vfswrap_readdir,
.freaddir_attr_fn = vfswrap_freaddir_attr,
- .seekdir_fn = vfswrap_seekdir,
- .telldir_fn = vfswrap_telldir,
.rewind_dir_fn = vfswrap_rewinddir,
.mkdirat_fn = vfswrap_mkdirat,
.closedir_fn = vfswrap_closedir,
.stat_fn = vfswrap_stat,
.fstat_fn = vfswrap_fstat,
.lstat_fn = vfswrap_lstat,
+ .fstatat_fn = vfswrap_fstatat,
.get_alloc_size_fn = vfswrap_get_alloc_size,
.unlinkat_fn = vfswrap_unlinkat,
.fchmod_fn = vfswrap_fchmod,
.ftruncate_fn = vfswrap_ftruncate,
.fallocate_fn = vfswrap_fallocate,
.lock_fn = vfswrap_lock,
- .kernel_flock_fn = vfswrap_kernel_flock,
+ .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
.fcntl_fn = vfswrap_fcntl,
.linux_setlease_fn = vfswrap_linux_setlease,
.getlock_fn = vfswrap_getlock,
.file_id_create_fn = vfswrap_file_id_create,
.fs_file_id_fn = vfswrap_fs_file_id,
.fstreaminfo_fn = vfswrap_fstreaminfo,
- .get_real_filename_fn = vfswrap_get_real_filename,
+ .get_real_filename_at_fn = vfswrap_get_real_filename_at,
.connectpath_fn = vfswrap_connectpath,
.brl_lock_windows_fn = vfswrap_brl_lock_windows,
.brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
.sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
/* EA operations. */
- .getxattr_fn = vfswrap_getxattr,
.getxattrat_send_fn = vfswrap_getxattrat_send,
.getxattrat_recv_fn = vfswrap_getxattrat_recv,
.fgetxattr_fn = vfswrap_fgetxattr,