vfs: remove SMB_VFS_INIT_SEARCH_OP
[nivanova/samba-autobuild/.git] / source3 / modules / vfs_default.c
index 6de5d641c3e1bf7bfde926b83f5dca4723c4be62..3379493accb0c4494bc5b9adb07f4e4935a0a6d0 100644 (file)
@@ -34,6 +34,7 @@
 #include "lib/util/sys_rw.h"
 #include "lib/pthreadpool/pthreadpool_tevent.h"
 #include "librpc/gen_ndr/ndr_ioctl.h"
+#include "offload_token.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -55,11 +56,13 @@ static void vfswrap_disconnect(vfs_handle_struct *handle)
 
 /* Disk operations */
 
-static uint64_t vfswrap_disk_free(vfs_handle_struct *handle, const char *path,
-                                 uint64_t *bsize, uint64_t *dfree,
-                                 uint64_t *dsize)
+static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname,
+                               uint64_t *bsize,
+                               uint64_t *dfree,
+                               uint64_t *dsize)
 {
-       if (sys_fsusage(path, dfree, dsize) != 0) {
+       if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
                return (uint64_t)-1;
        }
 
@@ -67,15 +70,17 @@ static uint64_t vfswrap_disk_free(vfs_handle_struct *handle, const char *path,
        return *dfree / 2;
 }
 
-static int vfswrap_get_quota(struct vfs_handle_struct *handle, const char *path,
-                            enum SMB_QUOTA_TYPE qtype, unid_t id,
-                            SMB_DISK_QUOTA *qt)
+static int vfswrap_get_quota(struct vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname,
+                               enum SMB_QUOTA_TYPE qtype,
+                               unid_t id,
+                               SMB_DISK_QUOTA *qt)
 {
 #ifdef HAVE_SYS_QUOTAS
        int result;
 
        START_PROFILE(syscall_get_quota);
-       result = sys_get_quota(path, qtype, id, qt);
+       result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
        END_PROFILE(syscall_get_quota);
        return result;
 #else
@@ -108,9 +113,11 @@ static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
        return -1;  /* Not implemented. */
 }
 
-static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
+static int vfswrap_statvfs(struct vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname,
+                               vfs_statvfs_struct *statbuf)
 {
-       return sys_statvfs(path, statbuf);
+       return sys_statvfs(smb_fname->base_name, statbuf);
 }
 
 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
@@ -222,10 +229,18 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
                                   !handle->conn->sconn->using_smb2,
                                   junction, &consumedcnt, &self_referral);
        if (!NT_STATUS_IS_OK(status)) {
-               vfs_ChDir(handle->conn, handle->conn->connectpath);
+               struct smb_filename connectpath_fname = {
+                       .base_name = handle->conn->connectpath
+               };
+               vfs_ChDir(handle->conn, &connectpath_fname);
                return status;
        }
-       vfs_ChDir(handle->conn, handle->conn->connectpath);
+       {
+               struct smb_filename connectpath_fname = {
+                       .base_name = handle->conn->connectpath
+               };
+               vfs_ChDir(handle->conn, &connectpath_fname);
+       }
 
        if (!self_referral) {
                pathnamep[consumedcnt] = '\0';
@@ -539,12 +554,6 @@ static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
        return result;
 }
 
-static void vfswrap_init_search_op(vfs_handle_struct *handle,
-                                  DIR *dirp)
-{
-       /* Default behavior is a NOOP */
-}
-
 /* File operations */
 
 static int vfswrap_open(vfs_handle_struct *handle,
@@ -723,7 +732,6 @@ static int vfswrap_init_pool(struct smbd_server_connection *conn)
 
 struct vfswrap_pread_state {
        ssize_t ret;
-       int err;
        int fd;
        void *buf;
        size_t count;
@@ -735,6 +743,7 @@ struct vfswrap_pread_state {
 
 static void vfs_pread_do(void *private_data);
 static void vfs_pread_done(struct tevent_req *subreq);
+static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
 
 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
                                             TALLOC_CTX *mem_ctx,
@@ -775,6 +784,8 @@ static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
        }
        tevent_req_set_callback(subreq, vfs_pread_done, req);
 
+       talloc_set_destructor(state, vfs_pread_state_destructor);
+
        return req;
 }
 
@@ -794,7 +805,9 @@ static void vfs_pread_do(void *private_data)
                                   state->offset);
        } while ((state->ret == -1) && (errno == EINTR));
 
