2 Unix SMB/CIFS implementation.
3 Wrap disk only vfs functions to sidestep dodgy compilers.
4 Copyright (C) Tim Potter 1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
27 #include "smbprofile.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/lookup_sid.h"
30 #include "source3/include/msdfs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "lib/util/sys_rw.h"
35 #include "lib/pthreadpool/pthreadpool_tevent.h"
36 #include "librpc/gen_ndr/ndr_ioctl.h"
37 #include "offload_token.h"
38 #include "util_reparse.h"
39 #include "lib/util/string_wrappers.h"
42 #define DBGC_CLASS DBGC_VFS
44 /* Check for NULL pointer parameters in vfswrap_* functions */
46 /* We don't want to have NULL function pointers lying around. Someone
47 is sure to try and execute them. These stubs are used to prevent
50 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
52 handle->conn->have_proc_fds = sys_have_proc_fds();
53 return 0; /* Return >= 0 for success */
56 static void vfswrap_disconnect(vfs_handle_struct *handle)
62 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
63 const struct smb_filename *smb_fname,
68 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
76 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
77 const struct smb_filename *smb_fname,
78 enum SMB_QUOTA_TYPE qtype,
82 #ifdef HAVE_SYS_QUOTAS
85 START_PROFILE(syscall_get_quota);
86 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
87 END_PROFILE(syscall_get_quota);
95 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
97 #ifdef HAVE_SYS_QUOTAS
100 START_PROFILE(syscall_set_quota);
101 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
102 END_PROFILE(syscall_set_quota);
110 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
111 struct files_struct *fsp,
112 struct shadow_copy_data *shadow_copy_data,
116 return -1; /* Not implemented. */
119 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
120 const struct smb_filename *smb_fname,
121 vfs_statvfs_struct *statbuf)
123 return sys_statvfs(smb_fname->base_name, statbuf);
126 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
127 enum timestamp_set_resolution *p_ts_res)
129 const struct loadparm_substitution *lp_sub =
130 loadparm_s3_global_substitution();
131 connection_struct *conn = handle->conn;
132 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
133 struct smb_filename *smb_fname_cpath = NULL;
134 struct vfs_statvfs_struct statbuf;
137 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
143 if (smb_fname_cpath == NULL) {
147 ZERO_STRUCT(statbuf);
148 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
150 caps = statbuf.FsCapabilities;
153 *p_ts_res = TIMESTAMP_SET_SECONDS;
155 /* Work out what timestamp resolution we can
156 * use when setting a timestamp. */
158 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
160 TALLOC_FREE(smb_fname_cpath);
164 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
165 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
166 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
167 /* If any of the normal UNIX directory timestamps
168 * have a non-zero tv_nsec component assume
169 * we might be able to set sub-second timestamps.
170 * See what filetime set primitives we have.
172 #if defined(HAVE_UTIMENSAT)
173 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
174 #elif defined(HAVE_UTIMES)
175 /* utimes allows msec timestamps to be set. */
176 *p_ts_res = TIMESTAMP_SET_MSEC;
177 #elif defined(HAVE_UTIME)
178 /* utime only allows sec timestamps to be set. */
179 *p_ts_res = TIMESTAMP_SET_SECONDS;
182 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
184 "available on share %s, directory %s\n",
185 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
186 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
187 conn->connectpath ));
189 TALLOC_FREE(smb_fname_cpath);
193 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
194 struct dfs_GetDFSReferral *r)
196 struct junction_map *junction = NULL;
198 bool self_referral = false;
199 char *pathnamep = NULL;
200 char *local_dfs_path = NULL;
203 uint16_t max_referral_level = r->in.req.max_referral_level;
206 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
209 /* get the junction entry */
210 if (r->in.req.servername == NULL) {
211 return NT_STATUS_NOT_FOUND;
215 * Trim pathname sent by client so it begins with only one backslash.
216 * Two backslashes confuse some dfs clients
219 local_dfs_path = talloc_strdup(r, r->in.req.servername);
220 if (local_dfs_path == NULL) {
221 return NT_STATUS_NO_MEMORY;
223 pathnamep = local_dfs_path;
224 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
225 IS_DIRECTORY_SEP(pathnamep[1])) {
229 junction = talloc_zero(r, struct junction_map);
230 if (junction == NULL) {
231 return NT_STATUS_NO_MEMORY;
234 /* The following call can change cwd. */
235 status = get_referred_path(r,
236 handle->conn->session_info,
238 handle->conn->sconn->remote_address,
239 handle->conn->sconn->local_address,
240 !handle->conn->sconn->using_smb2,
241 junction, &consumedcnt, &self_referral);
242 if (!NT_STATUS_IS_OK(status)) {
243 struct smb_filename connectpath_fname = {
244 .base_name = handle->conn->connectpath
246 vfs_ChDir(handle->conn, &connectpath_fname);
250 struct smb_filename connectpath_fname = {
251 .base_name = handle->conn->connectpath
253 vfs_ChDir(handle->conn, &connectpath_fname);
256 if (!self_referral) {
257 pathnamep[consumedcnt] = '\0';
260 dbgtext("Path %s to alternate path(s):",
262 for (i=0; i < junction->referral_count; i++) {
264 junction->referral_list[i].alternate_path);
270 if (r->in.req.max_referral_level <= 2) {
271 max_referral_level = 2;
273 if (r->in.req.max_referral_level >= 3) {
274 max_referral_level = 3;
277 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
278 if (r->out.resp == NULL) {
279 return NT_STATUS_NO_MEMORY;
282 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
283 r->out.resp->nb_referrals = junction->referral_count;
285 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
287 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
290 r->out.resp->referral_entries = talloc_zero_array(r,
291 struct dfs_referral_type,
292 r->out.resp->nb_referrals);
293 if (r->out.resp->referral_entries == NULL) {
294 return NT_STATUS_NO_MEMORY;
297 switch (max_referral_level) {
299 for(i=0; i < junction->referral_count; i++) {
300 struct referral *ref = &junction->referral_list[i];
301 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
302 struct dfs_referral_type *t =
303 &r->out.resp->referral_entries[i];
304 struct dfs_referral_v2 *v2 = &t->referral.v2;
307 v2->size = VERSION2_REFERRAL_SIZE;
309 v2->server_type = DFS_SERVER_ROOT;
311 v2->server_type = DFS_SERVER_NON_ROOT;
314 v2->proximity = ref->proximity;
316 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
317 if (v2->DFS_path == NULL) {
318 return NT_STATUS_NO_MEMORY;
320 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
321 if (v2->DFS_alt_path == NULL) {
322 return NT_STATUS_NO_MEMORY;
324 v2->netw_address = talloc_strdup(mem_ctx,
325 ref->alternate_path);
326 if (v2->netw_address == NULL) {
327 return NT_STATUS_NO_MEMORY;
333 for(i=0; i < junction->referral_count; i++) {
334 struct referral *ref = &junction->referral_list[i];
335 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
336 struct dfs_referral_type *t =
337 &r->out.resp->referral_entries[i];
338 struct dfs_referral_v3 *v3 = &t->referral.v3;
339 struct dfs_normal_referral *r1 = &v3->referrals.r1;
342 v3->size = VERSION3_REFERRAL_SIZE;
344 v3->server_type = DFS_SERVER_ROOT;
346 v3->server_type = DFS_SERVER_NON_ROOT;
350 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
351 if (r1->DFS_path == NULL) {
352 return NT_STATUS_NO_MEMORY;
354 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
355 if (r1->DFS_alt_path == NULL) {
356 return NT_STATUS_NO_MEMORY;
358 r1->netw_address = talloc_strdup(mem_ctx,
359 ref->alternate_path);
360 if (r1->netw_address == NULL) {
361 return NT_STATUS_NO_MEMORY;
366 DEBUG(0,("Invalid dfs referral version: %d\n",
367 max_referral_level));
368 return NT_STATUS_INVALID_LEVEL;
372 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
378 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
379 struct files_struct *dirfsp,
380 const struct smb_filename *smb_fname,
381 const struct referral *reflist,
382 size_t referral_count)
384 TALLOC_CTX *frame = talloc_stackframe();
385 NTSTATUS status = NT_STATUS_NO_MEMORY;
387 char *msdfs_link = NULL;
389 /* Form the msdfs_link contents */
390 msdfs_link = msdfs_link_string(frame,
393 if (msdfs_link == NULL) {
397 ret = symlinkat(msdfs_link,
398 fsp_get_pathref_fd(dirfsp),
399 smb_fname->base_name);
401 status = NT_STATUS_OK;
403 status = map_nt_error_from_unix(errno);
413 * Read and return the contents of a DFS redirect given a
414 * pathname. A caller can pass in NULL for ppreflist and
415 * preferral_count but still determine if this was a
416 * DFS redirect point by getting NT_STATUS_OK back
417 * without incurring the overhead of reading and parsing
418 * the referral contents.
421 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
423 struct files_struct *dirfsp,
424 struct smb_filename *smb_fname,
425 struct referral **ppreflist,
426 size_t *preferral_count)
428 NTSTATUS status = NT_STATUS_NO_MEMORY;
430 char *link_target = NULL;
433 #if defined(HAVE_BROKEN_READLINK)
434 char link_target_buf[PATH_MAX];
436 char link_target_buf[7];
440 if (is_named_stream(smb_fname)) {
441 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
445 if (ppreflist == NULL && preferral_count == NULL) {
447 * We're only checking if this is a DFS
448 * redirect. We don't need to return data.
450 bufsize = sizeof(link_target_buf);
451 link_target = link_target_buf;
454 link_target = talloc_array(mem_ctx, char, bufsize);
460 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
461 smb_fname->base_name,
464 if (referral_len == -1) {
465 if (errno == EINVAL) {
467 * If the path isn't a link, readlinkat
468 * returns EINVAL. Allow the caller to
471 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
472 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
474 status = map_nt_error_from_unix(errno);
475 if (errno == ENOENT) {
476 DBG_NOTICE("Error reading "
477 "msdfs link %s: %s\n",
478 smb_fname->base_name,
481 DBG_ERR("Error reading "
482 "msdfs link %s: %s\n",
483 smb_fname->base_name,
489 link_target[referral_len] = '\0';
491 DBG_INFO("%s -> %s\n",
492 smb_fname->base_name,
495 if (!strnequal(link_target, "msdfs:", 6)) {
496 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
500 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
501 smb_fname->base_name,
504 lp_fake_directory_create_times(SNUM(handle->conn)));
506 status = map_nt_error_from_unix(errno);
510 if (ppreflist == NULL && preferral_count == NULL) {
511 /* Early return for checking if this is a DFS link. */
515 ok = parse_msdfs_symlink(mem_ctx,
516 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
522 status = NT_STATUS_OK;
524 status = NT_STATUS_NO_MEMORY;
529 if (link_target != link_target_buf) {
530 TALLOC_FREE(link_target);
535 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
537 const char *service_path,
540 return NT_STATUS_NOT_SUPPORTED;
543 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
545 const char *base_volume,
551 return NT_STATUS_NOT_SUPPORTED;
554 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
559 return NT_STATUS_NOT_SUPPORTED;
562 /* Directory operations */
564 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
571 START_PROFILE(syscall_fdopendir);
572 result = sys_fdopendir(fsp_get_io_fd(fsp));
573 END_PROFILE(syscall_fdopendir);
578 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
579 struct files_struct *dirfsp,
581 SMB_STRUCT_STAT *sbuf)
583 struct dirent *result;
584 bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
585 int flags = AT_SYMLINK_NOFOLLOW;
589 START_PROFILE(syscall_readdir);
591 result = readdir(dirp);
592 END_PROFILE(syscall_readdir);
597 if (result == NULL) {
602 * Default Posix readdir() does not give us stat info.
603 * Set to invalid to indicate we didn't return this info.
605 SET_STAT_INVALID(*sbuf);
607 ret = sys_fstatat(dirfd(dirp),
617 * As this is an optimization, ignore it if we stat'ed a
618 * symlink for non-POSIX context. Make the caller do it again
619 * as we don't know if they wanted the link info, or its
622 if (S_ISLNK(st.st_ex_mode) &&
623 !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
632 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
633 struct files_struct *fsp,
635 struct readdir_attr_data **attr_data)
637 return NT_STATUS_NOT_SUPPORTED;
640 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
642 START_PROFILE(syscall_seekdir);
643 seekdir(dirp, offset);
644 END_PROFILE(syscall_seekdir);
647 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
650 START_PROFILE(syscall_telldir);
651 result = telldir(dirp);
652 END_PROFILE(syscall_telldir);
656 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
658 START_PROFILE(syscall_rewinddir);
660 END_PROFILE(syscall_rewinddir);
663 static int vfswrap_mkdirat(vfs_handle_struct *handle,
664 struct files_struct *dirfsp,
665 const struct smb_filename *smb_fname,
670 START_PROFILE(syscall_mkdirat);
672 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
674 END_PROFILE(syscall_mkdirat);
678 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
682 START_PROFILE(syscall_closedir);
683 result = closedir(dirp);
684 END_PROFILE(syscall_closedir);
688 /* File operations */
690 static int vfswrap_openat(vfs_handle_struct *handle,
691 const struct files_struct *dirfsp,
692 const struct smb_filename *smb_fname,
697 bool have_opath = false;
698 bool became_root = false;
701 START_PROFILE(syscall_openat);
703 if (is_named_stream(smb_fname)) {
711 if (fsp->fsp_flags.is_pathref) {
716 if (fsp->fsp_flags.is_pathref && !have_opath) {
721 result = openat(fsp_get_pathref_fd(dirfsp),
722 smb_fname->base_name,
730 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
733 END_PROFILE(syscall_openat);
736 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
737 struct smb_request *req,
738 struct smb_filename *smb_fname,
739 uint32_t access_mask,
740 uint32_t share_access,
741 uint32_t create_disposition,
742 uint32_t create_options,
743 uint32_t file_attributes,
744 uint32_t oplock_request,
745 const struct smb2_lease *lease,
746 uint64_t allocation_size,
747 uint32_t private_flags,
748 struct security_descriptor *sd,
749 struct ea_list *ea_list,
750 files_struct **result,
752 const struct smb2_create_blobs *in_context_blobs,
753 struct smb2_create_blobs *out_context_blobs)
755 return create_file_default(handle->conn, req, smb_fname,
756 access_mask, share_access,
757 create_disposition, create_options,
758 file_attributes, oplock_request, lease,
759 allocation_size, private_flags,
761 pinfo, in_context_blobs, out_context_blobs);
764 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
768 START_PROFILE(syscall_close);
769 result = fd_close_posix(fsp);
770 END_PROFILE(syscall_close);
774 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
775 size_t n, off_t offset)
779 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
780 START_PROFILE_BYTES(syscall_pread, n);
781 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
782 END_PROFILE_BYTES(syscall_pread);
784 if (result == -1 && errno == ESPIPE) {
785 /* Maintain the fiction that pipes can be seeked (sought?) on. */
786 result = sys_read(fsp_get_io_fd(fsp), data, n);
787 fh_set_pos(fsp->fh, 0);
790 #else /* HAVE_PREAD */
793 #endif /* HAVE_PREAD */
798 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
799 size_t n, off_t offset)
803 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
804 START_PROFILE_BYTES(syscall_pwrite, n);
805 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
806 END_PROFILE_BYTES(syscall_pwrite);
808 if (result == -1 && errno == ESPIPE) {
809 /* Maintain the fiction that pipes can be sought on. */
810 result = sys_write(fsp_get_io_fd(fsp), data, n);
813 #else /* HAVE_PWRITE */
816 #endif /* HAVE_PWRITE */
821 struct vfswrap_pread_state {
828 struct vfs_aio_state vfs_aio_state;
829 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
832 static void vfs_pread_do(void *private_data);
833 static void vfs_pread_done(struct tevent_req *subreq);
834 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
836 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
838 struct tevent_context *ev,
839 struct files_struct *fsp,
841 size_t n, off_t offset)
843 struct tevent_req *req, *subreq;
844 struct vfswrap_pread_state *state;
846 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
852 state->fd = fsp_get_io_fd(fsp);
855 state->offset = offset;
857 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
858 state->profile_bytes, n);
859 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
861 subreq = pthreadpool_tevent_job_send(
862 state, ev, handle->conn->sconn->pool,
863 vfs_pread_do, state);
864 if (tevent_req_nomem(subreq, req)) {
865 return tevent_req_post(req, ev);
867 tevent_req_set_callback(subreq, vfs_pread_done, req);
869 talloc_set_destructor(state, vfs_pread_state_destructor);
874 static void vfs_pread_do(void *private_data)
876 struct vfswrap_pread_state *state = talloc_get_type_abort(
877 private_data, struct vfswrap_pread_state);
878 struct timespec start_time;
879 struct timespec end_time;
881 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
883 PROFILE_TIMESTAMP(&start_time);
885 state->ret = sys_pread_full(state->fd,
890 if (state->ret == -1) {
891 state->vfs_aio_state.error = errno;
894 PROFILE_TIMESTAMP(&end_time);
896 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
898 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
901 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
906 static void vfs_pread_done(struct tevent_req *subreq)
908 struct tevent_req *req = tevent_req_callback_data(
909 subreq, struct tevent_req);
910 struct vfswrap_pread_state *state = tevent_req_data(
911 req, struct vfswrap_pread_state);
914 ret = pthreadpool_tevent_job_recv(subreq);
916 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
917 talloc_set_destructor(state, NULL);
920 tevent_req_error(req, ret);
924 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
925 * means the lower level pthreadpool failed to create a new
926 * thread. Fallback to sync processing in that case to allow
927 * some progress for the client.
932 tevent_req_done(req);
935 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
936 struct vfs_aio_state *vfs_aio_state)
938 struct vfswrap_pread_state *state = tevent_req_data(
939 req, struct vfswrap_pread_state);
941 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
945 *vfs_aio_state = state->vfs_aio_state;
949 struct vfswrap_pwrite_state {
956 struct vfs_aio_state vfs_aio_state;
957 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
960 static void vfs_pwrite_do(void *private_data);
961 static void vfs_pwrite_done(struct tevent_req *subreq);
962 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
964 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
966 struct tevent_context *ev,
967 struct files_struct *fsp,
969 size_t n, off_t offset)
971 struct tevent_req *req, *subreq;
972 struct vfswrap_pwrite_state *state;
974 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
980 state->fd = fsp_get_io_fd(fsp);
983 state->offset = offset;
985 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
986 state->profile_bytes, n);
987 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
989 subreq = pthreadpool_tevent_job_send(
990 state, ev, handle->conn->sconn->pool,
991 vfs_pwrite_do, state);
992 if (tevent_req_nomem(subreq, req)) {
993 return tevent_req_post(req, ev);
995 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
997 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1002 static void vfs_pwrite_do(void *private_data)
1004 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1005 private_data, struct vfswrap_pwrite_state);
1006 struct timespec start_time;
1007 struct timespec end_time;
1009 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1011 PROFILE_TIMESTAMP(&start_time);
1013 state->ret = sys_pwrite_full(state->fd,
1018 if (state->ret == -1) {
1019 state->vfs_aio_state.error = errno;
1022 PROFILE_TIMESTAMP(&end_time);
1024 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1026 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1029 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1034 static void vfs_pwrite_done(struct tevent_req *subreq)
1036 struct tevent_req *req = tevent_req_callback_data(
1037 subreq, struct tevent_req);
1038 struct vfswrap_pwrite_state *state = tevent_req_data(
1039 req, struct vfswrap_pwrite_state);
1042 ret = pthreadpool_tevent_job_recv(subreq);
1043 TALLOC_FREE(subreq);
1044 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1045 talloc_set_destructor(state, NULL);
1047 if (ret != EAGAIN) {
1048 tevent_req_error(req, ret);
1052 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1053 * means the lower level pthreadpool failed to create a new
1054 * thread. Fallback to sync processing in that case to allow
1055 * some progress for the client.
1057 vfs_pwrite_do(state);
1060 tevent_req_done(req);
1063 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1064 struct vfs_aio_state *vfs_aio_state)
1066 struct vfswrap_pwrite_state *state = tevent_req_data(
1067 req, struct vfswrap_pwrite_state);
1069 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1073 *vfs_aio_state = state->vfs_aio_state;
1077 struct vfswrap_fsync_state {
1081 struct vfs_aio_state vfs_aio_state;
1082 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1085 static void vfs_fsync_do(void *private_data);
1086 static void vfs_fsync_done(struct tevent_req *subreq);
1087 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1089 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1090 TALLOC_CTX *mem_ctx,
1091 struct tevent_context *ev,
1092 struct files_struct *fsp)
1094 struct tevent_req *req, *subreq;
1095 struct vfswrap_fsync_state *state;
1097 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1103 state->fd = fsp_get_io_fd(fsp);
1105 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1106 state->profile_bytes, 0);
1107 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1109 subreq = pthreadpool_tevent_job_send(
1110 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1111 if (tevent_req_nomem(subreq, req)) {
1112 return tevent_req_post(req, ev);
1114 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1116 talloc_set_destructor(state, vfs_fsync_state_destructor);
1121 static void vfs_fsync_do(void *private_data)
1123 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1124 private_data, struct vfswrap_fsync_state);
1125 struct timespec start_time;
1126 struct timespec end_time;
1128 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1130 PROFILE_TIMESTAMP(&start_time);
1133 state->ret = fsync(state->fd);
1134 } while ((state->ret == -1) && (errno == EINTR));
1136 if (state->ret == -1) {
1137 state->vfs_aio_state.error = errno;
1140 PROFILE_TIMESTAMP(&end_time);
1142 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1144 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1147 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1152 static void vfs_fsync_done(struct tevent_req *subreq)
1154 struct tevent_req *req = tevent_req_callback_data(
1155 subreq, struct tevent_req);
1156 struct vfswrap_fsync_state *state = tevent_req_data(
1157 req, struct vfswrap_fsync_state);
1160 ret = pthreadpool_tevent_job_recv(subreq);
1161 TALLOC_FREE(subreq);
1162 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1163 talloc_set_destructor(state, NULL);
1165 if (ret != EAGAIN) {
1166 tevent_req_error(req, ret);
1170 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1171 * means the lower level pthreadpool failed to create a new
1172 * thread. Fallback to sync processing in that case to allow
1173 * some progress for the client.
1175 vfs_fsync_do(state);
1178 tevent_req_done(req);
1181 static int vfswrap_fsync_recv(struct tevent_req *req,
1182 struct vfs_aio_state *vfs_aio_state)
1184 struct vfswrap_fsync_state *state = tevent_req_data(
1185 req, struct vfswrap_fsync_state);
1187 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1191 *vfs_aio_state = state->vfs_aio_state;
1195 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1199 START_PROFILE(syscall_lseek);
1201 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1203 * We want to maintain the fiction that we can seek
1204 * on a fifo for file system purposes. This allows
1205 * people to set up UNIX fifo's that feed data to Windows
1206 * applications. JRA.
1209 if((result == -1) && (errno == ESPIPE)) {
1214 END_PROFILE(syscall_lseek);
1218 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1219 off_t offset, size_t n)
1223 START_PROFILE_BYTES(syscall_sendfile, n);
1224 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1225 END_PROFILE_BYTES(syscall_sendfile);
1229 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1231 files_struct *tofsp,
1237 START_PROFILE_BYTES(syscall_recvfile, n);
1238 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1239 END_PROFILE_BYTES(syscall_recvfile);
1243 static int vfswrap_renameat(vfs_handle_struct *handle,
1244 files_struct *srcfsp,
1245 const struct smb_filename *smb_fname_src,
1246 files_struct *dstfsp,
1247 const struct smb_filename *smb_fname_dst)
1251 START_PROFILE(syscall_renameat);
1253 if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) {
1258 result = renameat(fsp_get_pathref_fd(srcfsp),
1259 smb_fname_src->base_name,
1260 fsp_get_pathref_fd(dstfsp),
1261 smb_fname_dst->base_name);
1264 END_PROFILE(syscall_renameat);
1268 static int vfswrap_stat(vfs_handle_struct *handle,
1269 struct smb_filename *smb_fname)
1273 START_PROFILE(syscall_stat);
1275 if (is_named_stream(smb_fname)) {
1280 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1281 lp_fake_directory_create_times(SNUM(handle->conn)));
1283 END_PROFILE(syscall_stat);
1287 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1291 START_PROFILE(syscall_fstat);
1292 result = sys_fstat(fsp_get_pathref_fd(fsp),
1293 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1294 END_PROFILE(syscall_fstat);
1298 static int vfswrap_lstat(vfs_handle_struct *handle,
1299 struct smb_filename *smb_fname)
1303 START_PROFILE(syscall_lstat);
1305 if (is_named_stream(smb_fname)) {
1310 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1311 lp_fake_directory_create_times(SNUM(handle->conn)));
1313 END_PROFILE(syscall_lstat);
1317 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1319 enum vfs_translate_direction direction,
1320 TALLOC_CTX *mem_ctx,
1323 return NT_STATUS_NONE_MAPPED;
1327 * Return allocated parent directory and basename of path
1329 * Note: if requesting name, it is returned as talloc child of the
1330 * parent. Freeing the parent is thus sufficient to free both.
1332 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1333 TALLOC_CTX *mem_ctx,
1334 const struct smb_filename *smb_fname_in,
1335 struct smb_filename **parent_dir_out,
1336 struct smb_filename **atname_out)
1338 TALLOC_CTX *frame = talloc_stackframe();
1339 struct smb_filename *parent = NULL;
1340 struct smb_filename *name = NULL;
1343 parent = cp_smb_filename(frame, smb_fname_in);
1344 if (parent == NULL) {
1346 return NT_STATUS_NO_MEMORY;
1348 TALLOC_FREE(parent->stream_name);
1349 SET_STAT_INVALID(parent->st);
1351 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1353 TALLOC_FREE(parent->base_name);
1354 parent->base_name = talloc_strdup(parent, ".");
1355 if (parent->base_name == NULL) {
1357 return NT_STATUS_NO_MEMORY;
1359 p = smb_fname_in->base_name;
1365 if (atname_out == NULL) {
1366 *parent_dir_out = talloc_move(mem_ctx, &parent);
1368 return NT_STATUS_OK;
1371 name = cp_smb_filename(frame, smb_fname_in);
1374 return NT_STATUS_NO_MEMORY;
1376 TALLOC_FREE(name->base_name);
1378 name->base_name = talloc_strdup(name, p);
1379 if (name->base_name == NULL) {
1381 return NT_STATUS_NO_MEMORY;
1384 *parent_dir_out = talloc_move(mem_ctx, &parent);
1385 *atname_out = talloc_move(*parent_dir_out, &name);
1387 return NT_STATUS_OK;
1391 * Implement the default fsctl operation.
1393 static bool vfswrap_logged_ioctl_message = false;
1395 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1396 struct files_struct *fsp,
1399 uint16_t req_flags, /* Needed for UNICODE ... */
1400 const uint8_t *_in_data,
1402 uint8_t **_out_data,
1403 uint32_t max_out_len,
1406 const char *in_data = (const char *)_in_data;
1407 char **out_data = (char **)_out_data;
1411 case FSCTL_SET_SPARSE:
1413 bool set_sparse = true;
1415 if (in_len >= 1 && in_data[0] == 0) {
1419 status = file_set_sparse(handle->conn, fsp, set_sparse);
1421 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1422 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1423 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1424 nt_errstr(status)));
1429 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1431 unsigned char objid[16];
1432 char *return_data = NULL;
1434 /* This should return the object-id on this file.
1435 * I think I'll make this be the inode+dev. JRA.
1438 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1439 fsp_fnum_dbg(fsp)));
1441 *out_len = MIN(max_out_len, 64);
1443 /* Hmmm, will this cause problems if less data asked for? */
1444 return_data = talloc_array(ctx, char, 64);
1445 if (return_data == NULL) {
1446 return NT_STATUS_NO_MEMORY;
1449 /* For backwards compatibility only store the dev/inode. */
1450 push_file_id_16(return_data, &fsp->file_id);
1451 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1452 push_file_id_16(return_data+32, &fsp->file_id);
1453 memset(return_data+48, 0, 16);
1454 *out_data = return_data;
1455 return NT_STATUS_OK;
1458 case FSCTL_GET_REPARSE_POINT:
1460 status = fsctl_get_reparse_point(
1461 fsp, ctx, out_data, max_out_len, out_len);
1465 case FSCTL_SET_REPARSE_POINT:
1467 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1471 case FSCTL_DELETE_REPARSE_POINT:
1473 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1477 case FSCTL_GET_SHADOW_COPY_DATA:
1480 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1481 * and return their volume names. If max_data_count is 16, then it is just
1482 * asking for the number of volumes and length of the combined names.
1484 * pdata is the data allocated by our caller, but that uses
1485 * total_data_count (which is 0 in our case) rather than max_data_count.
1486 * Allocate the correct amount and return the pointer to let
1487 * it be deallocated when we return.
1489 struct shadow_copy_data *shadow_data = NULL;
1490 bool labels = False;
1491 uint32_t labels_data_count = 0;
1493 char *cur_pdata = NULL;
1495 if (max_out_len < 16) {
1496 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1498 return NT_STATUS_INVALID_PARAMETER;
1501 if (max_out_len > 16) {
1505 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1506 if (shadow_data == NULL) {
1507 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1508 return NT_STATUS_NO_MEMORY;
1512 * Call the VFS routine to actually do the work.
1514 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1517 /* broken module didn't set errno on error */
1518 status = NT_STATUS_UNSUCCESSFUL;
1520 status = map_nt_error_from_unix(errno);
1521 if (NT_STATUS_EQUAL(status,
1522 NT_STATUS_NOT_SUPPORTED)) {
1526 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1527 "connectpath %s, failed - %s.\n",
1528 fsp->conn->connectpath,
1529 nt_errstr(status)));
1530 TALLOC_FREE(shadow_data);
1534 labels_data_count = (shadow_data->num_volumes * 2 *
1535 sizeof(SHADOW_COPY_LABEL)) + 2;
1540 *out_len = 12 + labels_data_count;
1543 if (max_out_len < *out_len) {
1544 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1545 max_out_len, *out_len));
1546 TALLOC_FREE(shadow_data);
1547 return NT_STATUS_BUFFER_TOO_SMALL;
1550 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1551 if (cur_pdata == NULL) {
1552 TALLOC_FREE(shadow_data);
1553 return NT_STATUS_NO_MEMORY;
1556 *out_data = cur_pdata;
1558 /* num_volumes 4 bytes */
1559 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1562 /* num_labels 4 bytes */
1563 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1566 /* needed_data_count 4 bytes */
1567 SIVAL(cur_pdata, 8, labels_data_count);
1571 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1572 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1573 if (labels && shadow_data->labels) {
1574 for (i=0; i<shadow_data->num_volumes; i++) {
1576 status = srvstr_push(cur_pdata, req_flags,
1577 cur_pdata, shadow_data->labels[i],
1578 2 * sizeof(SHADOW_COPY_LABEL),
1579 STR_UNICODE|STR_TERMINATE, &len);
1580 if (!NT_STATUS_IS_OK(status)) {
1581 TALLOC_FREE(*out_data);
1582 TALLOC_FREE(shadow_data);
1585 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1586 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1590 TALLOC_FREE(shadow_data);
1592 return NT_STATUS_OK;
1595 case FSCTL_FIND_FILES_BY_SID:
1597 /* pretend this succeeded -
1599 * we have to send back a list with all files owned by this SID
1601 * but I have to check that --metze
1605 struct dom_sid_buf buf;
1609 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1610 fsp_fnum_dbg(fsp)));
1613 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1614 return NT_STATUS_INVALID_PARAMETER;
1617 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1619 /* unknown 4 bytes: this is not the length of the sid :-( */
1620 /*unknown = IVAL(pdata,0);*/
1622 ret = sid_parse(_in_data + 4, sid_len, &sid);
1624 return NT_STATUS_INVALID_PARAMETER;
1626 DEBUGADD(10, ("for SID: %s\n",
1627 dom_sid_str_buf(&sid, &buf)));
1629 if (!sid_to_uid(&sid, &uid)) {
1630 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1631 dom_sid_str_buf(&sid, &buf),
1632 (unsigned long)sid_len));
1636 /* we can take a look at the find source :-)
1638 * find ./ -uid $uid -name '*' is what we need here
1641 * and send 4bytes len and then NULL terminated unicode strings
1644 * but I don't know how to deal with the paged results
1645 * (maybe we can hang the result anywhere in the fsp struct)
1647 * but I don't know how to deal with the paged results
1648 * (maybe we can hang the result anywhere in the fsp struct)
1650 * we don't send all files at once
1651 * and at the next we should *not* start from the beginning,
1652 * so we have to cache the result
1657 /* this works for now... */
1658 return NT_STATUS_OK;
1661 case FSCTL_QUERY_ALLOCATED_RANGES:
1663 /* FIXME: This is just a dummy reply, telling that all of the
1664 * file is allocated. MKS cp needs that.
1665 * Adding the real allocated ranges via FIEMAP on Linux
1666 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1667 * this FSCTL correct for sparse files.
1669 uint64_t offset, length;
1670 char *out_data_tmp = NULL;
1673 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1675 return NT_STATUS_INVALID_PARAMETER;
1678 if (max_out_len < 16) {
1679 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1681 return NT_STATUS_INVALID_PARAMETER;
1684 offset = BVAL(in_data,0);
1685 length = BVAL(in_data,8);
1687 if (offset + length < offset) {
1688 /* No 64-bit integer wrap. */
1689 return NT_STATUS_INVALID_PARAMETER;
1692 /* Shouldn't this be SMB_VFS_STAT ... ? */
1693 status = vfs_stat_fsp(fsp);
1694 if (!NT_STATUS_IS_OK(status)) {
1699 out_data_tmp = talloc_array(ctx, char, *out_len);
1700 if (out_data_tmp == NULL) {
1701 DEBUG(10, ("unable to allocate memory for response\n"));
1702 return NT_STATUS_NO_MEMORY;
1705 if (offset > fsp->fsp_name->st.st_ex_size ||
1706 fsp->fsp_name->st.st_ex_size == 0 ||
1708 memset(out_data_tmp, 0, *out_len);
1710 uint64_t end = offset + length;
1711 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1712 SBVAL(out_data_tmp, 0, 0);
1713 SBVAL(out_data_tmp, 8, end);
1716 *out_data = out_data_tmp;
1718 return NT_STATUS_OK;
1721 case FSCTL_IS_VOLUME_DIRTY:
1723 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1724 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1726 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1727 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1729 return NT_STATUS_INVALID_PARAMETER;
1734 * Only print once ... unfortunately there could be lots of
1735 * different FSCTLs that are called.
1737 if (!vfswrap_logged_ioctl_message) {
1738 vfswrap_logged_ioctl_message = true;
1739 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1740 __func__, function));
1744 return NT_STATUS_NOT_SUPPORTED;
1747 static bool vfswrap_is_offline(struct connection_struct *conn,
1748 const struct smb_filename *fname);
1750 struct vfswrap_get_dos_attributes_state {
1751 struct vfs_aio_state aio_state;
1752 connection_struct *conn;
1753 TALLOC_CTX *mem_ctx;
1754 struct tevent_context *ev;
1755 files_struct *dir_fsp;
1756 struct smb_filename *smb_fname;
1761 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1763 static struct tevent_req *vfswrap_get_dos_attributes_send(
1764 TALLOC_CTX *mem_ctx,
1765 struct tevent_context *ev,
1766 struct vfs_handle_struct *handle,
1767 files_struct *dir_fsp,
1768 struct smb_filename *smb_fname)
1770 struct tevent_req *req = NULL;
1771 struct tevent_req *subreq = NULL;
1772 struct vfswrap_get_dos_attributes_state *state = NULL;
1774 req = tevent_req_create(mem_ctx, &state,
1775 struct vfswrap_get_dos_attributes_state);
1780 *state = (struct vfswrap_get_dos_attributes_state) {
1781 .conn = dir_fsp->conn,
1785 .smb_fname = smb_fname,
1788 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1792 SAMBA_XATTR_DOS_ATTRIB,
1794 if (tevent_req_nomem(subreq, req)) {
1795 return tevent_req_post(req, ev);
1797 tevent_req_set_callback(subreq,
1798 vfswrap_get_dos_attributes_getxattr_done,
1804 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1806 struct tevent_req *req =
1807 tevent_req_callback_data(subreq,
1809 struct vfswrap_get_dos_attributes_state *state =
1810 tevent_req_data(req,
1811 struct vfswrap_get_dos_attributes_state);
1813 DATA_BLOB blob = {0};
1815 char *tofree = NULL;
1816 char pathbuf[PATH_MAX+1];
1818 struct smb_filename smb_fname;
1822 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1826 TALLOC_FREE(subreq);
1827 if (xattr_size == -1) {
1828 status = map_nt_error_from_unix(state->aio_state.error);
1830 if (state->as_root) {
1831 tevent_req_nterror(req, status);
1834 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1835 tevent_req_nterror(req, status);
1839 state->as_root = true;
1842 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1846 SAMBA_XATTR_DOS_ATTRIB,
1849 if (tevent_req_nomem(subreq, req)) {
1852 tevent_req_set_callback(subreq,
1853 vfswrap_get_dos_attributes_getxattr_done,
1858 blob.length = xattr_size;
1860 status = parse_dos_attribute_blob(state->smb_fname,
1863 if (!NT_STATUS_IS_OK(status)) {
1864 tevent_req_nterror(req, status);
1868 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1869 state->smb_fname->base_name,
1874 if (pathlen == -1) {
1875 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1879 smb_fname = (struct smb_filename) {
1881 .st = state->smb_fname->st,
1882 .flags = state->smb_fname->flags,
1883 .twrp = state->smb_fname->twrp,
1886 offline = vfswrap_is_offline(state->conn, &smb_fname);
1888 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1890 TALLOC_FREE(tofree);
1892 tevent_req_done(req);
1896 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1897 struct vfs_aio_state *aio_state,
1900 struct vfswrap_get_dos_attributes_state *state =
1901 tevent_req_data(req,
1902 struct vfswrap_get_dos_attributes_state);
1905 if (tevent_req_is_nterror(req, &status)) {
1906 tevent_req_received(req);
1910 *aio_state = state->aio_state;
1911 *dosmode = state->dosmode;
1912 tevent_req_received(req);
1913 return NT_STATUS_OK;
1916 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1917 struct files_struct *fsp,
1922 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1924 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1927 return fget_ea_dos_attribute(fsp, dosmode);
1930 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1931 struct files_struct *fsp,
1934 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1937 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1939 struct vfswrap_offload_read_state {
1943 static struct tevent_req *vfswrap_offload_read_send(
1944 TALLOC_CTX *mem_ctx,
1945 struct tevent_context *ev,
1946 struct vfs_handle_struct *handle,
1947 struct files_struct *fsp,
1953 struct tevent_req *req = NULL;
1954 struct vfswrap_offload_read_state *state = NULL;
1957 req = tevent_req_create(mem_ctx, &state,
1958 struct vfswrap_offload_read_state);
1963 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
1964 &vfswrap_offload_ctx);
1965 if (tevent_req_nterror(req, status)) {
1966 return tevent_req_post(req, ev);
1969 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
1970 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
1971 return tevent_req_post(req, ev);
1974 status = vfs_offload_token_create_blob(state, fsp, fsctl,
1976 if (tevent_req_nterror(req, status)) {
1977 return tevent_req_post(req, ev);
1980 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
1982 if (tevent_req_nterror(req, status)) {
1983 return tevent_req_post(req, ev);
1986 tevent_req_done(req);
1987 return tevent_req_post(req, ev);
1990 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
1991 struct vfs_handle_struct *handle,
1992 TALLOC_CTX *mem_ctx,
1997 struct vfswrap_offload_read_state *state = tevent_req_data(
1998 req, struct vfswrap_offload_read_state);
2001 if (tevent_req_is_nterror(req, &status)) {
2002 tevent_req_received(req);
2008 token->length = state->token.length;
2009 token->data = talloc_move(mem_ctx, &state->token.data);
2011 tevent_req_received(req);
2012 return NT_STATUS_OK;
2015 struct vfswrap_offload_write_state {
2017 bool read_lck_locked;
2018 bool write_lck_locked;
2020 struct tevent_context *src_ev;
2021 struct files_struct *src_fsp;
2023 struct tevent_context *dst_ev;
2024 struct files_struct *dst_fsp;
2029 size_t next_io_size;
2032 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2033 enum tevent_req_state req_state)
2035 struct vfswrap_offload_write_state *state = tevent_req_data(
2036 req, struct vfswrap_offload_write_state);
2039 if (state->dst_fsp == NULL) {
2043 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2045 state->dst_fsp = NULL;
2048 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2049 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2051 static struct tevent_req *vfswrap_offload_write_send(
2052 struct vfs_handle_struct *handle,
2053 TALLOC_CTX *mem_ctx,
2054 struct tevent_context *ev,
2057 off_t transfer_offset,
2058 struct files_struct *dest_fsp,
2062 struct tevent_req *req;
2063 struct vfswrap_offload_write_state *state = NULL;
2064 /* off_t is signed! */
2065 off_t max_offset = INT64_MAX - to_copy;
2066 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2067 files_struct *src_fsp = NULL;
2071 req = tevent_req_create(mem_ctx, &state,
2072 struct vfswrap_offload_write_state);
2077 *state = (struct vfswrap_offload_write_state) {
2079 .src_off = transfer_offset,
2081 .dst_fsp = dest_fsp,
2082 .dst_off = dest_off,
2084 .remaining = to_copy,
2087 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2090 case FSCTL_SRV_COPYCHUNK:
2091 case FSCTL_SRV_COPYCHUNK_WRITE:
2094 case FSCTL_OFFLOAD_WRITE:
2095 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2096 return tevent_req_post(req, ev);
2098 case FSCTL_DUP_EXTENTS_TO_FILE:
2099 DBG_DEBUG("COW clones not supported by vfs_default\n");
2100 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2101 return tevent_req_post(req, ev);
2104 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2105 return tevent_req_post(req, ev);
2109 * From here on we assume a copy-chunk fsctl
2113 tevent_req_done(req);
2114 return tevent_req_post(req, ev);
2117 if (state->src_off > max_offset) {
2119 * Protect integer checks below.
2121 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2122 return tevent_req_post(req, ev);
2124 if (state->src_off < 0) {
2126 * Protect integer checks below.
2128 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2129 return tevent_req_post(req, ev);
2131 if (state->dst_off > max_offset) {
2133 * Protect integer checks below.
2135 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2136 return tevent_req_post(req, ev);
2138 if (state->dst_off < 0) {
2140 * Protect integer checks below.
2142 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2143 return tevent_req_post(req, ev);
2146 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2148 if (tevent_req_nterror(req, status)) {
2149 return tevent_req_post(req, ev);
2152 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2154 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2155 if (!NT_STATUS_IS_OK(status)) {
2156 tevent_req_nterror(req, status);
2157 return tevent_req_post(req, ev);
2160 ok = change_to_user_and_service_by_fsp(src_fsp);
2162 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2163 return tevent_req_post(req, ev);
2166 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2167 state->src_fsp = src_fsp;
2169 status = vfs_stat_fsp(src_fsp);
2170 if (tevent_req_nterror(req, status)) {
2171 return tevent_req_post(req, ev);
2174 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2176 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2177 * If the SourceOffset or SourceOffset + Length extends beyond
2178 * the end of file, the server SHOULD<240> treat this as a
2179 * STATUS_END_OF_FILE error.
2181 * <240> Section 3.3.5.15.6: Windows servers will return
2182 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2184 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2185 return tevent_req_post(req, ev);
2188 status = vfswrap_offload_copy_file_range(req);
2189 if (NT_STATUS_IS_OK(status)) {
2190 tevent_req_done(req);
2191 return tevent_req_post(req, ev);
2193 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2194 tevent_req_nterror(req, status);
2195 return tevent_req_post(req, ev);
2198 state->buf = talloc_array(state, uint8_t, num);
2199 if (tevent_req_nomem(state->buf, req)) {
2200 return tevent_req_post(req, ev);
2203 status = vfswrap_offload_write_loop(req);
2204 if (!NT_STATUS_IS_OK(status)) {
2205 tevent_req_nterror(req, status);
2206 return tevent_req_post(req, ev);
2212 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2214 struct vfswrap_offload_write_state *state = tevent_req_data(
2215 req, struct vfswrap_offload_write_state);
2216 struct lock_struct lck;
2221 static bool try_copy_file_range = true;
2223 if (!try_copy_file_range) {
2224 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2227 same_file = file_id_equal(&state->src_fsp->file_id,
2228 &state->dst_fsp->file_id);
2230 sys_io_ranges_overlap(state->remaining,
2235 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2238 if (is_named_stream(state->src_fsp->fsp_name) ||
2239 is_named_stream(state->dst_fsp->fsp_name))
2241 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2244 init_strict_lock_struct(state->src_fsp,
2245 state->src_fsp->op->global->open_persistent_id,
2251 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2255 return NT_STATUS_FILE_LOCK_CONFLICT;
2258 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2260 return NT_STATUS_INTERNAL_ERROR;
2263 init_strict_lock_struct(state->dst_fsp,
2264 state->dst_fsp->op->global->open_persistent_id,
2270 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2274 return NT_STATUS_FILE_LOCK_CONFLICT;
2277 while (state->remaining > 0) {
2278 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2280 fsp_get_io_fd(state->dst_fsp),
2284 if (nwritten == -1) {
2285 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2286 "n [%jd] failed: %s\n",
2287 fsp_str_dbg(state->src_fsp),
2288 (intmax_t)state->src_off,
2289 fsp_str_dbg(state->dst_fsp),
2290 (intmax_t)state->dst_off,
2291 (intmax_t)state->remaining,
2296 try_copy_file_range = false;
2297 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2300 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2303 status = map_nt_error_from_unix(errno);
2304 if (NT_STATUS_EQUAL(
2306 NT_STATUS_MORE_PROCESSING_REQUIRED))
2308 /* Avoid triggering the fallback */
2309 status = NT_STATUS_INTERNAL_ERROR;
2316 if (state->remaining < nwritten) {
2317 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2318 "n [%jd] remaining [%jd]\n",
2319 fsp_str_dbg(state->src_fsp),
2320 fsp_str_dbg(state->dst_fsp),
2322 (intmax_t)state->remaining);
2323 return NT_STATUS_INTERNAL_ERROR;
2326 if (nwritten == 0) {
2329 state->copied += nwritten;
2330 state->remaining -= nwritten;
2334 * Tell the req cleanup function there's no need to call
2335 * change_to_user_and_service_by_fsp() on the dst handle.
2337 state->dst_fsp = NULL;
2338 return NT_STATUS_OK;
2341 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2343 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2345 struct vfswrap_offload_write_state *state = tevent_req_data(
2346 req, struct vfswrap_offload_write_state);
2347 struct tevent_req *subreq = NULL;
2348 struct lock_struct read_lck;
2352 * This is called under the context of state->src_fsp.
2355 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2357 init_strict_lock_struct(state->src_fsp,
2358 state->src_fsp->op->global->open_persistent_id,
2360 state->next_io_size,
2364 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2368 return NT_STATUS_FILE_LOCK_CONFLICT;
2371 subreq = SMB_VFS_PREAD_SEND(state,
2375 state->next_io_size,
2377 if (subreq == NULL) {
2378 return NT_STATUS_NO_MEMORY;
2380 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2382 return NT_STATUS_OK;
2385 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2387 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2389 struct tevent_req *req = tevent_req_callback_data(
2390 subreq, struct tevent_req);
2391 struct vfswrap_offload_write_state *state = tevent_req_data(
2392 req, struct vfswrap_offload_write_state);
2393 struct vfs_aio_state aio_state;
2394 struct lock_struct write_lck;
2398 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2399 TALLOC_FREE(subreq);
2401 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2402 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2405 if (nread != state->next_io_size) {
2406 DBG_ERR("Short read, only %zd of %zu\n",
2407 nread, state->next_io_size);
2408 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2412 state->src_off += nread;
2414 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2416 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2420 init_strict_lock_struct(state->dst_fsp,
2421 state->dst_fsp->op->global->open_persistent_id,
2423 state->next_io_size,
2427 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2431 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2435 subreq = SMB_VFS_PWRITE_SEND(state,
2439 state->next_io_size,
2441 if (subreq == NULL) {
2442 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2445 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2448 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2450 struct tevent_req *req = tevent_req_callback_data(
2451 subreq, struct tevent_req);
2452 struct vfswrap_offload_write_state *state = tevent_req_data(
2453 req, struct vfswrap_offload_write_state);
2454 struct vfs_aio_state aio_state;
2459 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2460 TALLOC_FREE(subreq);
2461 if (nwritten == -1) {
2462 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2463 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2466 if (nwritten != state->next_io_size) {
2467 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2468 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2472 state->dst_off += nwritten;
2474 if (state->remaining < nwritten) {
2475 /* Paranoia check */
2476 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2479 state->copied += nwritten;
2480 state->remaining -= nwritten;
2481 if (state->remaining == 0) {
2482 tevent_req_done(req);
2486 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2488 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2492 status = vfswrap_offload_write_loop(req);
2493 if (!NT_STATUS_IS_OK(status)) {
2494 tevent_req_nterror(req, status);
2501 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2502 struct tevent_req *req,
2505 struct vfswrap_offload_write_state *state = tevent_req_data(
2506 req, struct vfswrap_offload_write_state);
2509 if (tevent_req_is_nterror(req, &status)) {
2510 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2512 tevent_req_received(req);
2516 *copied = state->copied;
2517 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2518 tevent_req_received(req);
2520 return NT_STATUS_OK;
2523 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2524 TALLOC_CTX *mem_ctx,
2525 struct files_struct *fsp,
2526 uint16_t *_compression_fmt)
2528 return NT_STATUS_INVALID_DEVICE_REQUEST;
2531 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2532 TALLOC_CTX *mem_ctx,
2533 struct files_struct *fsp,
2534 uint16_t compression_fmt)
2536 return NT_STATUS_INVALID_DEVICE_REQUEST;
2539 /********************************************************************
2540 Given a stat buffer return the allocated size on disk, taking into
2541 account sparse files.
2542 ********************************************************************/
2543 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2544 struct files_struct *fsp,
2545 const SMB_STRUCT_STAT *sbuf)
2549 START_PROFILE(syscall_get_alloc_size);
2551 if(S_ISDIR(sbuf->st_ex_mode)) {
2556 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2557 /* The type of st_blocksize is blkcnt_t which *MUST* be
2558 signed (according to POSIX) and can be less than 64-bits.
2559 Ensure when we're converting to 64 bits wide we don't
2561 #if defined(SIZEOF_BLKCNT_T_8)
2562 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2563 #elif defined(SIZEOF_BLKCNT_T_4)
2565 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2566 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2569 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2573 * Some file systems do not allocate a block for very
2574 * small files. But for non-empty file should report a
2578 uint64_t filesize = get_file_size_stat(sbuf);
2580 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2584 result = get_file_size_stat(sbuf);
2587 if (fsp && fsp->initial_allocation_size)
2588 result = MAX(result,fsp->initial_allocation_size);
2590 result = smb_roundup(handle->conn, result);
2593 END_PROFILE(syscall_get_alloc_size);
2597 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2598 struct files_struct *dirfsp,
2599 const struct smb_filename *smb_fname,
2604 START_PROFILE(syscall_unlinkat);
2606 if (is_named_stream(smb_fname)) {
2610 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2611 smb_fname->base_name,
2615 END_PROFILE(syscall_unlinkat);
2619 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2623 START_PROFILE(syscall_fchmod);
2625 if (!fsp->fsp_flags.is_pathref) {
2626 result = fchmod(fsp_get_io_fd(fsp), mode);
2627 END_PROFILE(syscall_fchmod);
2631 if (fsp->fsp_flags.have_proc_fds) {
2632 int fd = fsp_get_pathref_fd(fsp);
2633 const char *p = NULL;
2636 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2638 result = chmod(p, mode);
2642 END_PROFILE(syscall_fchmod);
2647 * This is no longer a handle based call.
2649 result = chmod(fsp->fsp_name->base_name, mode);
2651 END_PROFILE(syscall_fchmod);
2655 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2660 START_PROFILE(syscall_fchown);
2661 if (!fsp->fsp_flags.is_pathref) {
2662 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2663 END_PROFILE(syscall_fchown);
2667 if (fsp->fsp_flags.have_proc_fds) {
2668 int fd = fsp_get_pathref_fd(fsp);
2669 const char *p = NULL;
2672 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2674 result = chown(p, uid, gid);
2678 END_PROFILE(syscall_fchown);
2683 * This is no longer a handle based call.
2685 result = chown(fsp->fsp_name->base_name, uid, gid);
2686 END_PROFILE(syscall_fchown);
2694 static int vfswrap_lchown(vfs_handle_struct *handle,
2695 const struct smb_filename *smb_fname,
2701 START_PROFILE(syscall_lchown);
2702 result = lchown(smb_fname->base_name, uid, gid);
2703 END_PROFILE(syscall_lchown);
2707 static int vfswrap_chdir(vfs_handle_struct *handle,
2708 const struct smb_filename *smb_fname)
2712 START_PROFILE(syscall_chdir);
2713 result = chdir(smb_fname->base_name);
2714 END_PROFILE(syscall_chdir);
2718 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2722 struct smb_filename *smb_fname = NULL;
2724 START_PROFILE(syscall_getwd);
2725 result = sys_getwd();
2726 END_PROFILE(syscall_getwd);
2728 if (result == NULL) {
2731 smb_fname = synthetic_smb_fname(ctx,
2738 * sys_getwd() *always* returns malloced memory.
2739 * We must free here to avoid leaks:
2740 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2746 /*********************************************************************
2747 nsec timestamp resolution call. Convert down to whatever the underlying
2748 system will support.
2749 **********************************************************************/
2751 static int vfswrap_fntimes(vfs_handle_struct *handle,
2753 struct smb_file_time *ft)
2756 struct timespec ts[2];
2757 struct timespec *times = NULL;
2759 START_PROFILE(syscall_fntimes);
2761 if (is_named_stream(fsp->fsp_name)) {
2767 if (is_omit_timespec(&ft->atime)) {
2768 ft->atime = fsp->fsp_name->st.st_ex_atime;
2771 if (is_omit_timespec(&ft->mtime)) {
2772 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2775 if (!is_omit_timespec(&ft->create_time)) {
2776 set_create_timespec_ea(fsp,
2780 if ((timespec_compare(&ft->atime,
2781 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2782 (timespec_compare(&ft->mtime,
2783 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2795 if (!fsp->fsp_flags.is_pathref) {
2796 result = futimens(fsp_get_io_fd(fsp), times);
2800 if (fsp->fsp_flags.have_proc_fds) {
2801 int fd = fsp_get_pathref_fd(fsp);
2802 const char *p = NULL;
2805 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2808 * The dirfd argument of utimensat is ignored when
2809 * pathname is an absolute path
2811 result = utimensat(AT_FDCWD, p, times, 0);
2820 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2821 * path translation mechanism. Fallback to path based call.
2823 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2826 END_PROFILE(syscall_fntimes);
2832 /*********************************************************************
2833 A version of ftruncate that will write the space on disk if strict
2835 **********************************************************************/
2837 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2839 off_t space_to_write;
2840 uint64_t space_avail;
2841 uint64_t bsize,dfree,dsize;
2844 SMB_STRUCT_STAT *pst;
2847 ok = vfs_valid_pwrite_range(len, 0);
2853 status = vfs_stat_fsp(fsp);
2854 if (!NT_STATUS_IS_OK(status)) {
2857 pst = &fsp->fsp_name->st;
2860 if (S_ISFIFO(pst->st_ex_mode))
2864 if (pst->st_ex_size == len)
2867 /* Shrink - just ftruncate. */
2868 if (pst->st_ex_size > len)
2869 return ftruncate(fsp_get_io_fd(fsp), len);
2871 space_to_write = len - pst->st_ex_size;
2873 /* for allocation try fallocate first. This can fail on some
2874 platforms e.g. when the filesystem doesn't support it and no
2875 emulation is being done by the libc (like on AIX with JFS1). In that
2876 case we do our own emulation. fallocate implementations can
2877 return ENOTSUP or EINVAL in cases like that. */
2878 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2879 if (ret == -1 && errno == ENOSPC) {
2885 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2886 "error %d. Falling back to slow manual allocation\n", errno));
2888 /* available disk space is enough or not? */
2890 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2891 /* space_avail is 1k blocks */
2892 if (space_avail == (uint64_t)-1 ||
2893 ((uint64_t)space_to_write/1024 > space_avail) ) {
2898 /* Write out the real space on disk. */
2899 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2907 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2910 SMB_STRUCT_STAT *pst;
2914 START_PROFILE(syscall_ftruncate);
2916 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2917 result = strict_allocate_ftruncate(handle, fsp, len);
2918 END_PROFILE(syscall_ftruncate);
2922 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2923 ftruncate if the system supports it. Then I discovered that
2924 you can have some filesystems that support ftruncate
2925 expansion and some that don't! On Linux fat can't do
2926 ftruncate extend but ext2 can. */
2928 result = ftruncate(fsp_get_io_fd(fsp), len);
2930 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2931 extend a file with ftruncate. Provide alternate implementation
2934 /* Do an fstat to see if the file is longer than the requested
2935 size in which case the ftruncate above should have
2936 succeeded or shorter, in which case seek to len - 1 and
2937 write 1 byte of zero */
2938 status = vfs_stat_fsp(fsp);
2939 if (!NT_STATUS_IS_OK(status)) {
2943 /* We need to update the files_struct after successful ftruncate */
2948 pst = &fsp->fsp_name->st;
2951 if (S_ISFIFO(pst->st_ex_mode)) {
2957 if (pst->st_ex_size == len) {
2962 if (pst->st_ex_size > len) {
2963 /* the ftruncate should have worked */
2967 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
2975 END_PROFILE(syscall_ftruncate);
2979 static int vfswrap_fallocate(vfs_handle_struct *handle,
2987 START_PROFILE(syscall_fallocate);
2989 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
2991 * posix_fallocate returns 0 on success, errno on error
2992 * and doesn't set errno. Make it behave like fallocate()
2993 * which returns -1, and sets errno on failure.
3000 /* sys_fallocate handles filtering of unsupported mode flags */
3001 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3003 END_PROFILE(syscall_fallocate);
3007 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3011 START_PROFILE(syscall_fcntl_lock);
3013 if (fsp->fsp_flags.use_ofd_locks) {
3014 op = map_process_lock_to_ofd_lock(op);
3017 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3018 END_PROFILE(syscall_fcntl_lock);
3022 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3024 uint32_t share_access,
3025 uint32_t access_mask)
3031 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3035 va_list dup_cmd_arg;
3039 START_PROFILE(syscall_fcntl);
3041 va_copy(dup_cmd_arg, cmd_arg);
3047 #if defined(HAVE_OFD_LOCKS)
3052 #if defined(HAVE_F_OWNER_EX)
3056 #if defined(HAVE_RW_HINTS)
3059 case F_GET_FILE_RW_HINT:
3060 case F_SET_FILE_RW_HINT:
3062 argp = va_arg(dup_cmd_arg, void *);
3063 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3066 val = va_arg(dup_cmd_arg, int);
3067 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3070 va_end(dup_cmd_arg);
3072 END_PROFILE(syscall_fcntl);
3076 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3081 START_PROFILE(syscall_fcntl_getlock);
3083 if (fsp->fsp_flags.use_ofd_locks) {
3084 op = map_process_lock_to_ofd_lock(op);
3087 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3088 END_PROFILE(syscall_fcntl_getlock);
3092 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3097 START_PROFILE(syscall_linux_setlease);
3099 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3100 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3104 END_PROFILE(syscall_linux_setlease);
3108 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3109 const struct smb_filename *link_target,
3110 struct files_struct *dirfsp,
3111 const struct smb_filename *new_smb_fname)
3115 START_PROFILE(syscall_symlinkat);
3117 result = symlinkat(link_target->base_name,
3118 fsp_get_pathref_fd(dirfsp),
3119 new_smb_fname->base_name);
3120 END_PROFILE(syscall_symlinkat);
3124 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3125 const struct files_struct *dirfsp,
3126 const struct smb_filename *smb_fname,
3132 START_PROFILE(syscall_readlinkat);
3134 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3135 smb_fname->base_name,
3139 END_PROFILE(syscall_readlinkat);
3143 static int vfswrap_linkat(vfs_handle_struct *handle,
3144 files_struct *srcfsp,
3145 const struct smb_filename *old_smb_fname,
3146 files_struct *dstfsp,
3147 const struct smb_filename *new_smb_fname,
3152 START_PROFILE(syscall_linkat);
3154 result = linkat(fsp_get_pathref_fd(srcfsp),
3155 old_smb_fname->base_name,
3156 fsp_get_pathref_fd(dstfsp),
3157 new_smb_fname->base_name,
3160 END_PROFILE(syscall_linkat);
3164 static int vfswrap_mknodat(vfs_handle_struct *handle,
3165 files_struct *dirfsp,
3166 const struct smb_filename *smb_fname,
3172 START_PROFILE(syscall_mknodat);
3174 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3175 smb_fname->base_name,
3179 END_PROFILE(syscall_mknodat);
3183 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3185 const struct smb_filename *smb_fname)
3188 struct smb_filename *result_fname = NULL;
3190 START_PROFILE(syscall_realpath);
3191 result = sys_realpath(smb_fname->base_name);
3192 END_PROFILE(syscall_realpath);
3194 result_fname = synthetic_smb_fname(ctx,
3202 return result_fname;
3205 static int vfswrap_fchflags(vfs_handle_struct *handle,
3206 struct files_struct *fsp,
3209 #ifdef HAVE_FCHFLAGS
3210 int fd = fsp_get_pathref_fd(fsp);
3212 if (!fsp->fsp_flags.is_pathref) {
3213 return fchflags(fd, flags);
3216 if (fsp->fsp_flags.have_proc_fds) {
3217 const char *p = NULL;
3220 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3225 return chflags(p, flags);
3229 * This is no longer a handle based call.
3231 return chflags(fsp->fsp_name->base_name, flags);
3238 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3239 const SMB_STRUCT_STAT *sbuf)
3243 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3247 key.devid = sbuf->st_ex_dev;
3248 key.inode = sbuf->st_ex_ino;
3249 /* key.extid is unused by default. */
3254 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3255 const SMB_STRUCT_STAT *psbuf)
3259 if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
3260 return psbuf->st_ex_file_id;
3263 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3264 return (uint64_t)psbuf->st_ex_ino;
3268 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3271 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3276 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3277 struct files_struct *fsp,
3278 TALLOC_CTX *mem_ctx,
3279 unsigned int *pnum_streams,
3280 struct stream_struct **pstreams)
3282 struct stream_struct *tmp_streams = NULL;
3283 unsigned int num_streams = *pnum_streams;
3284 struct stream_struct *streams = *pstreams;
3287 if (fsp->fsp_flags.is_directory) {
3289 * No default streams on directories
3293 status = vfs_stat_fsp(fsp);
3294 if (!NT_STATUS_IS_OK(status)) {
3298 if (num_streams + 1 < 1) {
3300 return NT_STATUS_INVALID_PARAMETER;
3303 tmp_streams = talloc_realloc(mem_ctx,
3305 struct stream_struct,
3307 if (tmp_streams == NULL) {
3308 return NT_STATUS_NO_MEMORY;
3310 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3311 if (tmp_streams[num_streams].name == NULL) {
3312 return NT_STATUS_NO_MEMORY;
3314 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3315 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3318 &fsp->fsp_name->st);
3321 *pnum_streams = num_streams;
3322 *pstreams = tmp_streams;
3324 return NT_STATUS_OK;
3327 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
3328 const struct smb_filename *path,
3330 TALLOC_CTX *mem_ctx,
3334 * Don't fall back to get_real_filename so callers can differentiate
3335 * between a full directory scan and an actual case-insensitive stat.
3341 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3342 const struct smb_filename *smb_fname)
3344 return handle->conn->connectpath;
3347 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3348 struct byte_range_lock *br_lck,
3349 struct lock_struct *plock)
3351 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3353 /* Note: blr is not used in the default implementation. */
3354 return brl_lock_windows_default(br_lck, plock);
3357 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3358 struct byte_range_lock *br_lck,
3359 const struct lock_struct *plock)
3361 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3363 return brl_unlock_windows_default(br_lck, plock);
3366 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3368 struct lock_struct *plock)
3370 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3371 plock->lock_type == WRITE_LOCK);
3373 return strict_lock_check_default(fsp, plock);
3376 /* NT ACL operations. */
3378 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3380 uint32_t security_info,
3381 TALLOC_CTX *mem_ctx,
3382 struct security_descriptor **ppdesc)
3386 START_PROFILE(fget_nt_acl);
3387 result = posix_fget_nt_acl(fsp, security_info,
3389 END_PROFILE(fget_nt_acl);
3393 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3397 START_PROFILE(fset_nt_acl);
3398 result = set_nt_acl(fsp, security_info_sent, psd);
3399 END_PROFILE(fset_nt_acl);
3403 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3404 struct smb_filename *file,
3405 struct security_acl *sacl,
3406 uint32_t access_requested,
3407 uint32_t access_denied)
3409 return NT_STATUS_OK; /* Nothing to do here ... */
3412 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3414 SMB_ACL_TYPE_T type,
3415 TALLOC_CTX *mem_ctx)
3417 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3420 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3422 SMB_ACL_TYPE_T type,
3425 return sys_acl_set_fd(handle, fsp, type, theacl);
3428 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3431 return sys_acl_delete_def_fd(handle, fsp);
3434 /****************************************************************
3435 Extended attribute operations.
3436 *****************************************************************/
3438 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3439 struct files_struct *fsp,
3444 int fd = fsp_get_pathref_fd(fsp);
3446 if (!fsp->fsp_flags.is_pathref) {
3447 return fgetxattr(fd, name, value, size);
3450 if (fsp->fsp_flags.have_proc_fds) {
3451 const char *p = NULL;
3454 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3459 return getxattr(p, name, value, size);
3463 * This is no longer a handle based call.
3465 return getxattr(fsp->fsp_name->base_name, name, value, size);
3468 struct vfswrap_getxattrat_state {
3469 struct tevent_context *ev;
3470 struct vfs_handle_struct *handle;
3471 files_struct *dir_fsp;
3472 const struct smb_filename *smb_fname;
3475 * The following variables are talloced off "state" which is protected
3476 * by a destructor and thus are guaranteed to be safe to be used in the
3477 * job function in the worker thread.
3480 const char *xattr_name;
3481 uint8_t *xattr_value;
3482 struct security_unix_token *token;
3485 struct vfs_aio_state vfs_aio_state;
3486 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3489 static int vfswrap_getxattrat_state_destructor(
3490 struct vfswrap_getxattrat_state *state)
3495 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3496 static void vfswrap_getxattrat_do_async(void *private_data);
3497 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3499 static struct tevent_req *vfswrap_getxattrat_send(
3500 TALLOC_CTX *mem_ctx,
3501 struct tevent_context *ev,
3502 struct vfs_handle_struct *handle,
3503 files_struct *dir_fsp,
3504 const struct smb_filename *smb_fname,
3505 const char *xattr_name,
3508 struct tevent_req *req = NULL;
3509 struct tevent_req *subreq = NULL;
3510 struct vfswrap_getxattrat_state *state = NULL;
3511 size_t max_threads = 0;
3512 bool have_per_thread_cwd = false;
3513 bool have_per_thread_creds = false;
3514 bool do_async = false;
3516 req = tevent_req_create(mem_ctx, &state,
3517 struct vfswrap_getxattrat_state);
3521 *state = (struct vfswrap_getxattrat_state) {
3525 .smb_fname = smb_fname,
3528 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3529 if (max_threads >= 1) {
3531 * We need a non sync threadpool!
3533 have_per_thread_cwd = per_thread_cwd_supported();
3535 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3536 have_per_thread_creds = true;
3538 if (have_per_thread_cwd && have_per_thread_creds) {
3542 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3543 state->profile_bytes, 0);
3545 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3546 DBG_ERR("Need a valid directory fd\n");
3547 tevent_req_error(req, EINVAL);
3548 return tevent_req_post(req, ev);
3551 if (alloc_hint > 0) {
3552 state->xattr_value = talloc_zero_array(state,
3555 if (tevent_req_nomem(state->xattr_value, req)) {
3556 return tevent_req_post(req, ev);
3561 vfswrap_getxattrat_do_sync(req);
3562 return tevent_req_post(req, ev);
3566 * Now allocate all parameters from a memory context that won't go away
3567 * no matter what. These paremeters will get used in threads and we
3568 * can't reliably cancel threads, so all buffers passed to the threads
3569 * must not be freed before all referencing threads terminate.
3572 state->name = talloc_strdup(state, smb_fname->base_name);
3573 if (tevent_req_nomem(state->name, req)) {
3574 return tevent_req_post(req, ev);
3577 state->xattr_name = talloc_strdup(state, xattr_name);
3578 if (tevent_req_nomem(state->xattr_name, req)) {
3579 return tevent_req_post(req, ev);
3583 * This is a hot codepath so at first glance one might think we should
3584 * somehow optimize away the token allocation and do a
3585 * talloc_reference() or similar black magic instead. But due to the
3586 * talloc_stackframe pool per SMB2 request this should be a simple copy
3587 * without a malloc in most cases.
3589 if (geteuid() == sec_initial_uid()) {
3590 state->token = root_unix_token(state);
3592 state->token = copy_unix_token(
3594 dir_fsp->conn->session_info->unix_token);
3596 if (tevent_req_nomem(state->token, req)) {
3597 return tevent_req_post(req, ev);
3600 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3602 subreq = pthreadpool_tevent_job_send(
3605 dir_fsp->conn->sconn->pool,
3606 vfswrap_getxattrat_do_async,
3608 if (tevent_req_nomem(subreq, req)) {
3609 return tevent_req_post(req, ev);
3611 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3613 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3618 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3620 struct vfswrap_getxattrat_state *state = tevent_req_data(
3621 req, struct vfswrap_getxattrat_state);
3622 struct files_struct *fsp = state->smb_fname->fsp;
3624 if (fsp->base_fsp != NULL) {
3625 fsp = fsp->base_fsp;
3628 state->xattr_size = vfswrap_fgetxattr(state->handle,
3632 talloc_array_length(state->xattr_value));
3633 if (state->xattr_size == -1) {
3634 tevent_req_error(req, errno);
3638 tevent_req_done(req);
3642 static void vfswrap_getxattrat_do_async(void *private_data)
3644 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3645 private_data, struct vfswrap_getxattrat_state);
3646 struct timespec start_time;
3647 struct timespec end_time;
3649 struct files_struct *fsp = state->smb_fname->fsp;
3651 if (fsp->base_fsp != NULL) {
3652 fsp = fsp->base_fsp;
3655 PROFILE_TIMESTAMP(&start_time);
3656 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3659 * Here we simulate a getxattrat()
3660 * call using fchdir();getxattr()
3663 per_thread_cwd_activate();
3665 /* Become the correct credential on this thread. */
3666 ret = set_thread_credentials(state->token->uid,
3668 (size_t)state->token->ngroups,
3669 state->token->groups);
3671 state->xattr_size = -1;
3672 state->vfs_aio_state.error = errno;
3676 state->xattr_size = vfswrap_fgetxattr(state->handle,
3680 talloc_array_length(state->xattr_value));
3681 if (state->xattr_size == -1) {
3682 state->vfs_aio_state.error = errno;
3686 PROFILE_TIMESTAMP(&end_time);
3687 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3688 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3691 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3693 struct tevent_req *req = tevent_req_callback_data(
3694 subreq, struct tevent_req);
3695 struct vfswrap_getxattrat_state *state = tevent_req_data(
3696 req, struct vfswrap_getxattrat_state);
3701 * Make sure we run as the user again
3703 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3706 ret = pthreadpool_tevent_job_recv(subreq);
3707 TALLOC_FREE(subreq);
3708 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3709 talloc_set_destructor(state, NULL);
3711 if (ret != EAGAIN) {
3712 tevent_req_error(req, ret);
3716 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3717 * means the lower level pthreadpool failed to create a new
3718 * thread. Fallback to sync processing in that case to allow
3719 * some progress for the client.
3721 vfswrap_getxattrat_do_sync(req);
3725 if (state->xattr_size == -1) {
3726 tevent_req_error(req, state->vfs_aio_state.error);
3730 if (state->xattr_value == NULL) {
3732 * The caller only wanted the size.
3734 tevent_req_done(req);
3739 * shrink the buffer to the returned size.
3740 * (can't fail). It means NULL if size is 0.
3742 state->xattr_value = talloc_realloc(state,
3747 tevent_req_done(req);
3750 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3751 struct vfs_aio_state *aio_state,
3752 TALLOC_CTX *mem_ctx,
3753 uint8_t **xattr_value)
3755 struct vfswrap_getxattrat_state *state = tevent_req_data(
3756 req, struct vfswrap_getxattrat_state);
3759 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3760 tevent_req_received(req);
3764 *aio_state = state->vfs_aio_state;
3765 xattr_size = state->xattr_size;
3766 if (xattr_value != NULL) {
3767 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3770 tevent_req_received(req);
3774 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3776 int fd = fsp_get_pathref_fd(fsp);
3778 if (!fsp->fsp_flags.is_pathref) {
3779 return flistxattr(fd, list, size);
3782 if (fsp->fsp_flags.have_proc_fds) {
3783 const char *p = NULL;
3786 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3791 return listxattr(p, list, size);
3795 * This is no longer a handle based call.
3797 return listxattr(fsp->fsp_name->base_name, list, size);
3800 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3802 int fd = fsp_get_pathref_fd(fsp);
3804 if (!fsp->fsp_flags.is_pathref) {
3805 return fremovexattr(fd, name);
3808 if (fsp->fsp_flags.have_proc_fds) {
3809 const char *p = NULL;
3812 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3817 return removexattr(p, name);
3821 * This is no longer a handle based call.
3823 return removexattr(fsp->fsp_name->base_name, name);
3826 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3828 int fd = fsp_get_pathref_fd(fsp);
3830 if (!fsp->fsp_flags.is_pathref) {
3831 return fsetxattr(fd, name, value, size, flags);
3834 if (fsp->fsp_flags.have_proc_fds) {
3835 const char *p = NULL;
3838 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3843 return setxattr(p, name, value, size, flags);
3847 * This is no longer a handle based call.
3849 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3852 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3857 static bool vfswrap_is_offline(struct connection_struct *conn,
3858 const struct smb_filename *fname)
3862 bool offline = false;
3864 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3868 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3869 #if defined(ENOTSUP)
3875 status = get_full_smb_filename(talloc_tos(), fname, &path);
3876 if (!NT_STATUS_IS_OK(status)) {
3877 errno = map_errno_from_nt_status(status);
3881 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3888 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3889 struct files_struct *fsp,
3890 TALLOC_CTX *mem_ctx,
3893 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3896 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3897 struct files_struct *fsp,
3898 const DATA_BLOB old_cookie,
3899 TALLOC_CTX *mem_ctx,
3900 DATA_BLOB *new_cookie)
3902 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3906 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3907 struct smb_request *smb1req,
3908 struct smbXsrv_open *op,
3909 const DATA_BLOB old_cookie,
3910 TALLOC_CTX *mem_ctx,
3911 struct files_struct **fsp,
3912 DATA_BLOB *new_cookie)
3914 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3915 old_cookie, mem_ctx,
3919 static struct vfs_fn_pointers vfs_default_fns = {
3920 /* Disk operations */
3922 .connect_fn = vfswrap_connect,
3923 .disconnect_fn = vfswrap_disconnect,
3924 .disk_free_fn = vfswrap_disk_free,
3925 .get_quota_fn = vfswrap_get_quota,
3926 .set_quota_fn = vfswrap_set_quota,
3927 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3928 .statvfs_fn = vfswrap_statvfs,
3929 .fs_capabilities_fn = vfswrap_fs_capabilities,
3930 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3931 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3932 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3933 .snap_check_path_fn = vfswrap_snap_check_path,
3934 .snap_create_fn = vfswrap_snap_create,
3935 .snap_delete_fn = vfswrap_snap_delete,
3937 /* Directory operations */
3939 .fdopendir_fn = vfswrap_fdopendir,
3940 .readdir_fn = vfswrap_readdir,
3941 .freaddir_attr_fn = vfswrap_freaddir_attr,
3942 .seekdir_fn = vfswrap_seekdir,
3943 .telldir_fn = vfswrap_telldir,
3944 .rewind_dir_fn = vfswrap_rewinddir,
3945 .mkdirat_fn = vfswrap_mkdirat,
3946 .closedir_fn = vfswrap_closedir,
3948 /* File operations */
3950 .openat_fn = vfswrap_openat,
3951 .create_file_fn = vfswrap_create_file,
3952 .close_fn = vfswrap_close,
3953 .pread_fn = vfswrap_pread,
3954 .pread_send_fn = vfswrap_pread_send,
3955 .pread_recv_fn = vfswrap_pread_recv,
3956 .pwrite_fn = vfswrap_pwrite,
3957 .pwrite_send_fn = vfswrap_pwrite_send,
3958 .pwrite_recv_fn = vfswrap_pwrite_recv,
3959 .lseek_fn = vfswrap_lseek,
3960 .sendfile_fn = vfswrap_sendfile,
3961 .recvfile_fn = vfswrap_recvfile,
3962 .renameat_fn = vfswrap_renameat,
3963 .fsync_send_fn = vfswrap_fsync_send,
3964 .fsync_recv_fn = vfswrap_fsync_recv,
3965 .stat_fn = vfswrap_stat,
3966 .fstat_fn = vfswrap_fstat,
3967 .lstat_fn = vfswrap_lstat,
3968 .get_alloc_size_fn = vfswrap_get_alloc_size,
3969 .unlinkat_fn = vfswrap_unlinkat,
3970 .fchmod_fn = vfswrap_fchmod,
3971 .fchown_fn = vfswrap_fchown,
3972 .lchown_fn = vfswrap_lchown,
3973 .chdir_fn = vfswrap_chdir,
3974 .getwd_fn = vfswrap_getwd,
3975 .fntimes_fn = vfswrap_fntimes,
3976 .ftruncate_fn = vfswrap_ftruncate,
3977 .fallocate_fn = vfswrap_fallocate,
3978 .lock_fn = vfswrap_lock,
3979 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
3980 .fcntl_fn = vfswrap_fcntl,
3981 .linux_setlease_fn = vfswrap_linux_setlease,
3982 .getlock_fn = vfswrap_getlock,
3983 .symlinkat_fn = vfswrap_symlinkat,
3984 .readlinkat_fn = vfswrap_readlinkat,
3985 .linkat_fn = vfswrap_linkat,
3986 .mknodat_fn = vfswrap_mknodat,
3987 .realpath_fn = vfswrap_realpath,
3988 .fchflags_fn = vfswrap_fchflags,
3989 .file_id_create_fn = vfswrap_file_id_create,
3990 .fs_file_id_fn = vfswrap_fs_file_id,
3991 .fstreaminfo_fn = vfswrap_fstreaminfo,
3992 .get_real_filename_fn = vfswrap_get_real_filename,
3993 .connectpath_fn = vfswrap_connectpath,
3994 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
3995 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
3996 .strict_lock_check_fn = vfswrap_strict_lock_check,
3997 .translate_name_fn = vfswrap_translate_name,
3998 .parent_pathname_fn = vfswrap_parent_pathname,
3999 .fsctl_fn = vfswrap_fsctl,
4000 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4001 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4002 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4003 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4004 .offload_read_send_fn = vfswrap_offload_read_send,
4005 .offload_read_recv_fn = vfswrap_offload_read_recv,
4006 .offload_write_send_fn = vfswrap_offload_write_send,
4007 .offload_write_recv_fn = vfswrap_offload_write_recv,
4008 .fget_compression_fn = vfswrap_fget_compression,
4009 .set_compression_fn = vfswrap_set_compression,
4011 /* NT ACL operations. */
4013 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4014 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4015 .audit_file_fn = vfswrap_audit_file,
4017 /* POSIX ACL operations. */
4019 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4020 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4021 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4022 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4024 /* EA operations. */
4025 .getxattrat_send_fn = vfswrap_getxattrat_send,
4026 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4027 .fgetxattr_fn = vfswrap_fgetxattr,
4028 .flistxattr_fn = vfswrap_flistxattr,
4029 .fremovexattr_fn = vfswrap_fremovexattr,
4030 .fsetxattr_fn = vfswrap_fsetxattr,
4032 /* aio operations */
4033 .aio_force_fn = vfswrap_aio_force,
4035 /* durable handle operations */
4036 .durable_cookie_fn = vfswrap_durable_cookie,
4037 .durable_disconnect_fn = vfswrap_durable_disconnect,
4038 .durable_reconnect_fn = vfswrap_durable_reconnect,
4042 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4045 * Here we need to implement every call!
4047 * As this is the end of the vfs module chain.
4049 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4050 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4051 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);