#include "source3/include/msdfs.h"
#include "librpc/gen_ndr/ndr_dfsblobs.h"
#include "lib/util/tevent_unix.h"
-#include "lib/asys/asys.h"
#include "lib/util/tevent_ntstatus.h"
#include "lib/util/sys_rw.h"
+#include "lib/pthreadpool/pthreadpool_tevent.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
* use when setting a timestamp. */
smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
- NULL, NULL);
+ NULL, NULL, 0);
if (smb_fname_cpath == NULL) {
return caps;
}
/* The following call can change cwd. */
status = get_referred_path(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)) {
/* Directory operations */
-static DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32_t attr)
+static DIR *vfswrap_opendir(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ const char *mask,
+ uint32_t attr)
{
DIR *result;
START_PROFILE(syscall_opendir);
- result = opendir(fname);
+ result = opendir(smb_fname->base_name);
END_PROFILE(syscall_opendir);
return result;
}
if (result != NULL) {
/* See if we can efficiently return this. */
struct stat st;
- int flags = (lp_posix_pathnames() ?
- AT_SYMLINK_NOFOLLOW : 0);
+ int flags = AT_SYMLINK_NOFOLLOW;
int ret = fstatat(dirfd(dirp),
result->d_name,
&st,
flags);
- if (ret == 0) {
+ /*
+ * As this is an optimization,
+ * ignore it if we stat'ed a
+ * symlink. Make the caller
+ * do it again as we don't
+ * know if they wanted the link
+ * info, or its target info.
+ */
+ if ((ret == 0) && (!S_ISLNK(st.st_mode))) {
init_stat_ex_from_stat(sbuf,
&st,
lp_fake_directory_create_times(
END_PROFILE(syscall_rewinddir);
}
-static int vfswrap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
+static int vfswrap_mkdir(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ mode_t mode)
{
int result;
bool has_dacl = False;
+ const char *path = smb_fname->base_name;
char *parent = NULL;
START_PROFILE(syscall_mkdir);
* mess up any inherited ACL bits that were set. JRA.
*/
int saved_errno = errno; /* We may get ENOSYS */
- if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
+ if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
+ (errno == ENOSYS)) {
errno = saved_errno;
+ }
}
END_PROFILE(syscall_mkdir);
return result;
}
-static int vfswrap_rmdir(vfs_handle_struct *handle, const char *path)
+static int vfswrap_rmdir(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
{
int result;
START_PROFILE(syscall_rmdir);
- result = rmdir(path);
+ result = rmdir(smb_fname->base_name);
END_PROFILE(syscall_rmdir);
return result;
}
const struct smb2_create_blobs *in_context_blobs,
struct smb2_create_blobs *out_context_blobs)
{
- struct smb2_create_blob *svhdx = NULL;
-
- /*
- * It might be empty ... and smb2_create_blob_find does not handle that
- */
- if (in_context_blobs) {
- svhdx = smb2_create_blob_find(in_context_blobs,
- SVHDX_OPEN_DEVICE_CONTEXT);
- }
-
- if (svhdx != NULL) {
- /* SharedVHD is not yet supported */
- DEBUG(10, ("Shared VHD not yet supported, INVALID_DEVICE_REQUEST\n"));
- return NT_STATUS_INVALID_DEVICE_REQUEST;
- }
-
return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
access_mask, share_access,
create_disposition, create_options,
return result;
}
-static void vfswrap_asys_finished(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags, void *p);
-
-static bool vfswrap_init_asys_ctx(struct smbd_server_connection *conn)
+static int vfswrap_init_pool(struct smbd_server_connection *conn)
{
- struct asys_context *ctx;
- struct tevent_fd *fde;
int ret;
- int fd;
-
- if (conn->asys_ctx != NULL) {
- return true;
- }
-
- ret = asys_context_init(&ctx, lp_aio_max_threads());
- if (ret != 0) {
- DEBUG(1, ("asys_context_init failed: %s\n", strerror(ret)));
- return false;
- }
- fd = asys_signalfd(ctx);
-
- ret = set_blocking(fd, false);
- if (ret != 0) {
- DBG_WARNING("set_blocking failed: %s\n", strerror(errno));
- goto fail;
- }
-
- fde = tevent_add_fd(conn->ev_ctx, conn, fd, TEVENT_FD_READ,
- vfswrap_asys_finished, ctx);
- if (fde == NULL) {
- DEBUG(1, ("tevent_add_fd failed\n"));
- goto fail;
+ if (conn->pool != NULL) {
+ return 0;
}
- conn->asys_ctx = ctx;
- conn->asys_fde = fde;
- return true;
-
-fail:
- asys_context_destroy(ctx);
- return false;
+ ret = pthreadpool_tevent_init(conn, lp_aio_max_threads(),
+ &conn->pool);
+ return ret;
}
-struct vfswrap_asys_state {
- struct asys_context *asys_ctx;
- struct tevent_req *req;
+struct vfswrap_pread_state {
ssize_t ret;
int err;
- SMBPROFILE_BASIC_ASYNC_STATE(profile_basic);
+ int fd;
+ void *buf;
+ size_t count;
+ off_t offset;
+
+ struct vfs_aio_state vfs_aio_state;
SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
};
-static int vfswrap_asys_state_destructor(struct vfswrap_asys_state *s)
-{
- asys_cancel(s->asys_ctx, s->req);
- return 0;
-}
+static void vfs_pread_do(void *private_data);
+static void vfs_pread_done(struct tevent_req *subreq);
static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
void *data,
size_t n, off_t offset)
{
- struct tevent_req *req;
- struct vfswrap_asys_state *state;
+ struct tevent_req *req, *subreq;
+ struct vfswrap_pread_state *state;
int ret;
- req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
+ req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
if (req == NULL) {
return NULL;
}
- if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
- tevent_req_oom(req);
+
+ ret = vfswrap_init_pool(handle->conn->sconn);
+ if (tevent_req_error(req, ret)) {
return tevent_req_post(req, ev);
}
- state->asys_ctx = handle->conn->sconn->asys_ctx;
- state->req = req;
+
+ state->ret = -1;
+ state->fd = fsp->fh->fd;
+ state->buf = data;
+ state->count = n;
+ state->offset = offset;
SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
state->profile_bytes, n);
- ret = asys_pread(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
- if (ret != 0) {
- tevent_req_error(req, ret);
+ SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
+
+ subreq = pthreadpool_tevent_job_send(
+ state, ev, handle->conn->sconn->pool,
+ vfs_pread_do, state);
+ if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- talloc_set_destructor(state, vfswrap_asys_state_destructor);
+ tevent_req_set_callback(subreq, vfs_pread_done, req);
return req;
}
+static void vfs_pread_do(void *private_data)
+{
+ struct vfswrap_pread_state *state = talloc_get_type_abort(
+ private_data, struct vfswrap_pread_state);
+ struct timespec start_time;
+ struct timespec end_time;
+
+ SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
+
+ PROFILE_TIMESTAMP(&start_time);
+
+ do {
+ state->ret = pread(state->fd, state->buf, state->count,
+ state->offset);
+ } while ((state->ret == -1) && (errno == EINTR));
+
+ state->err = errno;
+
+ PROFILE_TIMESTAMP(&end_time);
+
+ state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
+
+ SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
+}
+
+static void vfs_pread_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+#ifdef WITH_PROFILE
+ struct vfswrap_pread_state *state = tevent_req_data(
+ req, struct vfswrap_pread_state);
+#endif
+ int ret;
+
+ ret = pthreadpool_tevent_job_recv(subreq);
+ TALLOC_FREE(subreq);
+ SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static ssize_t vfswrap_pread_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct vfswrap_pread_state *state = tevent_req_data(
+ req, struct vfswrap_pread_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
+struct vfswrap_pwrite_state {
+ ssize_t ret;
+ int err;
+ int fd;
+ const void *buf;
+ size_t count;
+ off_t offset;
+
+ struct vfs_aio_state vfs_aio_state;
+ SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
+};
+
+static void vfs_pwrite_do(void *private_data);
+static void vfs_pwrite_done(struct tevent_req *subreq);
+
static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
const void *data,
size_t n, off_t offset)
{
- struct tevent_req *req;
- struct vfswrap_asys_state *state;
+ struct tevent_req *req, *subreq;
+ struct vfswrap_pwrite_state *state;
int ret;
- req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
+ req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
if (req == NULL) {
return NULL;
}
- if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
- tevent_req_oom(req);
+
+ ret = vfswrap_init_pool(handle->conn->sconn);
+ if (tevent_req_error(req, ret)) {
return tevent_req_post(req, ev);
}
- state->asys_ctx = handle->conn->sconn->asys_ctx;
- state->req = req;
+
+ state->ret = -1;
+ state->fd = fsp->fh->fd;
+ state->buf = data;
+ state->count = n;
+ state->offset = offset;
SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
state->profile_bytes, n);
- ret = asys_pwrite(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
- if (ret != 0) {
- tevent_req_error(req, ret);
+ SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
+
+ subreq = pthreadpool_tevent_job_send(
+ state, ev, handle->conn->sconn->pool,
+ vfs_pwrite_do, state);
+ if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- talloc_set_destructor(state, vfswrap_asys_state_destructor);
+ tevent_req_set_callback(subreq, vfs_pwrite_done, req);
return req;
}
+static void vfs_pwrite_do(void *private_data)
+{
+ struct vfswrap_pwrite_state *state = talloc_get_type_abort(
+ private_data, struct vfswrap_pwrite_state);
+ struct timespec start_time;
+ struct timespec end_time;
+
+ SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
+
+ PROFILE_TIMESTAMP(&start_time);
+
+ do {
+ state->ret = pwrite(state->fd, state->buf, state->count,
+ state->offset);
+ } while ((state->ret == -1) && (errno == EINTR));
+
+ state->err = errno;
+
+ PROFILE_TIMESTAMP(&end_time);
+
+ state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
+
+ SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
+}
+
+static void vfs_pwrite_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+#ifdef WITH_PROFILE
+ struct vfswrap_pwrite_state *state = tevent_req_data(
+ req, struct vfswrap_pwrite_state);
+#endif
+ int ret;
+
+ ret = pthreadpool_tevent_job_recv(subreq);
+ TALLOC_FREE(subreq);
+ SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct vfswrap_pwrite_state *state = tevent_req_data(
+ req, struct vfswrap_pwrite_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
+struct vfswrap_fsync_state {
+ ssize_t ret;
+ int err;
+ int fd;
+
+ struct vfs_aio_state vfs_aio_state;
+ SMBPROFILE_BASIC_ASYNC_STATE(profile_basic);
+};
+
+static void vfs_fsync_do(void *private_data);
+static void vfs_fsync_done(struct tevent_req *subreq);
+
static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct files_struct *fsp)
{
- struct tevent_req *req;
- struct vfswrap_asys_state *state;
+ struct tevent_req *req, *subreq;
+ struct vfswrap_fsync_state *state;
int ret;
- req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
+ req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
if (req == NULL) {
return NULL;
}
- if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
- tevent_req_oom(req);
+
+ ret = vfswrap_init_pool(handle->conn->sconn);
+ if (tevent_req_error(req, ret)) {
return tevent_req_post(req, ev);
}
- state->asys_ctx = handle->conn->sconn->asys_ctx;
- state->req = req;
+
+ state->ret = -1;
+ state->fd = fsp->fh->fd;
SMBPROFILE_BASIC_ASYNC_START(syscall_asys_fsync, profile_p,
state->profile_basic);
- ret = asys_fsync(state->asys_ctx, fsp->fh->fd, req);
- if (ret != 0) {
- tevent_req_error(req, ret);
+
+ subreq = pthreadpool_tevent_job_send(
+ state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
+ if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- talloc_set_destructor(state, vfswrap_asys_state_destructor);
+ tevent_req_set_callback(subreq, vfs_fsync_done, req);
return req;
}
-static void vfswrap_asys_finished(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags, void *p)
+static void vfs_fsync_do(void *private_data)
{
- struct asys_context *asys_ctx = (struct asys_context *)p;
- struct asys_result results[get_outstanding_aio_calls()];
- int i, ret;
+ struct vfswrap_fsync_state *state = talloc_get_type_abort(
+ private_data, struct vfswrap_fsync_state);
+ struct timespec start_time;
+ struct timespec end_time;
- if ((flags & TEVENT_FD_READ) == 0) {
- return;
- }
+ PROFILE_TIMESTAMP(&start_time);
- ret = asys_results(asys_ctx, results, get_outstanding_aio_calls());
- if (ret < 0) {
- DEBUG(1, ("asys_results returned %s\n", strerror(-ret)));
- return;
- }
+ do {
+ state->ret = fsync(state->fd);
+ } while ((state->ret == -1) && (errno == EINTR));
- for (i=0; i<ret; i++) {
- struct asys_result *result = &results[i];
- struct tevent_req *req;
- struct vfswrap_asys_state *state;
+ state->err = errno;
- if ((result->ret == -1) && (result->err == ECANCELED)) {
- continue;
- }
-
- req = talloc_get_type_abort(result->private_data,
- struct tevent_req);
- state = tevent_req_data(req, struct vfswrap_asys_state);
+ PROFILE_TIMESTAMP(&end_time);
- talloc_set_destructor(state, NULL);
-
- SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
- SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
- state->ret = result->ret;
- state->err = result->err;
- tevent_req_defer_callback(req, ev);
- tevent_req_done(req);
- }
+ state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
}
-static ssize_t vfswrap_asys_ssize_t_recv(struct tevent_req *req, int *err)
+static void vfs_fsync_done(struct tevent_req *subreq)
{
- struct vfswrap_asys_state *state = tevent_req_data(
- req, struct vfswrap_asys_state);
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+#ifdef WITH_PROFILE
+ struct vfswrap_fsync_state *state = tevent_req_data(
+ req, struct vfswrap_fsync_state);
+#endif
+ int ret;
- if (tevent_req_is_unix_error(req, err)) {
- return -1;
+ ret = pthreadpool_tevent_job_recv(subreq);
+ TALLOC_FREE(subreq);
+ SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
+ if (tevent_req_error(req, ret)) {
+ return;
}
- *err = state->err;
- return state->ret;
+
+ tevent_req_done(req);
}
-static int vfswrap_asys_int_recv(struct tevent_req *req, int *err)
+static int vfswrap_fsync_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
{
- struct vfswrap_asys_state *state = tevent_req_data(
- req, struct vfswrap_asys_state);
+ struct vfswrap_fsync_state *state = tevent_req_data(
+ req, struct vfswrap_fsync_state);
- if (tevent_req_is_unix_error(req, err)) {
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
return -1;
}
- *err = state->err;
+
+ *vfs_aio_state = state->vfs_aio_state;
return state->ret;
}
return NT_STATUS_NOT_SUPPORTED;
}
+static bool vfswrap_is_offline(struct vfs_handle_struct *handle,
+ const struct smb_filename *fname,
+ SMB_STRUCT_STAT *sbuf);
+
+static NTSTATUS vfswrap_get_dos_attributes(struct vfs_handle_struct *handle,
+ struct smb_filename *smb_fname,
+ uint32_t *dosmode)
+{
+ bool offline;
+
+ offline = vfswrap_is_offline(handle, smb_fname, &smb_fname->st);
+ if (offline) {
+ *dosmode |= FILE_ATTRIBUTE_OFFLINE;
+ }
+
+ return get_ea_dos_attribute(handle->conn, smb_fname, dosmode);
+}
+
+static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t *dosmode)
+{
+ bool offline;
+
+ offline = vfswrap_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st);
+ if (offline) {
+ *dosmode |= FILE_ATTRIBUTE_OFFLINE;
+ }
+
+ return get_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
+}
+
+static NTSTATUS vfswrap_set_dos_attributes(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uint32_t dosmode)
+{
+ return set_ea_dos_attribute(handle->conn, smb_fname, dosmode);
+}
+
+static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t dosmode)
+{
+ return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
+}
+
struct vfs_cc_state {
- off_t copied;
+ struct tevent_context *ev;
uint8_t *buf;
+ bool read_lck_locked;
+ struct lock_struct read_lck;
+ bool write_lck_locked;
+ struct lock_struct write_lck;
+ struct files_struct *src_fsp;
+ off_t src_off;
+ struct files_struct *dst_fsp;
+ off_t dst_off;
+ off_t to_copy;
+ off_t remaining;
+ size_t next_io_size;
+ uint32_t flags;
};
+static NTSTATUS copy_chunk_loop(struct tevent_req *req);
+
static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
off_t src_off,
struct files_struct *dest_fsp,
off_t dest_off,
- off_t num)
+ off_t to_copy,
+ uint32_t flags)
{
struct tevent_req *req;
- struct vfs_cc_state *vfs_cc_state;
+ struct vfs_cc_state *state = NULL;
+ size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
NTSTATUS status;
- DEBUG(10, ("performing server side copy chunk of length %lu\n",
- (unsigned long)num));
+ DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
- req = tevent_req_create(mem_ctx, &vfs_cc_state, struct vfs_cc_state);
+ req = tevent_req_create(mem_ctx, &state, struct vfs_cc_state);
if (req == NULL) {
return NULL;
}
- vfs_cc_state->buf = talloc_array(vfs_cc_state, uint8_t,
- MIN(num, 8*1024*1024));
- if (tevent_req_nomem(vfs_cc_state->buf, req)) {
+ if (flags & ~VFS_COPY_CHUNK_FL_MASK_ALL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (flags & VFS_COPY_CHUNK_FL_MUST_CLONE) {
+ DEBUG(10, ("COW clones not supported by vfs_default\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ *state = (struct vfs_cc_state) {
+ .ev = ev,
+ .src_fsp = src_fsp,
+ .src_off = src_off,
+ .dst_fsp = dest_fsp,
+ .dst_off = dest_off,
+ .to_copy = to_copy,
+ .remaining = to_copy,
+ .flags = flags,
+ };
+ state->buf = talloc_array(state, uint8_t, num);
+ if (tevent_req_nomem(state->buf, req)) {
return tevent_req_post(req, ev);
}
return tevent_req_post(req, ev);
}
- /* could use 2.6.33+ sendfile here to do this in kernel */
- while (vfs_cc_state->copied < num) {
- ssize_t ret;
- struct lock_struct lck;
- int saved_errno;
+ if (src_fsp->op == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
+ if (dest_fsp->op == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
+ status = copy_chunk_loop(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
- off_t this_num = MIN(talloc_array_length(vfs_cc_state->buf),
- num - vfs_cc_state->copied);
+ return req;
+}
- if (src_fsp->op == NULL) {
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return tevent_req_post(req, ev);
- }
- init_strict_lock_struct(src_fsp,
- src_fsp->op->global->open_persistent_id,
- src_off,
- this_num,
+static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq);
+
+static NTSTATUS copy_chunk_loop(struct tevent_req *req)
+{
+ struct vfs_cc_state *state = tevent_req_data(req, struct vfs_cc_state);
+ struct tevent_req *subreq = NULL;
+ bool ok;
+
+ state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
+
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ init_strict_lock_struct(state->src_fsp,
+ state->src_fsp->op->global->open_persistent_id,
+ state->src_off,
+ state->next_io_size,
READ_LOCK,
- &lck);
+ &state->read_lck);
- if (!SMB_VFS_STRICT_LOCK(src_fsp->conn, src_fsp, &lck)) {
- tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
- return tevent_req_post(req, ev);
+ ok = SMB_VFS_STRICT_LOCK(state->src_fsp->conn,
+ state->src_fsp,
+ &state->read_lck);
+ if (!ok) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
}
+ }
- ret = SMB_VFS_PREAD(src_fsp, vfs_cc_state->buf,
- this_num, src_off);
- if (ret == -1) {
- saved_errno = errno;
- }
+ subreq = SMB_VFS_PREAD_SEND(state,
+ state->src_fsp->conn->sconn->ev_ctx,
+ state->src_fsp,
+ state->buf,
+ state->next_io_size,
+ state->src_off);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, vfswrap_copy_chunk_read_done, req);
- SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &lck);
+ return NT_STATUS_OK;
+}
- if (ret == -1) {
- errno = saved_errno;
- tevent_req_nterror(req, map_nt_error_from_unix(errno));
- return tevent_req_post(req, ev);
- }
- if (ret != this_num) {
- /* zero tolerance for short reads */
- tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
- return tevent_req_post(req, ev);
- }
+static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq);
- src_off += ret;
+static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct vfs_cc_state *state = tevent_req_data(req, struct vfs_cc_state);
+ struct vfs_aio_state aio_state;
+ ssize_t nread;
+ bool ok;
- if (dest_fsp->op == NULL) {
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return tevent_req_post(req, ev);
- }
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ SMB_VFS_STRICT_UNLOCK(state->src_fsp->conn,
+ state->src_fsp,
+ &state->read_lck);
+ ZERO_STRUCT(state->read_lck);
+ }
+
+ nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
+ TALLOC_FREE(subreq);
+ if (nread == -1) {
+ DBG_ERR("read failed: %s\n", strerror(errno));
+ tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
+ return;
+ }
+ if (nread != state->next_io_size) {
+ DBG_ERR("Short read, only %zd of %zu\n",
+ nread, state->next_io_size);
+ tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
+ return;
+ }
- init_strict_lock_struct(dest_fsp,
- dest_fsp->op->global->open_persistent_id,
- dest_off,
- this_num,
+ state->src_off += nread;
+
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ init_strict_lock_struct(state->dst_fsp,
+ state->dst_fsp->op->global->open_persistent_id,
+ state->dst_off,
+ state->next_io_size,
WRITE_LOCK,
- &lck);
+ &state->write_lck);
- if (!SMB_VFS_STRICT_LOCK(dest_fsp->conn, dest_fsp, &lck)) {
+ ok = SMB_VFS_STRICT_LOCK(state->dst_fsp->conn,
+ state->dst_fsp,
+ &state->write_lck);
+ if (!ok) {
tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
- return tevent_req_post(req, ev);
+ return;
}
+ }
- ret = SMB_VFS_PWRITE(dest_fsp, vfs_cc_state->buf,
- this_num, dest_off);
- if (ret == -1) {
- saved_errno = errno;
- }
+ subreq = SMB_VFS_PWRITE_SEND(state,
+ state->ev,
+ state->dst_fsp,
+ state->buf,
+ state->next_io_size,
+ state->dst_off);
+ if (subreq == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ tevent_req_set_callback(subreq, vfswrap_copy_chunk_write_done, req);
+}
- SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &lck);
+static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct vfs_cc_state *state = tevent_req_data(req, struct vfs_cc_state);
+ struct vfs_aio_state aio_state;
+ ssize_t nwritten;
+ NTSTATUS status;
- if (ret == -1) {
- errno = saved_errno;
- tevent_req_nterror(req, map_nt_error_from_unix(errno));
- return tevent_req_post(req, ev);
- }
- if (ret != this_num) {
- /* zero tolerance for short writes */
- tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
- return tevent_req_post(req, ev);
- }
- dest_off += ret;
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ SMB_VFS_STRICT_UNLOCK(state->dst_fsp->conn,
+ state->dst_fsp,
+ &state->write_lck);
+ ZERO_STRUCT(state->write_lck);
+ }
+
+ nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ DBG_ERR("write failed: %s\n", strerror(errno));
+ tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
+ return;
+ }
+ if (nwritten != state->next_io_size) {
+ DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
+ tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
+ return;
+ }
- vfs_cc_state->copied += this_num;
+ state->dst_off += nwritten;
+
+ if (state->remaining < nwritten) {
+ /* Paranoia check */
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+ state->remaining -= nwritten;
+ if (state->remaining == 0) {
+ tevent_req_done(req);
+ return;
}
- tevent_req_done(req);
- return tevent_req_post(req, ev);
+ status = copy_chunk_loop(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ return;
}
static NTSTATUS vfswrap_copy_chunk_recv(struct vfs_handle_struct *handle,
struct tevent_req *req,
off_t *copied)
{
- struct vfs_cc_state *vfs_cc_state = tevent_req_data(req,
- struct vfs_cc_state);
+ struct vfs_cc_state *state = tevent_req_data(req, struct vfs_cc_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
- DEBUG(2, ("server side copy chunk failed: %s\n",
- nt_errstr(status)));
+ DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
*copied = 0;
tevent_req_received(req);
return status;
}
- *copied = vfs_cc_state->copied;
- DEBUG(10, ("server side copy chunk copied %lu\n",
- (unsigned long)*copied));
+ *copied = state->to_copy;
+ DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
tevent_req_received(req);
return NT_STATUS_OK;
return result;
}
-static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+static int vfswrap_chmod(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ mode_t mode)
{
int result;
{
int saved_errno = errno; /* We might get ENOSYS */
- if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
+ result = SMB_VFS_CHMOD_ACL(handle->conn,
+ smb_fname,
+ mode);
+ if (result == 0) {
END_PROFILE(syscall_chmod);
return result;
}
errno = saved_errno;
}
- result = chmod(path, mode);
+ result = chmod(smb_fname->base_name, mode);
END_PROFILE(syscall_chmod);
return result;
}
return result;
}
-static int vfswrap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+static int vfswrap_chown(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uid_t uid,
+ gid_t gid)
{
int result;
START_PROFILE(syscall_chown);
- result = chown(path, uid, gid);
+ result = chown(smb_fname->base_name, uid, gid);
END_PROFILE(syscall_chown);
return result;
}
#endif
}
-static int vfswrap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+static int vfswrap_lchown(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uid_t uid,
+ gid_t gid)
{
int result;
START_PROFILE(syscall_lchown);
- result = lchown(path, uid, gid);
+ result = lchown(smb_fname->base_name, uid, gid);
END_PROFILE(syscall_lchown);
return result;
}
"error %d. Falling back to slow manual allocation\n", errno));
/* available disk space is enough or not? */
- space_avail = get_dfree_info(fsp->conn,
- fsp->fsp_name->base_name,
- &bsize, &dfree, &dsize);
+ space_avail =
+ get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
/* space_avail is 1k blocks */
if (space_avail == (uint64_t)-1 ||
((uint64_t)space_to_write/1024 > space_avail) ) {
bool result;
START_PROFILE(syscall_fcntl_lock);
+
+ if (fsp->use_ofd_locks || !lp_parm_bool(SNUM(fsp->conn),
+ "smbd",
+ "force process locks",
+ false)) {
+ op = map_process_lock_to_ofd_lock(op, &fsp->use_ofd_locks);
+ }
+
result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
END_PROFILE(syscall_fcntl_lock);
return result;
static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
{
bool result;
+ int op = F_GETLK;
START_PROFILE(syscall_fcntl_getlock);
- result = fcntl_getlock(fsp->fh->fd, poffset, pcount, ptype, ppid);
+
+ if (fsp->use_ofd_locks || !lp_parm_bool(SNUM(fsp->conn),
+ "smbd",
+ "force process locks",
+ false)) {
+ op = map_process_lock_to_ofd_lock(op, &fsp->use_ofd_locks);
+ }
+
+ result = fcntl_getlock(fsp->fh->fd, op, poffset, pcount, ptype, ppid);
END_PROFILE(syscall_fcntl_getlock);
return result;
}
char *result;
START_PROFILE(syscall_realpath);
-#ifdef REALPATH_TAKES_NULL
- result = realpath(path, NULL);
-#else
- result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
- if (result) {
- char *resolved_path = realpath(path, result);
- if (!resolved_path) {
- SAFE_FREE(result);
- } else {
- /* SMB_ASSERT(result == resolved_path) ? */
- result = resolved_path;
- }
- }
-#endif
+ result = sys_realpath(path);
END_PROFILE(syscall_realpath);
return result;
}
static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
struct files_struct *fsp,
- const char *fname,
+ const struct smb_filename *smb_fname,
TALLOC_CTX *mem_ctx,
unsigned int *pnum_streams,
struct stream_struct **pstreams)
ret = SMB_VFS_FSTAT(fsp, &sbuf);
}
else {
- struct smb_filename smb_fname;
+ struct smb_filename smb_fname_cp;
- ZERO_STRUCT(smb_fname);
- smb_fname.base_name = discard_const_p(char, fname);
+ ZERO_STRUCT(smb_fname_cp);
+ smb_fname_cp.base_name = discard_const_p(char,
+ smb_fname->base_name);
+ smb_fname_cp.flags = smb_fname->flags;
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LSTAT(handle->conn, &smb_fname);
+ if (smb_fname_cp.flags & SMB_FILENAME_POSIX_PATH) {
+ ret = SMB_VFS_LSTAT(handle->conn, &smb_fname_cp);
} else {
- ret = SMB_VFS_STAT(handle->conn, &smb_fname);
+ ret = SMB_VFS_STAT(handle->conn, &smb_fname_cp);
}
- sbuf = smb_fname.st;
+ sbuf = smb_fname_cp.st;
}
if (ret == -1) {
}
static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
- const char *name,
+ const struct smb_filename *smb_fname,
uint32_t security_info,
TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc)
NTSTATUS result;
START_PROFILE(get_nt_acl);
- result = posix_get_nt_acl(handle->conn, name, security_info,
- mem_ctx, ppdesc);
+ result = posix_get_nt_acl(handle->conn,
+ smb_fname,
+ security_info,
+ mem_ctx,
+ ppdesc);
END_PROFILE(get_nt_acl);
return result;
}
return NT_STATUS_OK; /* Nothing to do here ... */
}
-static int vfswrap_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode)
+static int vfswrap_chmod_acl(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ mode_t mode)
{
#ifdef HAVE_NO_ACL
errno = ENOSYS;
int result;
START_PROFILE(chmod_acl);
- result = chmod_acl(handle->conn, name, mode);
+ result = chmod_acl(handle->conn, smb_fname, mode);
END_PROFILE(chmod_acl);
return result;
#endif
}
static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle,
- const char *path_p,
+ const struct smb_filename *smb_fname,
SMB_ACL_TYPE_T type,
TALLOC_CTX *mem_ctx)
{
- return sys_acl_get_file(handle, path_p, type, mem_ctx);
+ return sys_acl_get_file(handle, smb_fname, type, mem_ctx);
}
static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
return sys_acl_set_fd(handle, fsp, theacl);
}
-static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
+static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
{
- return sys_acl_delete_def_file(handle, path);
+ return sys_acl_delete_def_file(handle, smb_fname);
}
/****************************************************************
return offline;
}
-static int vfswrap_set_offline(struct vfs_handle_struct *handle,
- const struct smb_filename *fname)
-{
- /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
-#if defined(ENOTSUP)
- errno = ENOTSUP;
-#endif
- return -1;
-}
-
static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
struct files_struct *fsp,
TALLOC_CTX *mem_ctx,
.read_fn = vfswrap_read,
.pread_fn = vfswrap_pread,
.pread_send_fn = vfswrap_pread_send,
- .pread_recv_fn = vfswrap_asys_ssize_t_recv,
+ .pread_recv_fn = vfswrap_pread_recv,
.write_fn = vfswrap_write,
.pwrite_fn = vfswrap_pwrite,
.pwrite_send_fn = vfswrap_pwrite_send,
- .pwrite_recv_fn = vfswrap_asys_ssize_t_recv,
+ .pwrite_recv_fn = vfswrap_pwrite_recv,
.lseek_fn = vfswrap_lseek,
.sendfile_fn = vfswrap_sendfile,
.recvfile_fn = vfswrap_recvfile,
.rename_fn = vfswrap_rename,
.fsync_fn = vfswrap_fsync,
.fsync_send_fn = vfswrap_fsync_send,
- .fsync_recv_fn = vfswrap_asys_int_recv,
+ .fsync_recv_fn = vfswrap_fsync_recv,
.stat_fn = vfswrap_stat,
.fstat_fn = vfswrap_fstat,
.lstat_fn = vfswrap_lstat,
.strict_unlock_fn = vfswrap_strict_unlock,
.translate_name_fn = vfswrap_translate_name,
.fsctl_fn = vfswrap_fsctl,
+ .set_dos_attributes_fn = vfswrap_set_dos_attributes,
+ .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
+ .get_dos_attributes_fn = vfswrap_get_dos_attributes,
+ .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
.copy_chunk_send_fn = vfswrap_copy_chunk_send,
.copy_chunk_recv_fn = vfswrap_copy_chunk_recv,
.get_compression_fn = vfswrap_get_compression,
/* aio operations */
.aio_force_fn = vfswrap_aio_force,
- /* offline operations */
- .is_offline_fn = vfswrap_is_offline,
- .set_offline_fn = vfswrap_set_offline,
-
/* durable handle operations */
.durable_cookie_fn = vfswrap_durable_cookie,
.durable_disconnect_fn = vfswrap_durable_disconnect,
.durable_reconnect_fn = vfswrap_durable_reconnect,
};
-NTSTATUS vfs_default_init(void);
-NTSTATUS vfs_default_init(void)
+NTSTATUS vfs_default_init(TALLOC_CTX *);
+NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
{
return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);