-       state->err = errno;
+       if (state->ret == -1) {
+               state->vfs_aio_state.error = errno;
+       }
 
        PROFILE_TIMESTAMP(&end_time);
 
@@ -803,19 +816,23 @@ static void vfs_pread_do(void *private_data)
        SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
 }
 
+static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
+{
+       return -1;
+}
+
 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);
+       talloc_set_destructor(state, NULL);
        if (tevent_req_error(req, ret)) {
                return;
        }
@@ -839,7 +856,6 @@ static ssize_t vfswrap_pread_recv(struct tevent_req *req,
 
 struct vfswrap_pwrite_state {
        ssize_t ret;
-       int err;
        int fd;
        const void *buf;
        size_t count;
@@ -851,6 +867,7 @@ struct vfswrap_pwrite_state {
 
 static void vfs_pwrite_do(void *private_data);
 static void vfs_pwrite_done(struct tevent_req *subreq);
+static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
 
 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
                                              TALLOC_CTX *mem_ctx,
@@ -891,6 +908,8 @@ static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
        }
        tevent_req_set_callback(subreq, vfs_pwrite_done, req);
 
+       talloc_set_destructor(state, vfs_pwrite_state_destructor);
+
        return req;
 }
 
@@ -910,7 +929,9 @@ static void vfs_pwrite_do(void *private_data)
                                   state->offset);
        } while ((state->ret == -1) && (errno == EINTR));
 
-       state->err = errno;
+       if (state->ret == -1) {
+               state->vfs_aio_state.error = errno;
+       }
 
        PROFILE_TIMESTAMP(&end_time);
 
@@ -919,19 +940,23 @@ static void vfs_pwrite_do(void *private_data)
        SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
 }
 
+static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
+{
+       return -1;
+}
+
 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);
+       talloc_set_destructor(state, NULL);
        if (tevent_req_error(req, ret)) {
                return;
        }
@@ -955,7 +980,6 @@ static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
 
 struct vfswrap_fsync_state {
        ssize_t ret;
-       int err;
        int fd;
 
        struct vfs_aio_state vfs_aio_state;
@@ -964,6 +988,7 @@ struct vfswrap_fsync_state {
 
 static void vfs_fsync_do(void *private_data);
 static void vfs_fsync_done(struct tevent_req *subreq);
+static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
 
 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
                                             TALLOC_CTX *mem_ctx,
@@ -997,6 +1022,8 @@ static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
        }
        tevent_req_set_callback(subreq, vfs_fsync_done, req);
 
+       talloc_set_destructor(state, vfs_fsync_state_destructor);
+
        return req;
 }
 
@@ -1013,26 +1040,32 @@ static void vfs_fsync_do(void *private_data)
                state->ret = fsync(state->fd);
        } while ((state->ret == -1) && (errno == EINTR));
 
-       state->err = errno;
+       if (state->ret == -1) {
+               state->vfs_aio_state.error = errno;
+       }
 
        PROFILE_TIMESTAMP(&end_time);
 
        state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
 }
 
+static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
+{
+       return -1;
+}
+
 static void vfs_fsync_done(struct tevent_req *subreq)
 {
        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;
 
        ret = pthreadpool_tevent_job_recv(subreq);
        TALLOC_FREE(subreq);
        SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
+       talloc_set_destructor(state, NULL);
        if (tevent_req_error(req, ret)) {
                return;
        }
@@ -1593,13 +1626,86 @@ static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
        return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
 }
 
-struct vfs_cc_state {
+static struct vfs_offload_ctx *vfswrap_offload_ctx;
+
+struct vfswrap_offload_read_state {
+       DATA_BLOB token;
+};
+
+static struct tevent_req *vfswrap_offload_read_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct vfs_handle_struct *handle,
+       struct files_struct *fsp,
+       uint32_t fsctl,
+       uint32_t ttl,
+       off_t offset,
+       size_t to_copy)
+{
+       struct tevent_req *req = NULL;
+       struct vfswrap_offload_read_state *state = NULL;
+       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct vfswrap_offload_read_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
+                                           &vfswrap_offload_ctx);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
+               return tevent_req_post(req, ev);
+       }
+
+       status = vfs_offload_token_create_blob(state, fsp, fsctl,
+                                              &state->token);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
+                                               &state->token);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
+                                         struct vfs_handle_struct *handle,
+                                         TALLOC_CTX *mem_ctx,
+                                         DATA_BLOB *token)
+{
+       struct vfswrap_offload_read_state *state = tevent_req_data(
+               req, struct vfswrap_offload_read_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       token->length = state->token.length;
+       token->data = talloc_move(mem_ctx, &state->token.data);
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+struct vfswrap_offload_write_state {
        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;
+       DATA_BLOB *token;
        struct files_struct *src_fsp;
        off_t src_off;
        struct files_struct *dst_fsp;
@@ -1607,54 +1713,86 @@ struct vfs_cc_state {
        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 NTSTATUS vfswrap_offload_write_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,
-                                                 struct files_struct *src_fsp,
-                                                 off_t src_off,
-                                                 struct files_struct *dest_fsp,
-                                                 off_t dest_off,
-                                                 off_t to_copy,
-                                                 uint32_t flags)
+static struct tevent_req *vfswrap_offload_write_send(
+       struct vfs_handle_struct *handle,
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       uint32_t fsctl,
+       DATA_BLOB *token,
+       off_t transfer_offset,
+       struct files_struct *dest_fsp,
+       off_t dest_off,
+       off_t to_copy)
 {
        struct tevent_req *req;
-       struct vfs_cc_state *state = NULL;
+       struct vfswrap_offload_write_state *state = NULL;
        size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
+       files_struct *src_fsp = NULL;
        NTSTATUS status;
 
-       DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
-
-       req = tevent_req_create(mem_ctx, &state, struct vfs_cc_state);
+       req = tevent_req_create(mem_ctx, &state,
+                               struct vfswrap_offload_write_state);
        if (req == NULL) {
                return NULL;
        }
 
-       if (flags & ~VFS_COPY_CHUNK_FL_MASK_ALL) {
+       *state = (struct vfswrap_offload_write_state) {
+               .ev = ev,
+               .token = token,
+               .src_off = transfer_offset,
+               .dst_fsp = dest_fsp,
+               .dst_off = dest_off,
+               .to_copy = to_copy,
+               .remaining = to_copy,
+       };
+
+       switch (fsctl) {
+       case FSCTL_SRV_COPYCHUNK:
+       case FSCTL_SRV_COPYCHUNK_WRITE:
+               break;
+
+       case FSCTL_OFFLOAD_WRITE:
+               tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+               return tevent_req_post(req, ev);
+
+       case FSCTL_DUP_EXTENTS_TO_FILE:
+               DBG_DEBUG("COW clones not supported by vfs_default\n");
                tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
                return tevent_req_post(req, ev);
+
+       default:
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               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);
+       /*
+        * From here on we assume a copy-chunk fsctl
+        */
+
+       if (to_copy == 0) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
+
+       status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
+                                               token, &src_fsp);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+       state->src_fsp = src_fsp;
+
+       DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
+
+       status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
                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);
@@ -1665,7 +1803,7 @@ static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *hand
                return tevent_req_post(req, ev);
        }
 
-       if (src_fsp->fsp_name->st.st_ex_size < src_off + num) {
+       if (src_fsp->fsp_name->st.st_ex_size < state->src_off + num) {
                /*
                 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
                 *   If the SourceOffset or SourceOffset + Length extends beyond
@@ -1689,7 +1827,7 @@ static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *hand
                return tevent_req_post(req, ev);
        }
 
-       status = copy_chunk_loop(req);
+       status = vfswrap_offload_write_loop(req);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return tevent_req_post(req, ev);
@@ -1698,30 +1836,30 @@ static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *hand
        return req;
 }
 
-static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq);
+static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
 
-static NTSTATUS copy_chunk_loop(struct tevent_req *req)
+static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
 {
-       struct vfs_cc_state *state = tevent_req_data(req, struct vfs_cc_state);
+       struct vfswrap_offload_write_state *state = tevent_req_data(
+               req, struct vfswrap_offload_write_state);
        struct tevent_req *subreq = NULL;
+       struct lock_struct read_lck;
        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,
+       init_strict_lock_struct(state->src_fsp,
                                state->src_fsp->op->global->open_persistent_id,
-                                       state->src_off,
-                                       state->next_io_size,
-                                       READ_LOCK,
-                                       &state->read_lck);
-
-               ok = SMB_VFS_STRICT_LOCK(state->src_fsp->conn,
-                                        state->src_fsp,
-                                        &state->read_lck);
-               if (!ok) {
-                       return NT_STATUS_FILE_LOCK_CONFLICT;
-               }
+                               state->src_off,
+                               state->next_io_size,
+                               READ_LOCK,
+                               &read_lck);
+
+       ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
+                                state->src_fsp,
+                                &read_lck);
+       if (!ok) {
+               return NT_STATUS_FILE_LOCK_CONFLICT;
        }
 
        subreq = SMB_VFS_PREAD_SEND(state,
@@ -1733,29 +1871,24 @@ static NTSTATUS copy_chunk_loop(struct tevent_req *req)
        if (subreq == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       tevent_req_set_callback(subreq, vfswrap_copy_chunk_read_done, req);
+       tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
 
        return NT_STATUS_OK;
 }
 
-static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq);
+static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
 
-static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq)
+static void vfswrap_offload_write_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 vfswrap_offload_write_state *state = tevent_req_data(
+               req, struct vfswrap_offload_write_state);
        struct vfs_aio_state aio_state;
+       struct lock_struct write_lck;
        ssize_t nread;
        bool ok;
 
-       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) {
@@ -1772,21 +1905,19 @@ static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq)
 
        state->src_off += nread;
 
-       if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
-               init_strict_lock_struct(state->dst_fsp,
+       init_strict_lock_struct(state->dst_fsp,
                                state->dst_fsp->op->global->open_persistent_id,
-                                       state->dst_off,
-                                       state->next_io_size,
-                                       WRITE_LOCK,
-                                       &state->write_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;
-               }
+                               state->dst_off,
+                               state->next_io_size,
+                               WRITE_LOCK,
+                               &write_lck);
+
+       ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
+                                state->dst_fsp,
+                                &write_lck);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
+               return;
        }
 
        subreq = SMB_VFS_PWRITE_SEND(state,
@@ -1799,25 +1930,19 @@ static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq)
                tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
-       tevent_req_set_callback(subreq, vfswrap_copy_chunk_write_done, req);
+       tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
 }
 
-static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq)
+static void vfswrap_offload_write_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 vfswrap_offload_write_state *state = tevent_req_data(
+               req, struct vfswrap_offload_write_state);
        struct vfs_aio_state aio_state;
        ssize_t nwritten;
        NTSTATUS status;
 
-       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) {
@@ -1844,7 +1969,7 @@ static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq)
                return;
        }
 
-       status = copy_chunk_loop(req);
+       status = vfswrap_offload_write_loop(req);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return;
@@ -1853,11 +1978,12 @@ static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq)
        return;
 }
 
-static NTSTATUS vfswrap_copy_chunk_recv(struct vfs_handle_struct *handle,
+static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
                                        struct tevent_req *req,
                                        off_t *copied)
 {
-       struct vfs_cc_state *state = tevent_req_data(req, struct vfs_cc_state);
+       struct vfswrap_offload_write_state *state = tevent_req_data(
+               req, struct vfswrap_offload_write_state);
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
@@ -2074,24 +2200,39 @@ static int vfswrap_lchown(vfs_handle_struct *handle,
        return result;
 }
 
-static int vfswrap_chdir(vfs_handle_struct *handle, const char *path)
+static int vfswrap_chdir(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname)
 {
        int result;
 
        START_PROFILE(syscall_chdir);
-       result = chdir(path);
+       result = chdir(smb_fname->base_name);
        END_PROFILE(syscall_chdir);
        return result;
 }
 
-static char *vfswrap_getwd(vfs_handle_struct *handle)
+static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
+                               TALLOC_CTX *ctx)
 {
        char *result;
+       struct smb_filename *smb_fname = NULL;
 
        START_PROFILE(syscall_getwd);
        result = sys_getwd();
        END_PROFILE(syscall_getwd);
-       return result;
+
+       if (result == NULL) {
+               return NULL;
+       }
+       smb_fname = synthetic_smb_fname(ctx,
+                               result,
+                               NULL,
+                               NULL,
+                               0);
+       if (smb_fname == NULL) {
+               SAFE_FREE(result);
+       }
+       return smb_fname;
 }
 
 /*********************************************************************
@@ -2412,32 +2553,39 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
        return result;
 }
 
-static int vfswrap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
+static int vfswrap_symlink(vfs_handle_struct *handle,
+                       const char *link_target,
+                       const struct smb_filename *new_smb_fname)
 {
        int result;
 
        START_PROFILE(syscall_symlink);
-       result = symlink(oldpath, newpath);
+       result = symlink(link_target, new_smb_fname->base_name);
        END_PROFILE(syscall_symlink);
        return result;
 }
 
-static int vfswrap_readlink(vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
+static int vfswrap_readlink(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       char *buf,
+                       size_t bufsiz)
 {
        int result;
 
        START_PROFILE(syscall_readlink);
-       result = readlink(path, buf, bufsiz);
+       result = readlink(smb_fname->base_name, buf, bufsiz);
        END_PROFILE(syscall_readlink);
        return result;
 }
 
-static int vfswrap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
+static int vfswrap_link(vfs_handle_struct *handle,
+                       const struct smb_filename *old_smb_fname,
+                       const struct smb_filename *new_smb_fname)
 {
        int result;
 
        START_PROFILE(syscall_link);
-       result = link(oldpath, newpath);
+       result = link(old_smb_fname->base_name, new_smb_fname->base_name);
        END_PROFILE(syscall_link);
        return result;
 }
@@ -2455,21 +2603,29 @@ static int vfswrap_mknod(vfs_handle_struct *handle,
        return result;
 }
 
-static char *vfswrap_realpath(vfs_handle_struct *handle, const char *path)
+static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
+                       TALLOC_CTX *ctx,
+                       const struct smb_filename *smb_fname)
 {
        char *result;
+       struct smb_filename *result_fname = NULL;
 
        START_PROFILE(syscall_realpath);
-       result = sys_realpath(path);
+       result = sys_realpath(smb_fname->base_name);
        END_PROFILE(syscall_realpath);
-       return result;
+       if (result) {
+               result_fname = synthetic_smb_fname(ctx, result, NULL, NULL, 0);
+               SAFE_FREE(result);
+       }
+       return result_fname;
 }
 
-static int vfswrap_chflags(vfs_handle_struct *handle, const char *path,
-                          unsigned int flags)
+static int vfswrap_chflags(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       unsigned int flags)
 {
 #ifdef HAVE_CHFLAGS
-       return chflags(path, flags);
+       return chflags(smb_fname->base_name, flags);
 #else
        errno = ENOSYS;
        return -1;
@@ -2570,7 +2726,7 @@ static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
 }
 
 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
-                                      const char *fname)
+                                  const struct smb_filename *smb_fname)
 {
        return handle->conn->connectpath;
 }
@@ -2606,24 +2762,14 @@ static bool vfswrap_brl_cancel_windows(struct vfs_handle_struct *handle,
        return brl_lock_cancel_default(br_lck, plock);
 }
 
-static bool vfswrap_strict_lock(struct vfs_handle_struct *handle,
-                               files_struct *fsp,
-                               struct lock_struct *plock)
-{
-       SMB_ASSERT(plock->lock_type == READ_LOCK ||
-           plock->lock_type == WRITE_LOCK);
-
-       return strict_lock_default(fsp, plock);
-}
-
-static void vfswrap_strict_unlock(struct vfs_handle_struct *handle,
-                               files_struct *fsp,
-                               struct lock_struct *plock)
+static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
+                                     files_struct *fsp,
+                                     struct lock_struct *plock)
 {
        SMB_ASSERT(plock->lock_type == READ_LOCK ||
            plock->lock_type == WRITE_LOCK);
 
-       strict_unlock_default(fsp, plock);
+       return strict_lock_check_default(fsp, plock);
 }
 
 /* NT ACL operations. */
@@ -2900,7 +3046,6 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .mkdir_fn = vfswrap_mkdir,
        .rmdir_fn = vfswrap_rmdir,
        .closedir_fn = vfswrap_closedir,
-       .init_search_op_fn = vfswrap_init_search_op,
 
        /* File operations */
 
@@ -2954,16 +3099,17 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .brl_lock_windows_fn = vfswrap_brl_lock_windows,
        .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
        .brl_cancel_windows_fn = vfswrap_brl_cancel_windows,
-       .strict_lock_fn = vfswrap_strict_lock,
-       .strict_unlock_fn = vfswrap_strict_unlock,
+       .strict_lock_check_fn = vfswrap_strict_lock_check,
        .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,
+       .offload_read_send_fn = vfswrap_offload_read_send,
+       .offload_read_recv_fn = vfswrap_offload_read_recv,
+       .offload_write_send_fn = vfswrap_offload_write_send,
+       .offload_write_recv_fn = vfswrap_offload_write_recv,
        .get_compression_fn = vfswrap_get_compression,
        .set_compression_fn = vfswrap_set_compression,