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)
54 handle->conn->have_proc_fds = sys_have_proc_fds();
57 * assume the kernel will support openat2(),
58 * it will be reset on the first ENOSYS.
60 * Note that libreplace will always provide openat2(),
61 * but return -1/errno = ENOSYS...
63 * The option is only there to test the fallback code.
65 bval = lp_parm_bool(SNUM(handle->conn),
67 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
70 handle->conn->open_how_resolve |=
71 VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
74 return 0; /* Return >= 0 for success */
77 static void vfswrap_disconnect(vfs_handle_struct *handle)
83 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
84 const struct smb_filename *smb_fname,
89 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
97 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
98 const struct smb_filename *smb_fname,
99 enum SMB_QUOTA_TYPE qtype,
103 #ifdef HAVE_SYS_QUOTAS
106 START_PROFILE(syscall_get_quota);
107 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
108 END_PROFILE(syscall_get_quota);
116 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
118 #ifdef HAVE_SYS_QUOTAS
121 START_PROFILE(syscall_set_quota);
122 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
123 END_PROFILE(syscall_set_quota);
131 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
132 struct files_struct *fsp,
133 struct shadow_copy_data *shadow_copy_data,
137 return -1; /* Not implemented. */
140 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
141 const struct smb_filename *smb_fname,
142 struct vfs_statvfs_struct *statbuf)
144 return sys_statvfs(smb_fname->base_name, statbuf);
147 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
148 enum timestamp_set_resolution *p_ts_res)
150 const struct loadparm_substitution *lp_sub =
151 loadparm_s3_global_substitution();
152 connection_struct *conn = handle->conn;
153 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
154 struct smb_filename *smb_fname_cpath = NULL;
155 struct vfs_statvfs_struct statbuf;
158 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
164 if (smb_fname_cpath == NULL) {
168 ZERO_STRUCT(statbuf);
169 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
171 caps = statbuf.FsCapabilities;
174 *p_ts_res = TIMESTAMP_SET_SECONDS;
176 /* Work out what timestamp resolution we can
177 * use when setting a timestamp. */
179 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
181 TALLOC_FREE(smb_fname_cpath);
185 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
186 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
187 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
188 /* If any of the normal UNIX directory timestamps
189 * have a non-zero tv_nsec component assume
190 * we might be able to set sub-second timestamps.
191 * See what filetime set primitives we have.
193 #if defined(HAVE_UTIMENSAT)
194 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
195 #elif defined(HAVE_UTIMES)
196 /* utimes allows msec timestamps to be set. */
197 *p_ts_res = TIMESTAMP_SET_MSEC;
198 #elif defined(HAVE_UTIME)
199 /* utime only allows sec timestamps to be set. */
200 *p_ts_res = TIMESTAMP_SET_SECONDS;
203 DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
205 "available on share %s, directory %s\n",
206 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
207 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
210 TALLOC_FREE(smb_fname_cpath);
214 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
215 struct dfs_GetDFSReferral *r)
217 struct junction_map *junction = NULL;
218 size_t consumedcnt = 0;
219 bool self_referral = false;
220 char *pathnamep = NULL;
221 char *local_dfs_path = NULL;
224 uint16_t max_referral_level = r->in.req.max_referral_level;
226 if (DEBUGLVL(DBGLVL_DEBUG)) {
227 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
230 /* get the junction entry */
231 if (r->in.req.servername == NULL) {
232 return NT_STATUS_NOT_FOUND;
236 * Trim pathname sent by client so it begins with only one backslash.
237 * Two backslashes confuse some dfs clients
240 local_dfs_path = talloc_strdup(r, r->in.req.servername);
241 if (local_dfs_path == NULL) {
242 return NT_STATUS_NO_MEMORY;
244 pathnamep = local_dfs_path;
245 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
246 IS_DIRECTORY_SEP(pathnamep[1])) {
250 junction = talloc_zero(r, struct junction_map);
251 if (junction == NULL) {
252 return NT_STATUS_NO_MEMORY;
255 /* The following call can change cwd. */
256 status = get_referred_path(r,
257 handle->conn->session_info,
259 handle->conn->sconn->remote_address,
260 handle->conn->sconn->local_address,
261 junction, &consumedcnt, &self_referral);
262 if (!NT_STATUS_IS_OK(status)) {
263 struct smb_filename connectpath_fname = {
264 .base_name = handle->conn->connectpath
266 vfs_ChDir(handle->conn, &connectpath_fname);
270 struct smb_filename connectpath_fname = {
271 .base_name = handle->conn->connectpath
273 vfs_ChDir(handle->conn, &connectpath_fname);
276 if (!self_referral) {
277 pathnamep[consumedcnt] = '\0';
279 if (DEBUGLVL(DBGLVL_INFO)) {
280 dbgtext("Path %s to alternate path(s):",
282 for (i=0; i < junction->referral_count; i++) {
284 junction->referral_list[i].alternate_path);
290 if (r->in.req.max_referral_level <= 2) {
291 max_referral_level = 2;
293 if (r->in.req.max_referral_level >= 3) {
294 max_referral_level = 3;
297 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
298 if (r->out.resp == NULL) {
299 return NT_STATUS_NO_MEMORY;
302 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
303 r->out.resp->nb_referrals = junction->referral_count;
305 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
307 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
310 r->out.resp->referral_entries = talloc_zero_array(r,
311 struct dfs_referral_type,
312 r->out.resp->nb_referrals);
313 if (r->out.resp->referral_entries == NULL) {
314 return NT_STATUS_NO_MEMORY;
317 switch (max_referral_level) {
319 for(i=0; i < junction->referral_count; i++) {
320 struct referral *ref = &junction->referral_list[i];
321 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
322 struct dfs_referral_type *t =
323 &r->out.resp->referral_entries[i];
324 struct dfs_referral_v2 *v2 = &t->referral.v2;
327 v2->size = VERSION2_REFERRAL_SIZE;
329 v2->server_type = DFS_SERVER_ROOT;
331 v2->server_type = DFS_SERVER_NON_ROOT;
334 v2->proximity = ref->proximity;
336 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
337 if (v2->DFS_path == NULL) {
338 return NT_STATUS_NO_MEMORY;
340 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
341 if (v2->DFS_alt_path == NULL) {
342 return NT_STATUS_NO_MEMORY;
344 v2->netw_address = talloc_strdup(mem_ctx,
345 ref->alternate_path);
346 if (v2->netw_address == NULL) {
347 return NT_STATUS_NO_MEMORY;
353 for(i=0; i < junction->referral_count; i++) {
354 struct referral *ref = &junction->referral_list[i];
355 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
356 struct dfs_referral_type *t =
357 &r->out.resp->referral_entries[i];
358 struct dfs_referral_v3 *v3 = &t->referral.v3;
359 struct dfs_normal_referral *r1 = &v3->referrals.r1;
362 v3->size = VERSION3_REFERRAL_SIZE;
364 v3->server_type = DFS_SERVER_ROOT;
366 v3->server_type = DFS_SERVER_NON_ROOT;
370 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
371 if (r1->DFS_path == NULL) {
372 return NT_STATUS_NO_MEMORY;
374 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
375 if (r1->DFS_alt_path == NULL) {
376 return NT_STATUS_NO_MEMORY;
378 r1->netw_address = talloc_strdup(mem_ctx,
379 ref->alternate_path);
380 if (r1->netw_address == NULL) {
381 return NT_STATUS_NO_MEMORY;
386 DBG_ERR("Invalid dfs referral version: %d\n",
388 return NT_STATUS_INVALID_LEVEL;
391 if (DEBUGLVL(DBGLVL_DEBUG)) {
392 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
398 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
399 struct files_struct *dirfsp,
400 const struct smb_filename *smb_fname,
401 const struct referral *reflist,
402 size_t referral_count)
404 TALLOC_CTX *frame = talloc_stackframe();
405 NTSTATUS status = NT_STATUS_NO_MEMORY;
407 char *msdfs_link = NULL;
409 /* Form the msdfs_link contents */
410 msdfs_link = msdfs_link_string(frame,
413 if (msdfs_link == NULL) {
417 ret = symlinkat(msdfs_link,
418 fsp_get_pathref_fd(dirfsp),
419 smb_fname->base_name);
421 status = NT_STATUS_OK;
423 status = map_nt_error_from_unix(errno);
433 * Read and return the contents of a DFS redirect given a
434 * pathname. A caller can pass in NULL for ppreflist and
435 * preferral_count but still determine if this was a
436 * DFS redirect point by getting NT_STATUS_OK back
437 * without incurring the overhead of reading and parsing
438 * the referral contents.
441 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
443 struct files_struct *dirfsp,
444 struct smb_filename *smb_fname,
445 struct referral **ppreflist,
446 size_t *preferral_count)
448 NTSTATUS status = NT_STATUS_NO_MEMORY;
450 char *link_target = NULL;
453 #if defined(HAVE_BROKEN_READLINK)
454 char link_target_buf[PATH_MAX];
456 char link_target_buf[7];
460 if (is_named_stream(smb_fname)) {
461 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
465 if (ppreflist == NULL && preferral_count == NULL) {
467 * We're only checking if this is a DFS
468 * redirect. We don't need to return data.
470 bufsize = sizeof(link_target_buf);
471 link_target = link_target_buf;
474 link_target = talloc_array(mem_ctx, char, bufsize);
480 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
481 smb_fname->base_name,
484 if (referral_len == -1) {
485 if (errno == EINVAL) {
487 * If the path isn't a link, readlinkat
488 * returns EINVAL. Allow the caller to
491 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
492 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
494 status = map_nt_error_from_unix(errno);
495 if (errno == ENOENT) {
496 DBG_NOTICE("Error reading "
497 "msdfs link %s: %s\n",
498 smb_fname->base_name,
501 DBG_ERR("Error reading "
502 "msdfs link %s: %s\n",
503 smb_fname->base_name,
509 link_target[referral_len] = '\0';
511 DBG_INFO("%s -> %s\n",
512 smb_fname->base_name,
515 if (!strnequal(link_target, "msdfs:", 6)) {
516 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
520 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
521 smb_fname->base_name,
524 lp_fake_directory_create_times(SNUM(handle->conn)));
526 status = map_nt_error_from_unix(errno);
530 if (ppreflist == NULL && preferral_count == NULL) {
531 /* Early return for checking if this is a DFS link. */
535 ok = parse_msdfs_symlink(mem_ctx,
536 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
542 status = NT_STATUS_OK;
544 status = NT_STATUS_NO_MEMORY;
549 if (link_target != link_target_buf) {
550 TALLOC_FREE(link_target);
555 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
557 const char *service_path,
560 return NT_STATUS_NOT_SUPPORTED;
563 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
565 const char *base_volume,
571 return NT_STATUS_NOT_SUPPORTED;
574 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
579 return NT_STATUS_NOT_SUPPORTED;
582 /* Directory operations */
584 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
591 START_PROFILE(syscall_fdopendir);
592 result = sys_fdopendir(fsp_get_io_fd(fsp));
593 END_PROFILE(syscall_fdopendir);
597 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
598 struct files_struct *dirfsp,
601 struct dirent *result;
603 START_PROFILE(syscall_readdir);
605 result = readdir(dirp);
606 END_PROFILE(syscall_readdir);
611 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
612 struct files_struct *fsp,
614 struct readdir_attr_data **attr_data)
616 return NT_STATUS_NOT_SUPPORTED;
619 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
621 START_PROFILE(syscall_rewinddir);
623 END_PROFILE(syscall_rewinddir);
626 static int vfswrap_mkdirat(vfs_handle_struct *handle,
627 struct files_struct *dirfsp,
628 const struct smb_filename *smb_fname,
633 START_PROFILE(syscall_mkdirat);
635 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
637 END_PROFILE(syscall_mkdirat);
641 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
645 START_PROFILE(syscall_closedir);
646 result = closedir(dirp);
647 END_PROFILE(syscall_closedir);
651 /* File operations */
653 static int vfswrap_openat(vfs_handle_struct *handle,
654 const struct files_struct *dirfsp,
655 const struct smb_filename *smb_fname,
657 const struct vfs_open_how *how)
659 int flags = how->flags;
660 mode_t mode = how->mode;
661 bool have_opath = false;
662 bool became_root = false;
665 START_PROFILE(syscall_openat);
667 if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
668 VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
674 SMB_ASSERT(!is_named_stream(smb_fname));
678 if (fsp->fsp_flags.is_pathref) {
681 if (flags & O_PATH) {
683 * From "man 2 openat":
685 * When O_PATH is specified in flags, flag bits other than
686 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
688 * From "man 2 openat2":
690 * Whereas openat(2) ignores unknown bits in its flags
691 * argument, openat2() returns an error if unknown or
692 * conflicting flags are specified in how.flags.
694 * So we better clear ignored/invalid flags
695 * and only keep the expected ones.
697 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
701 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
702 struct open_how linux_how = {
705 .resolve = RESOLVE_NO_SYMLINKS,
708 result = openat2(fsp_get_pathref_fd(dirfsp),
709 smb_fname->base_name,
713 if (errno == ENOSYS) {
715 * The kernel doesn't support
716 * openat2(), so indicate to
718 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
719 * would just be a waste of time.
721 fsp->conn->open_how_resolve &=
722 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
730 if (fsp->fsp_flags.is_pathref && !have_opath) {
735 result = openat(fsp_get_pathref_fd(dirfsp),
736 smb_fname->base_name,
745 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
748 END_PROFILE(syscall_openat);
751 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
752 struct smb_request *req,
753 struct files_struct *dirfsp,
754 struct smb_filename *smb_fname,
755 uint32_t access_mask,
756 uint32_t share_access,
757 uint32_t create_disposition,
758 uint32_t create_options,
759 uint32_t file_attributes,
760 uint32_t oplock_request,
761 const struct smb2_lease *lease,
762 uint64_t allocation_size,
763 uint32_t private_flags,
764 struct security_descriptor *sd,
765 struct ea_list *ea_list,
766 files_struct **result,
768 const struct smb2_create_blobs *in_context_blobs,
769 struct smb2_create_blobs *out_context_blobs)
771 return create_file_default(handle->conn, req, dirfsp, smb_fname,
772 access_mask, share_access,
773 create_disposition, create_options,
774 file_attributes, oplock_request, lease,
775 allocation_size, private_flags,
777 pinfo, in_context_blobs, out_context_blobs);
780 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
784 START_PROFILE(syscall_close);
785 result = fd_close_posix(fsp);
786 END_PROFILE(syscall_close);
790 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
791 size_t n, off_t offset)
795 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
796 START_PROFILE_BYTES(syscall_pread, n);
797 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
798 END_PROFILE_BYTES(syscall_pread);
800 if (result == -1 && errno == ESPIPE) {
801 /* Maintain the fiction that pipes can be seeked (sought?) on. */
802 result = sys_read(fsp_get_io_fd(fsp), data, n);
803 fh_set_pos(fsp->fh, 0);
806 #else /* HAVE_PREAD */
809 #endif /* HAVE_PREAD */
814 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
815 size_t n, off_t offset)
819 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
820 START_PROFILE_BYTES(syscall_pwrite, n);
821 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
822 END_PROFILE_BYTES(syscall_pwrite);
824 if (result == -1 && errno == ESPIPE) {
825 /* Maintain the fiction that pipes can be sought on. */
826 result = sys_write(fsp_get_io_fd(fsp), data, n);
829 #else /* HAVE_PWRITE */
832 #endif /* HAVE_PWRITE */
837 struct vfswrap_pread_state {
844 struct vfs_aio_state vfs_aio_state;
845 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
848 static void vfs_pread_do(void *private_data);
849 static void vfs_pread_done(struct tevent_req *subreq);
850 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
852 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
854 struct tevent_context *ev,
855 struct files_struct *fsp,
857 size_t n, off_t offset)
859 struct tevent_req *req, *subreq;
860 struct vfswrap_pread_state *state;
862 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
868 state->fd = fsp_get_io_fd(fsp);
871 state->offset = offset;
873 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
874 state->profile_bytes, n);
875 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
877 subreq = pthreadpool_tevent_job_send(
878 state, ev, handle->conn->sconn->pool,
879 vfs_pread_do, state);
880 if (tevent_req_nomem(subreq, req)) {
881 return tevent_req_post(req, ev);
883 tevent_req_set_callback(subreq, vfs_pread_done, req);
885 talloc_set_destructor(state, vfs_pread_state_destructor);
890 static void vfs_pread_do(void *private_data)
892 struct vfswrap_pread_state *state = talloc_get_type_abort(
893 private_data, struct vfswrap_pread_state);
894 struct timespec start_time;
895 struct timespec end_time;
897 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
899 PROFILE_TIMESTAMP(&start_time);
901 state->ret = sys_pread_full(state->fd,
906 if (state->ret == -1) {
907 state->vfs_aio_state.error = errno;
910 PROFILE_TIMESTAMP(&end_time);
912 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
914 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
917 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
922 static void vfs_pread_done(struct tevent_req *subreq)
924 struct tevent_req *req = tevent_req_callback_data(
925 subreq, struct tevent_req);
926 struct vfswrap_pread_state *state = tevent_req_data(
927 req, struct vfswrap_pread_state);
930 ret = pthreadpool_tevent_job_recv(subreq);
932 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
933 talloc_set_destructor(state, NULL);
936 tevent_req_error(req, ret);
940 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
941 * means the lower level pthreadpool failed to create a new
942 * thread. Fallback to sync processing in that case to allow
943 * some progress for the client.
948 tevent_req_done(req);
951 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
952 struct vfs_aio_state *vfs_aio_state)
954 struct vfswrap_pread_state *state = tevent_req_data(
955 req, struct vfswrap_pread_state);
957 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
961 *vfs_aio_state = state->vfs_aio_state;
965 struct vfswrap_pwrite_state {
972 struct vfs_aio_state vfs_aio_state;
973 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
976 static void vfs_pwrite_do(void *private_data);
977 static void vfs_pwrite_done(struct tevent_req *subreq);
978 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
980 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
982 struct tevent_context *ev,
983 struct files_struct *fsp,
985 size_t n, off_t offset)
987 struct tevent_req *req, *subreq;
988 struct vfswrap_pwrite_state *state;
990 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
996 state->fd = fsp_get_io_fd(fsp);
999 state->offset = offset;
1001 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1002 state->profile_bytes, n);
1003 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1005 subreq = pthreadpool_tevent_job_send(
1006 state, ev, handle->conn->sconn->pool,
1007 vfs_pwrite_do, state);
1008 if (tevent_req_nomem(subreq, req)) {
1009 return tevent_req_post(req, ev);
1011 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1013 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1018 static void vfs_pwrite_do(void *private_data)
1020 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1021 private_data, struct vfswrap_pwrite_state);
1022 struct timespec start_time;
1023 struct timespec end_time;
1025 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1027 PROFILE_TIMESTAMP(&start_time);
1029 state->ret = sys_pwrite_full(state->fd,
1034 if (state->ret == -1) {
1035 state->vfs_aio_state.error = errno;
1038 PROFILE_TIMESTAMP(&end_time);
1040 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1042 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1045 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1050 static void vfs_pwrite_done(struct tevent_req *subreq)
1052 struct tevent_req *req = tevent_req_callback_data(
1053 subreq, struct tevent_req);
1054 struct vfswrap_pwrite_state *state = tevent_req_data(
1055 req, struct vfswrap_pwrite_state);
1058 ret = pthreadpool_tevent_job_recv(subreq);
1059 TALLOC_FREE(subreq);
1060 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1061 talloc_set_destructor(state, NULL);
1063 if (ret != EAGAIN) {
1064 tevent_req_error(req, ret);
1068 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1069 * means the lower level pthreadpool failed to create a new
1070 * thread. Fallback to sync processing in that case to allow
1071 * some progress for the client.
1073 vfs_pwrite_do(state);
1076 tevent_req_done(req);
1079 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1080 struct vfs_aio_state *vfs_aio_state)
1082 struct vfswrap_pwrite_state *state = tevent_req_data(
1083 req, struct vfswrap_pwrite_state);
1085 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1089 *vfs_aio_state = state->vfs_aio_state;
1093 struct vfswrap_fsync_state {
1097 struct vfs_aio_state vfs_aio_state;
1098 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1101 static void vfs_fsync_do(void *private_data);
1102 static void vfs_fsync_done(struct tevent_req *subreq);
1103 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1105 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1106 TALLOC_CTX *mem_ctx,
1107 struct tevent_context *ev,
1108 struct files_struct *fsp)
1110 struct tevent_req *req, *subreq;
1111 struct vfswrap_fsync_state *state;
1113 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1119 state->fd = fsp_get_io_fd(fsp);
1121 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1122 state->profile_bytes, 0);
1123 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1125 subreq = pthreadpool_tevent_job_send(
1126 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1127 if (tevent_req_nomem(subreq, req)) {
1128 return tevent_req_post(req, ev);
1130 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1132 talloc_set_destructor(state, vfs_fsync_state_destructor);
1137 static void vfs_fsync_do(void *private_data)
1139 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1140 private_data, struct vfswrap_fsync_state);
1141 struct timespec start_time;
1142 struct timespec end_time;
1144 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1146 PROFILE_TIMESTAMP(&start_time);
1149 state->ret = fsync(state->fd);
1150 } while ((state->ret == -1) && (errno == EINTR));
1152 if (state->ret == -1) {
1153 state->vfs_aio_state.error = errno;
1156 PROFILE_TIMESTAMP(&end_time);
1158 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1160 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1163 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1168 static void vfs_fsync_done(struct tevent_req *subreq)
1170 struct tevent_req *req = tevent_req_callback_data(
1171 subreq, struct tevent_req);
1172 struct vfswrap_fsync_state *state = tevent_req_data(
1173 req, struct vfswrap_fsync_state);
1176 ret = pthreadpool_tevent_job_recv(subreq);
1177 TALLOC_FREE(subreq);
1178 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1179 talloc_set_destructor(state, NULL);
1181 if (ret != EAGAIN) {
1182 tevent_req_error(req, ret);
1186 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1187 * means the lower level pthreadpool failed to create a new
1188 * thread. Fallback to sync processing in that case to allow
1189 * some progress for the client.
1191 vfs_fsync_do(state);
1194 tevent_req_done(req);
1197 static int vfswrap_fsync_recv(struct tevent_req *req,
1198 struct vfs_aio_state *vfs_aio_state)
1200 struct vfswrap_fsync_state *state = tevent_req_data(
1201 req, struct vfswrap_fsync_state);
1203 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1207 *vfs_aio_state = state->vfs_aio_state;
1211 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1215 START_PROFILE(syscall_lseek);
1217 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1219 * We want to maintain the fiction that we can seek
1220 * on a fifo for file system purposes. This allows
1221 * people to set up UNIX fifo's that feed data to Windows
1222 * applications. JRA.
1225 if((result == -1) && (errno == ESPIPE)) {
1230 END_PROFILE(syscall_lseek);
1234 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1235 off_t offset, size_t n)
1239 START_PROFILE_BYTES(syscall_sendfile, n);
1240 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1241 END_PROFILE_BYTES(syscall_sendfile);
1245 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1247 files_struct *tofsp,
1253 START_PROFILE_BYTES(syscall_recvfile, n);
1254 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1255 END_PROFILE_BYTES(syscall_recvfile);
1259 static int vfswrap_renameat(vfs_handle_struct *handle,
1260 files_struct *srcfsp,
1261 const struct smb_filename *smb_fname_src,
1262 files_struct *dstfsp,
1263 const struct smb_filename *smb_fname_dst)
1267 START_PROFILE(syscall_renameat);
1269 SMB_ASSERT(!is_named_stream(smb_fname_src));
1270 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1272 result = renameat(fsp_get_pathref_fd(srcfsp),
1273 smb_fname_src->base_name,
1274 fsp_get_pathref_fd(dstfsp),
1275 smb_fname_dst->base_name);
1277 END_PROFILE(syscall_renameat);
1281 static int vfswrap_stat(vfs_handle_struct *handle,
1282 struct smb_filename *smb_fname)
1286 START_PROFILE(syscall_stat);
1288 SMB_ASSERT(!is_named_stream(smb_fname));
1290 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1291 lp_fake_directory_create_times(SNUM(handle->conn)));
1293 END_PROFILE(syscall_stat);
1297 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1301 START_PROFILE(syscall_fstat);
1302 result = sys_fstat(fsp_get_pathref_fd(fsp),
1303 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1304 END_PROFILE(syscall_fstat);
1308 static int vfswrap_lstat(vfs_handle_struct *handle,
1309 struct smb_filename *smb_fname)
1313 START_PROFILE(syscall_lstat);
1315 SMB_ASSERT(!is_named_stream(smb_fname));
1317 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1318 lp_fake_directory_create_times(SNUM(handle->conn)));
1320 END_PROFILE(syscall_lstat);
1324 static int vfswrap_fstatat(
1325 struct vfs_handle_struct *handle,
1326 const struct files_struct *dirfsp,
1327 const struct smb_filename *smb_fname,
1328 SMB_STRUCT_STAT *sbuf,
1333 START_PROFILE(syscall_fstatat);
1335 SMB_ASSERT(!is_named_stream(smb_fname));
1337 result = sys_fstatat(
1338 fsp_get_pathref_fd(dirfsp),
1339 smb_fname->base_name,
1342 lp_fake_directory_create_times(SNUM(handle->conn)));
1344 END_PROFILE(syscall_fstatat);
1348 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1350 enum vfs_translate_direction direction,
1351 TALLOC_CTX *mem_ctx,
1354 return NT_STATUS_NONE_MAPPED;
1358 * Return allocated parent directory and basename of path
1360 * Note: if requesting atname, it is returned as talloc child of the
1361 * parent. Freeing the parent is thus sufficient to free both.
1363 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1364 TALLOC_CTX *mem_ctx,
1365 const struct smb_filename *smb_fname_in,
1366 struct smb_filename **parent_dir_out,
1367 struct smb_filename **atname_out)
1369 struct smb_filename *parent = NULL;
1370 struct smb_filename *name = NULL;
1373 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1374 if (parent == NULL) {
1375 return NT_STATUS_NO_MEMORY;
1377 SET_STAT_INVALID(parent->st);
1379 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1381 TALLOC_FREE(parent->base_name);
1382 parent->base_name = talloc_strdup(parent, ".");
1383 if (parent->base_name == NULL) {
1384 TALLOC_FREE(parent);
1385 return NT_STATUS_NO_MEMORY;
1387 p = smb_fname_in->base_name;
1393 if (atname_out == NULL) {
1394 *parent_dir_out = parent;
1395 return NT_STATUS_OK;
1398 name = synthetic_smb_fname(
1401 smb_fname_in->stream_name,
1404 smb_fname_in->flags);
1406 return NT_STATUS_NO_MEMORY;
1409 *parent_dir_out = parent;
1411 return NT_STATUS_OK;
1415 * Implement the default fsctl operation.
1417 static bool vfswrap_logged_ioctl_message = false;
1419 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1420 struct files_struct *fsp,
1423 uint16_t req_flags, /* Needed for UNICODE ... */
1424 const uint8_t *_in_data,
1426 uint8_t **_out_data,
1427 uint32_t max_out_len,
1430 const char *in_data = (const char *)_in_data;
1431 char **out_data = (char **)_out_data;
1435 * Currently all fsctls operate on the base
1436 * file if given an alternate data stream.
1437 * Revisit this if we implement fsctls later
1438 * that need access to the ADS handle.
1440 fsp = metadata_fsp(fsp);
1443 case FSCTL_SET_SPARSE:
1445 bool set_sparse = true;
1447 if (in_len >= 1 && in_data[0] == 0) {
1451 status = file_set_sparse(handle->conn, fsp, set_sparse);
1453 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1454 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1455 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1456 nt_errstr(status)));
1461 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1463 unsigned char objid[16];
1464 char *return_data = NULL;
1466 /* This should return the object-id on this file.
1467 * I think I'll make this be the inode+dev. JRA.
1470 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1473 *out_len = MIN(max_out_len, 64);
1475 /* Hmmm, will this cause problems if less data asked for? */
1476 return_data = talloc_array(ctx, char, 64);
1477 if (return_data == NULL) {
1478 return NT_STATUS_NO_MEMORY;
1481 /* For backwards compatibility only store the dev/inode. */
1482 push_file_id_16(return_data, &fsp->file_id);
1483 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1484 push_file_id_16(return_data+32, &fsp->file_id);
1485 memset(return_data+48, 0, 16);
1486 *out_data = return_data;
1487 return NT_STATUS_OK;
1490 case FSCTL_GET_REPARSE_POINT:
1492 status = fsctl_get_reparse_point(
1493 fsp, ctx, out_data, max_out_len, out_len);
1497 case FSCTL_SET_REPARSE_POINT:
1499 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1503 case FSCTL_DELETE_REPARSE_POINT:
1505 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1509 case FSCTL_GET_SHADOW_COPY_DATA:
1512 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1513 * and return their volume names. If max_data_count is 16, then it is just
1514 * asking for the number of volumes and length of the combined names.
1516 * pdata is the data allocated by our caller, but that uses
1517 * total_data_count (which is 0 in our case) rather than max_data_count.
1518 * Allocate the correct amount and return the pointer to let
1519 * it be deallocated when we return.
1521 struct shadow_copy_data *shadow_data = NULL;
1522 bool labels = False;
1523 uint32_t labels_data_count = 0;
1525 char *cur_pdata = NULL;
1527 if (max_out_len < 16) {
1528 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1530 return NT_STATUS_INVALID_PARAMETER;
1533 if (max_out_len > 16) {
1537 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1538 if (shadow_data == NULL) {
1539 DBG_ERR("TALLOC_ZERO() failed!\n");
1540 return NT_STATUS_NO_MEMORY;
1544 * Call the VFS routine to actually do the work.
1546 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1547 int log_lev = DBGLVL_ERR;
1549 /* broken module didn't set errno on error */
1550 status = NT_STATUS_UNSUCCESSFUL;
1552 status = map_nt_error_from_unix(errno);
1553 if (NT_STATUS_EQUAL(status,
1554 NT_STATUS_NOT_SUPPORTED)) {
1555 log_lev = DBGLVL_INFO;
1558 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1559 "connectpath %s, failed - %s.\n",
1560 fsp->conn->connectpath,
1561 nt_errstr(status)));
1562 TALLOC_FREE(shadow_data);
1566 labels_data_count = (shadow_data->num_volumes * 2 *
1567 sizeof(SHADOW_COPY_LABEL)) + 2;
1572 *out_len = 12 + labels_data_count;
1575 if (max_out_len < *out_len) {
1576 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1577 max_out_len, *out_len);
1578 TALLOC_FREE(shadow_data);
1579 return NT_STATUS_BUFFER_TOO_SMALL;
1582 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1583 if (cur_pdata == NULL) {
1584 TALLOC_FREE(shadow_data);
1585 return NT_STATUS_NO_MEMORY;
1588 *out_data = cur_pdata;
1590 /* num_volumes 4 bytes */
1591 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1594 /* num_labels 4 bytes */
1595 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1598 /* needed_data_count 4 bytes */
1599 SIVAL(cur_pdata, 8, labels_data_count);
1603 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1604 shadow_data->num_volumes, fsp_str_dbg(fsp));
1605 if (labels && shadow_data->labels) {
1606 for (i=0; i<shadow_data->num_volumes; i++) {
1608 status = srvstr_push(cur_pdata, req_flags,
1609 cur_pdata, shadow_data->labels[i],
1610 2 * sizeof(SHADOW_COPY_LABEL),
1611 STR_UNICODE|STR_TERMINATE, &len);
1612 if (!NT_STATUS_IS_OK(status)) {
1613 TALLOC_FREE(*out_data);
1614 TALLOC_FREE(shadow_data);
1617 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1618 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1622 TALLOC_FREE(shadow_data);
1624 return NT_STATUS_OK;
1627 case FSCTL_FIND_FILES_BY_SID:
1629 /* pretend this succeeded -
1631 * we have to send back a list with all files owned by this SID
1633 * but I have to check that --metze
1637 struct dom_sid_buf buf;
1641 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1645 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1646 return NT_STATUS_INVALID_PARAMETER;
1649 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1651 /* unknown 4 bytes: this is not the length of the sid :-( */
1652 /*unknown = IVAL(pdata,0);*/
1654 ret = sid_parse(_in_data + 4, sid_len, &sid);
1656 return NT_STATUS_INVALID_PARAMETER;
1658 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1659 dom_sid_str_buf(&sid, &buf)));
1661 if (!sid_to_uid(&sid, &uid)) {
1662 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1663 dom_sid_str_buf(&sid, &buf),
1664 (unsigned long)sid_len);
1668 /* we can take a look at the find source :-)
1670 * find ./ -uid $uid -name '*' is what we need here
1673 * and send 4bytes len and then NULL terminated unicode strings
1676 * but I don't know how to deal with the paged results
1677 * (maybe we can hang the result anywhere in the fsp struct)
1679 * but I don't know how to deal with the paged results
1680 * (maybe we can hang the result anywhere in the fsp struct)
1682 * we don't send all files at once
1683 * and at the next we should *not* start from the beginning,
1684 * so we have to cache the result
1689 /* this works for now... */
1690 return NT_STATUS_OK;
1693 case FSCTL_QUERY_ALLOCATED_RANGES:
1695 /* FIXME: This is just a dummy reply, telling that all of the
1696 * file is allocated. MKS cp needs that.
1697 * Adding the real allocated ranges via FIEMAP on Linux
1698 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1699 * this FSCTL correct for sparse files.
1701 uint64_t offset, length;
1702 char *out_data_tmp = NULL;
1705 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1707 return NT_STATUS_INVALID_PARAMETER;
1710 if (max_out_len < 16) {
1711 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1713 return NT_STATUS_INVALID_PARAMETER;
1716 offset = BVAL(in_data,0);
1717 length = BVAL(in_data,8);
1719 if (offset + length < offset) {
1720 /* No 64-bit integer wrap. */
1721 return NT_STATUS_INVALID_PARAMETER;
1724 /* Shouldn't this be SMB_VFS_STAT ... ? */
1725 status = vfs_stat_fsp(fsp);
1726 if (!NT_STATUS_IS_OK(status)) {
1731 out_data_tmp = talloc_array(ctx, char, *out_len);
1732 if (out_data_tmp == NULL) {
1733 DBG_DEBUG("unable to allocate memory for response\n");
1734 return NT_STATUS_NO_MEMORY;
1737 if (offset > fsp->fsp_name->st.st_ex_size ||
1738 fsp->fsp_name->st.st_ex_size == 0 ||
1740 memset(out_data_tmp, 0, *out_len);
1742 uint64_t end = offset + length;
1743 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1744 SBVAL(out_data_tmp, 0, 0);
1745 SBVAL(out_data_tmp, 8, end);
1748 *out_data = out_data_tmp;
1750 return NT_STATUS_OK;
1753 case FSCTL_IS_VOLUME_DIRTY:
1755 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1756 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1758 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1759 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1761 return NT_STATUS_INVALID_PARAMETER;
1766 * Only print once ... unfortunately there could be lots of
1767 * different FSCTLs that are called.
1769 if (!vfswrap_logged_ioctl_message) {
1770 vfswrap_logged_ioctl_message = true;
1771 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1772 __func__, function);
1776 return NT_STATUS_NOT_SUPPORTED;
1779 static bool vfswrap_is_offline(struct connection_struct *conn,
1780 const struct smb_filename *fname);
1782 struct vfswrap_get_dos_attributes_state {
1783 struct vfs_aio_state aio_state;
1784 connection_struct *conn;
1785 TALLOC_CTX *mem_ctx;
1786 struct tevent_context *ev;
1787 files_struct *dir_fsp;
1788 struct smb_filename *smb_fname;
1793 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1795 static struct tevent_req *vfswrap_get_dos_attributes_send(
1796 TALLOC_CTX *mem_ctx,
1797 struct tevent_context *ev,
1798 struct vfs_handle_struct *handle,
1799 files_struct *dir_fsp,
1800 struct smb_filename *smb_fname)
1802 struct tevent_req *req = NULL;
1803 struct tevent_req *subreq = NULL;
1804 struct vfswrap_get_dos_attributes_state *state = NULL;
1806 SMB_ASSERT(!is_named_stream(smb_fname));
1808 req = tevent_req_create(mem_ctx, &state,
1809 struct vfswrap_get_dos_attributes_state);
1814 *state = (struct vfswrap_get_dos_attributes_state) {
1815 .conn = dir_fsp->conn,
1819 .smb_fname = smb_fname,
1822 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1823 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1824 "\"store dos attributes\" is disabled\n",
1825 dir_fsp->conn->connectpath);
1826 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1827 return tevent_req_post(req, ev);
1830 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1834 SAMBA_XATTR_DOS_ATTRIB,
1836 if (tevent_req_nomem(subreq, req)) {
1837 return tevent_req_post(req, ev);
1839 tevent_req_set_callback(subreq,
1840 vfswrap_get_dos_attributes_getxattr_done,
1846 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1848 struct tevent_req *req =
1849 tevent_req_callback_data(subreq,
1851 struct vfswrap_get_dos_attributes_state *state =
1852 tevent_req_data(req,
1853 struct vfswrap_get_dos_attributes_state);
1855 DATA_BLOB blob = {0};
1857 char *tofree = NULL;
1858 char pathbuf[PATH_MAX+1];
1860 struct smb_filename smb_fname;
1864 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1868 TALLOC_FREE(subreq);
1869 if (xattr_size == -1) {
1870 status = map_nt_error_from_unix(state->aio_state.error);
1872 if (state->as_root) {
1873 tevent_req_nterror(req, status);
1876 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1877 tevent_req_nterror(req, status);
1881 state->as_root = true;
1884 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1888 SAMBA_XATTR_DOS_ATTRIB,
1891 if (tevent_req_nomem(subreq, req)) {
1894 tevent_req_set_callback(subreq,
1895 vfswrap_get_dos_attributes_getxattr_done,
1900 blob.length = xattr_size;
1902 status = parse_dos_attribute_blob(state->smb_fname,
1905 if (!NT_STATUS_IS_OK(status)) {
1906 tevent_req_nterror(req, status);
1910 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1911 state->smb_fname->base_name,
1916 if (pathlen == -1) {
1917 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1921 smb_fname = (struct smb_filename) {
1923 .st = state->smb_fname->st,
1924 .flags = state->smb_fname->flags,
1925 .twrp = state->smb_fname->twrp,
1928 offline = vfswrap_is_offline(state->conn, &smb_fname);
1930 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1932 TALLOC_FREE(tofree);
1934 tevent_req_done(req);
1938 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1939 struct vfs_aio_state *aio_state,
1942 struct vfswrap_get_dos_attributes_state *state =
1943 tevent_req_data(req,
1944 struct vfswrap_get_dos_attributes_state);
1947 if (tevent_req_is_nterror(req, &status)) {
1948 tevent_req_received(req);
1952 *aio_state = state->aio_state;
1953 *dosmode = state->dosmode;
1954 tevent_req_received(req);
1955 return NT_STATUS_OK;
1958 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1959 struct files_struct *fsp,
1964 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1966 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1968 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1971 return fget_ea_dos_attribute(fsp, dosmode);
1974 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1975 struct files_struct *fsp,
1978 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1980 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1983 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1985 struct vfswrap_offload_read_state {
1989 static struct tevent_req *vfswrap_offload_read_send(
1990 TALLOC_CTX *mem_ctx,
1991 struct tevent_context *ev,
1992 struct vfs_handle_struct *handle,
1993 struct files_struct *fsp,
1999 struct tevent_req *req = NULL;
2000 struct vfswrap_offload_read_state *state = NULL;
2003 req = tevent_req_create(mem_ctx, &state,
2004 struct vfswrap_offload_read_state);
2009 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2010 &vfswrap_offload_ctx);
2011 if (tevent_req_nterror(req, status)) {
2012 return tevent_req_post(req, ev);
2015 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2016 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2017 return tevent_req_post(req, ev);
2020 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2022 if (tevent_req_nterror(req, status)) {
2023 return tevent_req_post(req, ev);
2026 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2028 if (tevent_req_nterror(req, status)) {
2029 return tevent_req_post(req, ev);
2032 tevent_req_done(req);
2033 return tevent_req_post(req, ev);
2036 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2037 struct vfs_handle_struct *handle,
2038 TALLOC_CTX *mem_ctx,
2043 struct vfswrap_offload_read_state *state = tevent_req_data(
2044 req, struct vfswrap_offload_read_state);
2047 if (tevent_req_is_nterror(req, &status)) {
2048 tevent_req_received(req);
2054 token->length = state->token.length;
2055 token->data = talloc_move(mem_ctx, &state->token.data);
2057 tevent_req_received(req);
2058 return NT_STATUS_OK;
2061 struct vfswrap_offload_write_state {
2063 bool read_lck_locked;
2064 bool write_lck_locked;
2066 struct tevent_context *src_ev;
2067 struct files_struct *src_fsp;
2069 struct tevent_context *dst_ev;
2070 struct files_struct *dst_fsp;
2075 size_t next_io_size;
2078 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2079 enum tevent_req_state req_state)
2081 struct vfswrap_offload_write_state *state = tevent_req_data(
2082 req, struct vfswrap_offload_write_state);
2085 if (state->dst_fsp == NULL) {
2089 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2091 state->dst_fsp = NULL;
2094 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2095 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2097 static struct tevent_req *vfswrap_offload_write_send(
2098 struct vfs_handle_struct *handle,
2099 TALLOC_CTX *mem_ctx,
2100 struct tevent_context *ev,
2103 off_t transfer_offset,
2104 struct files_struct *dest_fsp,
2108 struct tevent_req *req;
2109 struct vfswrap_offload_write_state *state = NULL;
2110 /* off_t is signed! */
2111 off_t max_offset = INT64_MAX - to_copy;
2112 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2113 files_struct *src_fsp = NULL;
2117 req = tevent_req_create(mem_ctx, &state,
2118 struct vfswrap_offload_write_state);
2123 *state = (struct vfswrap_offload_write_state) {
2125 .src_off = transfer_offset,
2127 .dst_fsp = dest_fsp,
2128 .dst_off = dest_off,
2130 .remaining = to_copy,
2133 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2136 case FSCTL_SRV_COPYCHUNK:
2137 case FSCTL_SRV_COPYCHUNK_WRITE:
2140 case FSCTL_OFFLOAD_WRITE:
2141 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2142 return tevent_req_post(req, ev);
2144 case FSCTL_DUP_EXTENTS_TO_FILE:
2145 DBG_DEBUG("COW clones not supported by vfs_default\n");
2146 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2147 return tevent_req_post(req, ev);
2150 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2151 return tevent_req_post(req, ev);
2155 * From here on we assume a copy-chunk fsctl
2159 tevent_req_done(req);
2160 return tevent_req_post(req, ev);
2163 if (state->src_off > max_offset) {
2165 * Protect integer checks below.
2167 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2168 return tevent_req_post(req, ev);
2170 if (state->src_off < 0) {
2172 * Protect integer checks below.
2174 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2175 return tevent_req_post(req, ev);
2177 if (state->dst_off > max_offset) {
2179 * Protect integer checks below.
2181 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2182 return tevent_req_post(req, ev);
2184 if (state->dst_off < 0) {
2186 * Protect integer checks below.
2188 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2189 return tevent_req_post(req, ev);
2192 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2194 if (tevent_req_nterror(req, status)) {
2195 return tevent_req_post(req, ev);
2198 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2200 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2201 if (!NT_STATUS_IS_OK(status)) {
2202 tevent_req_nterror(req, status);
2203 return tevent_req_post(req, ev);
2206 ok = change_to_user_and_service_by_fsp(src_fsp);
2208 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2209 return tevent_req_post(req, ev);
2212 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2213 state->src_fsp = src_fsp;
2215 status = vfs_stat_fsp(src_fsp);
2216 if (tevent_req_nterror(req, status)) {
2217 return tevent_req_post(req, ev);
2220 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2222 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2223 * If the SourceOffset or SourceOffset + Length extends beyond
2224 * the end of file, the server SHOULD<240> treat this as a
2225 * STATUS_END_OF_FILE error.
2227 * <240> Section 3.3.5.15.6: Windows servers will return
2228 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2230 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2231 return tevent_req_post(req, ev);
2234 status = vfswrap_offload_copy_file_range(req);
2235 if (NT_STATUS_IS_OK(status)) {
2236 tevent_req_done(req);
2237 return tevent_req_post(req, ev);
2239 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2240 tevent_req_nterror(req, status);
2241 return tevent_req_post(req, ev);
2244 state->buf = talloc_array(state, uint8_t, num);
2245 if (tevent_req_nomem(state->buf, req)) {
2246 return tevent_req_post(req, ev);
2249 status = vfswrap_offload_write_loop(req);
2250 if (!NT_STATUS_IS_OK(status)) {
2251 tevent_req_nterror(req, status);
2252 return tevent_req_post(req, ev);
2258 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2260 struct vfswrap_offload_write_state *state = tevent_req_data(
2261 req, struct vfswrap_offload_write_state);
2262 struct lock_struct lck;
2267 static bool try_copy_file_range = true;
2269 if (!try_copy_file_range) {
2270 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2273 same_file = file_id_equal(&state->src_fsp->file_id,
2274 &state->dst_fsp->file_id);
2276 sys_io_ranges_overlap(state->remaining,
2281 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2284 if (fsp_is_alternate_stream(state->src_fsp) ||
2285 fsp_is_alternate_stream(state->dst_fsp))
2287 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2290 init_strict_lock_struct(state->src_fsp,
2291 state->src_fsp->op->global->open_persistent_id,
2295 lp_posix_cifsu_locktype(state->src_fsp),
2298 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2302 return NT_STATUS_FILE_LOCK_CONFLICT;
2305 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2307 return NT_STATUS_INTERNAL_ERROR;
2310 init_strict_lock_struct(state->dst_fsp,
2311 state->dst_fsp->op->global->open_persistent_id,
2315 lp_posix_cifsu_locktype(state->dst_fsp),
2318 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2322 return NT_STATUS_FILE_LOCK_CONFLICT;
2325 while (state->remaining > 0) {
2326 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2328 fsp_get_io_fd(state->dst_fsp),
2332 if (nwritten == -1) {
2333 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2334 "n [%jd] failed: %s\n",
2335 fsp_str_dbg(state->src_fsp),
2336 (intmax_t)state->src_off,
2337 fsp_str_dbg(state->dst_fsp),
2338 (intmax_t)state->dst_off,
2339 (intmax_t)state->remaining,
2344 try_copy_file_range = false;
2345 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2348 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2351 status = map_nt_error_from_unix(errno);
2352 if (NT_STATUS_EQUAL(
2354 NT_STATUS_MORE_PROCESSING_REQUIRED))
2356 /* Avoid triggering the fallback */
2357 status = NT_STATUS_INTERNAL_ERROR;
2364 if (state->remaining < nwritten) {
2365 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2366 "n [%jd] remaining [%jd]\n",
2367 fsp_str_dbg(state->src_fsp),
2368 fsp_str_dbg(state->dst_fsp),
2370 (intmax_t)state->remaining);
2371 return NT_STATUS_INTERNAL_ERROR;
2374 if (nwritten == 0) {
2377 state->copied += nwritten;
2378 state->remaining -= nwritten;
2382 * Tell the req cleanup function there's no need to call
2383 * change_to_user_and_service_by_fsp() on the dst handle.
2385 state->dst_fsp = NULL;
2386 return NT_STATUS_OK;
2389 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2391 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2393 struct vfswrap_offload_write_state *state = tevent_req_data(
2394 req, struct vfswrap_offload_write_state);
2395 struct tevent_req *subreq = NULL;
2396 struct lock_struct read_lck;
2400 * This is called under the context of state->src_fsp.
2403 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2405 init_strict_lock_struct(state->src_fsp,
2406 state->src_fsp->op->global->open_persistent_id,
2408 state->next_io_size,
2410 lp_posix_cifsu_locktype(state->src_fsp),
2413 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2417 return NT_STATUS_FILE_LOCK_CONFLICT;
2420 subreq = SMB_VFS_PREAD_SEND(state,
2424 state->next_io_size,
2426 if (subreq == NULL) {
2427 return NT_STATUS_NO_MEMORY;
2429 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2431 return NT_STATUS_OK;
2434 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2436 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2438 struct tevent_req *req = tevent_req_callback_data(
2439 subreq, struct tevent_req);
2440 struct vfswrap_offload_write_state *state = tevent_req_data(
2441 req, struct vfswrap_offload_write_state);
2442 struct vfs_aio_state aio_state;
2443 struct lock_struct write_lck;
2447 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2448 TALLOC_FREE(subreq);
2450 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2451 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2454 if (nread != state->next_io_size) {
2455 DBG_ERR("Short read, only %zd of %zu\n",
2456 nread, state->next_io_size);
2457 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2461 state->src_off += nread;
2463 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2465 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2469 init_strict_lock_struct(state->dst_fsp,
2470 state->dst_fsp->op->global->open_persistent_id,
2472 state->next_io_size,
2474 lp_posix_cifsu_locktype(state->dst_fsp),
2477 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2481 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2485 subreq = SMB_VFS_PWRITE_SEND(state,
2489 state->next_io_size,
2491 if (subreq == NULL) {
2492 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2495 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2498 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2500 struct tevent_req *req = tevent_req_callback_data(
2501 subreq, struct tevent_req);
2502 struct vfswrap_offload_write_state *state = tevent_req_data(
2503 req, struct vfswrap_offload_write_state);
2504 struct vfs_aio_state aio_state;
2509 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2510 TALLOC_FREE(subreq);
2511 if (nwritten == -1) {
2512 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2513 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2516 if (nwritten != state->next_io_size) {
2517 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2518 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2522 state->dst_off += nwritten;
2524 if (state->remaining < nwritten) {
2525 /* Paranoia check */
2526 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2529 state->copied += nwritten;
2530 state->remaining -= nwritten;
2531 if (state->remaining == 0) {
2532 tevent_req_done(req);
2536 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2538 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2542 status = vfswrap_offload_write_loop(req);
2543 if (!NT_STATUS_IS_OK(status)) {
2544 tevent_req_nterror(req, status);
2551 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2552 struct tevent_req *req,
2555 struct vfswrap_offload_write_state *state = tevent_req_data(
2556 req, struct vfswrap_offload_write_state);
2559 if (tevent_req_is_nterror(req, &status)) {
2560 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2562 tevent_req_received(req);
2566 *copied = state->copied;
2567 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2568 tevent_req_received(req);
2570 return NT_STATUS_OK;
2573 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2574 TALLOC_CTX *mem_ctx,
2575 struct files_struct *fsp,
2576 uint16_t *_compression_fmt)
2578 return NT_STATUS_INVALID_DEVICE_REQUEST;
2581 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2582 TALLOC_CTX *mem_ctx,
2583 struct files_struct *fsp,
2584 uint16_t compression_fmt)
2586 return NT_STATUS_INVALID_DEVICE_REQUEST;
2589 /********************************************************************
2590 Given a stat buffer return the allocated size on disk, taking into
2591 account sparse files.
2592 ********************************************************************/
2593 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2594 struct files_struct *fsp,
2595 const SMB_STRUCT_STAT *sbuf)
2599 START_PROFILE(syscall_get_alloc_size);
2601 if(S_ISDIR(sbuf->st_ex_mode)) {
2606 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2607 /* The type of st_blocksize is blkcnt_t which *MUST* be
2608 signed (according to POSIX) and can be less than 64-bits.
2609 Ensure when we're converting to 64 bits wide we don't
2611 #if defined(SIZEOF_BLKCNT_T_8)
2612 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2613 #elif defined(SIZEOF_BLKCNT_T_4)
2615 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2616 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2619 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2623 * Some file systems do not allocate a block for very
2624 * small files. But for non-empty file should report a
2628 uint64_t filesize = get_file_size_stat(sbuf);
2630 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2634 result = get_file_size_stat(sbuf);
2637 if (fsp && fsp->initial_allocation_size)
2638 result = MAX(result,fsp->initial_allocation_size);
2640 result = smb_roundup(handle->conn, result);
2643 END_PROFILE(syscall_get_alloc_size);
2647 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2648 struct files_struct *dirfsp,
2649 const struct smb_filename *smb_fname,
2654 START_PROFILE(syscall_unlinkat);
2656 SMB_ASSERT(!is_named_stream(smb_fname));
2658 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2659 smb_fname->base_name,
2662 END_PROFILE(syscall_unlinkat);
2666 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2670 START_PROFILE(syscall_fchmod);
2672 if (!fsp->fsp_flags.is_pathref) {
2673 result = fchmod(fsp_get_io_fd(fsp), mode);
2674 END_PROFILE(syscall_fchmod);
2678 if (fsp->fsp_flags.have_proc_fds) {
2679 int fd = fsp_get_pathref_fd(fsp);
2680 struct sys_proc_fd_path_buf buf;
2682 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2684 END_PROFILE(syscall_fchmod);
2689 * This is no longer a handle based call.
2691 result = chmod(fsp->fsp_name->base_name, mode);
2693 END_PROFILE(syscall_fchmod);
2697 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2702 START_PROFILE(syscall_fchown);
2703 if (!fsp->fsp_flags.is_pathref) {
2704 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2705 END_PROFILE(syscall_fchown);
2709 if (fsp->fsp_flags.have_proc_fds) {
2710 int fd = fsp_get_pathref_fd(fsp);
2711 struct sys_proc_fd_path_buf buf;
2713 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2715 END_PROFILE(syscall_fchown);
2720 * This is no longer a handle based call.
2722 result = chown(fsp->fsp_name->base_name, uid, gid);
2723 END_PROFILE(syscall_fchown);
2731 static int vfswrap_lchown(vfs_handle_struct *handle,
2732 const struct smb_filename *smb_fname,
2738 START_PROFILE(syscall_lchown);
2739 result = lchown(smb_fname->base_name, uid, gid);
2740 END_PROFILE(syscall_lchown);
2744 static int vfswrap_chdir(vfs_handle_struct *handle,
2745 const struct smb_filename *smb_fname)
2749 START_PROFILE(syscall_chdir);
2750 result = chdir(smb_fname->base_name);
2751 END_PROFILE(syscall_chdir);
2755 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2759 struct smb_filename *smb_fname = NULL;
2761 START_PROFILE(syscall_getwd);
2762 result = sys_getwd();
2763 END_PROFILE(syscall_getwd);
2765 if (result == NULL) {
2768 smb_fname = synthetic_smb_fname(ctx,
2775 * sys_getwd() *always* returns malloced memory.
2776 * We must free here to avoid leaks:
2777 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2783 /*********************************************************************
2784 nsec timestamp resolution call. Convert down to whatever the underlying
2785 system will support.
2786 **********************************************************************/
2788 static int vfswrap_fntimes(vfs_handle_struct *handle,
2790 struct smb_file_time *ft)
2793 struct timespec ts[2];
2794 struct timespec *times = NULL;
2796 START_PROFILE(syscall_fntimes);
2798 if (fsp_is_alternate_stream(fsp)) {
2804 if (is_omit_timespec(&ft->atime)) {
2805 ft->atime = fsp->fsp_name->st.st_ex_atime;
2808 if (is_omit_timespec(&ft->mtime)) {
2809 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2812 if (!is_omit_timespec(&ft->create_time)) {
2813 set_create_timespec_ea(fsp,
2817 if ((timespec_compare(&ft->atime,
2818 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2819 (timespec_compare(&ft->mtime,
2820 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2832 if (!fsp->fsp_flags.is_pathref) {
2833 result = futimens(fsp_get_io_fd(fsp), times);
2837 if (fsp->fsp_flags.have_proc_fds) {
2838 int fd = fsp_get_pathref_fd(fsp);
2839 struct sys_proc_fd_path_buf buf;
2841 result = utimensat(AT_FDCWD,
2842 sys_proc_fd_path(fd, &buf),
2850 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2851 * path translation mechanism. Fallback to path based call.
2853 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2856 END_PROFILE(syscall_fntimes);
2862 /*********************************************************************
2863 A version of ftruncate that will write the space on disk if strict
2865 **********************************************************************/
2867 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2869 off_t space_to_write;
2870 uint64_t space_avail;
2871 uint64_t bsize,dfree,dsize;
2874 SMB_STRUCT_STAT *pst;
2877 ok = vfs_valid_pwrite_range(len, 0);
2883 status = vfs_stat_fsp(fsp);
2884 if (!NT_STATUS_IS_OK(status)) {
2887 pst = &fsp->fsp_name->st;
2890 if (S_ISFIFO(pst->st_ex_mode))
2894 if (pst->st_ex_size == len)
2897 /* Shrink - just ftruncate. */
2898 if (pst->st_ex_size > len)
2899 return ftruncate(fsp_get_io_fd(fsp), len);
2901 space_to_write = len - pst->st_ex_size;
2903 /* for allocation try fallocate first. This can fail on some
2904 platforms e.g. when the filesystem doesn't support it and no
2905 emulation is being done by the libc (like on AIX with JFS1). In that
2906 case we do our own emulation. fallocate implementations can
2907 return ENOTSUP or EINVAL in cases like that. */
2908 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2909 if (ret == -1 && errno == ENOSPC) {
2915 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2916 "error %d. Falling back to slow manual allocation\n", errno);
2918 /* available disk space is enough or not? */
2920 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2921 /* space_avail is 1k blocks */
2922 if (space_avail == (uint64_t)-1 ||
2923 ((uint64_t)space_to_write/1024 > space_avail) ) {
2928 /* Write out the real space on disk. */
2929 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2937 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2940 SMB_STRUCT_STAT *pst;
2944 START_PROFILE(syscall_ftruncate);
2946 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2947 result = strict_allocate_ftruncate(handle, fsp, len);
2948 END_PROFILE(syscall_ftruncate);
2952 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2953 ftruncate if the system supports it. Then I discovered that
2954 you can have some filesystems that support ftruncate
2955 expansion and some that don't! On Linux fat can't do
2956 ftruncate extend but ext2 can. */
2958 result = ftruncate(fsp_get_io_fd(fsp), len);
2960 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2961 extend a file with ftruncate. Provide alternate implementation
2964 /* Do an fstat to see if the file is longer than the requested
2965 size in which case the ftruncate above should have
2966 succeeded or shorter, in which case seek to len - 1 and
2967 write 1 byte of zero */
2968 status = vfs_stat_fsp(fsp);
2969 if (!NT_STATUS_IS_OK(status)) {
2973 /* We need to update the files_struct after successful ftruncate */
2978 pst = &fsp->fsp_name->st;
2981 if (S_ISFIFO(pst->st_ex_mode)) {
2987 if (pst->st_ex_size == len) {
2992 if (pst->st_ex_size > len) {
2993 /* the ftruncate should have worked */
2997 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3005 END_PROFILE(syscall_ftruncate);
3009 static int vfswrap_fallocate(vfs_handle_struct *handle,
3017 START_PROFILE(syscall_fallocate);
3019 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3021 * posix_fallocate returns 0 on success, errno on error
3022 * and doesn't set errno. Make it behave like fallocate()
3023 * which returns -1, and sets errno on failure.
3030 /* sys_fallocate handles filtering of unsupported mode flags */
3031 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3033 END_PROFILE(syscall_fallocate);
3037 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3041 START_PROFILE(syscall_fcntl_lock);
3043 if (fsp->fsp_flags.use_ofd_locks) {
3044 op = map_process_lock_to_ofd_lock(op);
3047 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3048 END_PROFILE(syscall_fcntl_lock);
3052 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3054 uint32_t share_access,
3055 uint32_t access_mask)
3061 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3065 va_list dup_cmd_arg;
3069 START_PROFILE(syscall_fcntl);
3071 va_copy(dup_cmd_arg, cmd_arg);
3077 #if defined(HAVE_OFD_LOCKS)
3082 #if defined(HAVE_F_OWNER_EX)
3086 #if defined(HAVE_RW_HINTS)
3089 case F_GET_FILE_RW_HINT:
3090 case F_SET_FILE_RW_HINT:
3092 argp = va_arg(dup_cmd_arg, void *);
3093 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3096 val = va_arg(dup_cmd_arg, int);
3097 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3100 va_end(dup_cmd_arg);
3102 END_PROFILE(syscall_fcntl);
3106 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3111 START_PROFILE(syscall_fcntl_getlock);
3113 if (fsp->fsp_flags.use_ofd_locks) {
3114 op = map_process_lock_to_ofd_lock(op);
3117 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3118 END_PROFILE(syscall_fcntl_getlock);
3122 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3127 START_PROFILE(syscall_linux_setlease);
3129 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3131 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3132 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3136 END_PROFILE(syscall_linux_setlease);
3140 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3141 const struct smb_filename *link_target,
3142 struct files_struct *dirfsp,
3143 const struct smb_filename *new_smb_fname)
3147 START_PROFILE(syscall_symlinkat);
3149 SMB_ASSERT(!is_named_stream(new_smb_fname));
3151 result = symlinkat(link_target->base_name,
3152 fsp_get_pathref_fd(dirfsp),
3153 new_smb_fname->base_name);
3154 END_PROFILE(syscall_symlinkat);
3158 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3159 const struct files_struct *dirfsp,
3160 const struct smb_filename *smb_fname,
3166 START_PROFILE(syscall_readlinkat);
3168 SMB_ASSERT(!is_named_stream(smb_fname));
3170 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3171 smb_fname->base_name,
3175 END_PROFILE(syscall_readlinkat);
3179 static int vfswrap_linkat(vfs_handle_struct *handle,
3180 files_struct *srcfsp,
3181 const struct smb_filename *old_smb_fname,
3182 files_struct *dstfsp,
3183 const struct smb_filename *new_smb_fname,
3188 START_PROFILE(syscall_linkat);
3190 SMB_ASSERT(!is_named_stream(old_smb_fname));
3191 SMB_ASSERT(!is_named_stream(new_smb_fname));
3193 result = linkat(fsp_get_pathref_fd(srcfsp),
3194 old_smb_fname->base_name,
3195 fsp_get_pathref_fd(dstfsp),
3196 new_smb_fname->base_name,
3199 END_PROFILE(syscall_linkat);
3203 static int vfswrap_mknodat(vfs_handle_struct *handle,
3204 files_struct *dirfsp,
3205 const struct smb_filename *smb_fname,
3211 START_PROFILE(syscall_mknodat);
3213 SMB_ASSERT(!is_named_stream(smb_fname));
3215 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3216 smb_fname->base_name,
3220 END_PROFILE(syscall_mknodat);
3224 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3226 const struct smb_filename *smb_fname)
3229 struct smb_filename *result_fname = NULL;
3231 START_PROFILE(syscall_realpath);
3232 result = sys_realpath(smb_fname->base_name);
3233 END_PROFILE(syscall_realpath);
3235 result_fname = synthetic_smb_fname(ctx,
3243 return result_fname;
3246 static int vfswrap_fchflags(vfs_handle_struct *handle,
3247 struct files_struct *fsp,
3250 #ifdef HAVE_FCHFLAGS
3251 int fd = fsp_get_pathref_fd(fsp);
3253 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3255 if (!fsp->fsp_flags.is_pathref) {
3256 return fchflags(fd, flags);
3259 if (fsp->fsp_flags.have_proc_fds) {
3260 struct sys_proc_fd_path_buf buf;
3262 return chflags(sys_proc_fd_path(fd, &buf), flags);
3266 * This is no longer a handle based call.
3268 return chflags(fsp->fsp_name->base_name, flags);
3275 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3276 const SMB_STRUCT_STAT *sbuf)
3280 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3284 key.devid = sbuf->st_ex_dev;
3285 key.inode = sbuf->st_ex_ino;
3286 /* key.extid is unused by default. */
3291 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3292 const SMB_STRUCT_STAT *psbuf)
3296 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3297 return (uint64_t)psbuf->st_ex_ino;
3301 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3304 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3309 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3310 struct files_struct *fsp,
3311 TALLOC_CTX *mem_ctx,
3312 unsigned int *pnum_streams,
3313 struct stream_struct **pstreams)
3315 struct stream_struct *tmp_streams = NULL;
3316 unsigned int num_streams = *pnum_streams;
3317 struct stream_struct *streams = *pstreams;
3320 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3322 if (fsp->fsp_flags.is_directory) {
3324 * No default streams on directories
3328 status = vfs_stat_fsp(fsp);
3329 if (!NT_STATUS_IS_OK(status)) {
3333 if (num_streams + 1 < 1) {
3335 return NT_STATUS_INVALID_PARAMETER;
3338 tmp_streams = talloc_realloc(mem_ctx,
3340 struct stream_struct,
3342 if (tmp_streams == NULL) {
3343 return NT_STATUS_NO_MEMORY;
3345 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3346 if (tmp_streams[num_streams].name == NULL) {
3347 return NT_STATUS_NO_MEMORY;
3349 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3350 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3353 &fsp->fsp_name->st);
3356 *pnum_streams = num_streams;
3357 *pstreams = tmp_streams;
3359 return NT_STATUS_OK;
3362 static NTSTATUS vfswrap_get_real_filename_at(
3363 struct vfs_handle_struct *handle,
3364 struct files_struct *dirfsp,
3366 TALLOC_CTX *mem_ctx,
3370 * Don't fall back to get_real_filename so callers can differentiate
3371 * between a full directory scan and an actual case-insensitive stat.
3373 return NT_STATUS_NOT_SUPPORTED;
3376 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3377 const struct files_struct *dirfsp,
3378 const struct smb_filename *smb_fname)
3380 return handle->conn->connectpath;
3383 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3384 struct byte_range_lock *br_lck,
3385 struct lock_struct *plock)
3387 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3389 /* Note: blr is not used in the default implementation. */
3390 return brl_lock_windows_default(br_lck, plock);
3393 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3394 struct byte_range_lock *br_lck,
3395 const struct lock_struct *plock)
3397 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3399 return brl_unlock_windows_default(br_lck, plock);
3402 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3404 struct lock_struct *plock)
3406 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3407 plock->lock_type == WRITE_LOCK);
3409 return strict_lock_check_default(fsp, plock);
3412 /* NT ACL operations. */
3414 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3416 uint32_t security_info,
3417 TALLOC_CTX *mem_ctx,
3418 struct security_descriptor **ppdesc)
3422 START_PROFILE(fget_nt_acl);
3424 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3426 result = posix_fget_nt_acl(fsp, security_info,
3428 END_PROFILE(fget_nt_acl);
3432 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3436 START_PROFILE(fset_nt_acl);
3438 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3440 result = set_nt_acl(fsp, security_info_sent, psd);
3441 END_PROFILE(fset_nt_acl);
3445 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3446 struct smb_filename *file,
3447 struct security_acl *sacl,
3448 uint32_t access_requested,
3449 uint32_t access_denied)
3451 return NT_STATUS_OK; /* Nothing to do here ... */
3454 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3456 SMB_ACL_TYPE_T type,
3457 TALLOC_CTX *mem_ctx)
3459 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3461 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3464 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3466 SMB_ACL_TYPE_T type,
3469 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3471 return sys_acl_set_fd(handle, fsp, type, theacl);
3474 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3477 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3479 return sys_acl_delete_def_fd(handle, fsp);
3482 /****************************************************************
3483 Extended attribute operations.
3484 *****************************************************************/
3486 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3487 struct files_struct *fsp,
3492 int fd = fsp_get_pathref_fd(fsp);
3494 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3496 if (!fsp->fsp_flags.is_pathref) {
3497 return fgetxattr(fd, name, value, size);
3500 if (fsp->fsp_flags.have_proc_fds) {
3501 struct sys_proc_fd_path_buf buf;
3503 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3507 * This is no longer a handle based call.
3509 return getxattr(fsp->fsp_name->base_name, name, value, size);
3512 struct vfswrap_getxattrat_state {
3513 struct tevent_context *ev;
3514 struct vfs_handle_struct *handle;
3515 files_struct *dir_fsp;
3516 const struct smb_filename *smb_fname;
3519 * The following variables are talloced off "state" which is protected
3520 * by a destructor and thus are guaranteed to be safe to be used in the
3521 * job function in the worker thread.
3524 const char *xattr_name;
3525 uint8_t *xattr_value;
3526 struct security_unix_token *token;
3529 struct vfs_aio_state vfs_aio_state;
3530 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3533 static int vfswrap_getxattrat_state_destructor(
3534 struct vfswrap_getxattrat_state *state)
3539 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3540 static void vfswrap_getxattrat_do_async(void *private_data);
3541 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3543 static struct tevent_req *vfswrap_getxattrat_send(
3544 TALLOC_CTX *mem_ctx,
3545 struct tevent_context *ev,
3546 struct vfs_handle_struct *handle,
3547 files_struct *dir_fsp,
3548 const struct smb_filename *smb_fname,
3549 const char *xattr_name,
3552 struct tevent_req *req = NULL;
3553 struct tevent_req *subreq = NULL;
3554 struct vfswrap_getxattrat_state *state = NULL;
3555 size_t max_threads = 0;
3556 bool have_per_thread_cwd = false;
3557 bool have_per_thread_creds = false;
3558 bool do_async = false;
3560 SMB_ASSERT(!is_named_stream(smb_fname));
3562 req = tevent_req_create(mem_ctx, &state,
3563 struct vfswrap_getxattrat_state);
3567 *state = (struct vfswrap_getxattrat_state) {
3571 .smb_fname = smb_fname,
3574 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3575 if (max_threads >= 1) {
3577 * We need a non sync threadpool!
3579 have_per_thread_cwd = per_thread_cwd_supported();
3581 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3582 have_per_thread_creds = true;
3584 if (have_per_thread_cwd && have_per_thread_creds) {
3588 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3589 state->profile_bytes, 0);
3591 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3592 DBG_ERR("Need a valid directory fd\n");
3593 tevent_req_error(req, EINVAL);
3594 return tevent_req_post(req, ev);
3597 if (alloc_hint > 0) {
3598 state->xattr_value = talloc_zero_array(state,
3601 if (tevent_req_nomem(state->xattr_value, req)) {
3602 return tevent_req_post(req, ev);
3607 vfswrap_getxattrat_do_sync(req);
3608 return tevent_req_post(req, ev);
3612 * Now allocate all parameters from a memory context that won't go away
3613 * no matter what. These parameters will get used in threads and we
3614 * can't reliably cancel threads, so all buffers passed to the threads
3615 * must not be freed before all referencing threads terminate.
3618 state->name = talloc_strdup(state, smb_fname->base_name);
3619 if (tevent_req_nomem(state->name, req)) {
3620 return tevent_req_post(req, ev);
3623 state->xattr_name = talloc_strdup(state, xattr_name);
3624 if (tevent_req_nomem(state->xattr_name, req)) {
3625 return tevent_req_post(req, ev);
3629 * This is a hot codepath so at first glance one might think we should
3630 * somehow optimize away the token allocation and do a
3631 * talloc_reference() or similar black magic instead. But due to the
3632 * talloc_stackframe pool per SMB2 request this should be a simple copy
3633 * without a malloc in most cases.
3635 if (geteuid() == sec_initial_uid()) {
3636 state->token = root_unix_token(state);
3638 state->token = copy_unix_token(
3640 dir_fsp->conn->session_info->unix_token);
3642 if (tevent_req_nomem(state->token, req)) {
3643 return tevent_req_post(req, ev);
3646 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3648 subreq = pthreadpool_tevent_job_send(
3651 dir_fsp->conn->sconn->pool,
3652 vfswrap_getxattrat_do_async,
3654 if (tevent_req_nomem(subreq, req)) {
3655 return tevent_req_post(req, ev);
3657 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3659 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3664 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3666 struct vfswrap_getxattrat_state *state = tevent_req_data(
3667 req, struct vfswrap_getxattrat_state);
3669 state->xattr_size = vfswrap_fgetxattr(state->handle,
3670 state->smb_fname->fsp,
3673 talloc_array_length(state->xattr_value));
3674 if (state->xattr_size == -1) {
3675 tevent_req_error(req, errno);
3679 tevent_req_done(req);
3683 static void vfswrap_getxattrat_do_async(void *private_data)
3685 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3686 private_data, struct vfswrap_getxattrat_state);
3687 struct timespec start_time;
3688 struct timespec end_time;
3691 PROFILE_TIMESTAMP(&start_time);
3692 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3695 * Here we simulate a getxattrat()
3696 * call using fchdir();getxattr()
3699 per_thread_cwd_activate();
3701 /* Become the correct credential on this thread. */
3702 ret = set_thread_credentials(state->token->uid,
3704 (size_t)state->token->ngroups,
3705 state->token->groups);
3707 state->xattr_size = -1;
3708 state->vfs_aio_state.error = errno;
3712 state->xattr_size = vfswrap_fgetxattr(state->handle,
3713 state->smb_fname->fsp,
3716 talloc_array_length(state->xattr_value));
3717 if (state->xattr_size == -1) {
3718 state->vfs_aio_state.error = errno;
3722 PROFILE_TIMESTAMP(&end_time);
3723 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3724 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3727 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3729 struct tevent_req *req = tevent_req_callback_data(
3730 subreq, struct tevent_req);
3731 struct vfswrap_getxattrat_state *state = tevent_req_data(
3732 req, struct vfswrap_getxattrat_state);
3737 * Make sure we run as the user again
3739 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3742 ret = pthreadpool_tevent_job_recv(subreq);
3743 TALLOC_FREE(subreq);
3744 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3745 talloc_set_destructor(state, NULL);
3747 if (ret != EAGAIN) {
3748 tevent_req_error(req, ret);
3752 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3753 * means the lower level pthreadpool failed to create a new
3754 * thread. Fallback to sync processing in that case to allow
3755 * some progress for the client.
3757 vfswrap_getxattrat_do_sync(req);
3761 if (state->xattr_size == -1) {
3762 tevent_req_error(req, state->vfs_aio_state.error);
3766 if (state->xattr_value == NULL) {
3768 * The caller only wanted the size.
3770 tevent_req_done(req);
3775 * shrink the buffer to the returned size.
3776 * (can't fail). It means NULL if size is 0.
3778 state->xattr_value = talloc_realloc(state,
3783 tevent_req_done(req);
3786 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3787 struct vfs_aio_state *aio_state,
3788 TALLOC_CTX *mem_ctx,
3789 uint8_t **xattr_value)
3791 struct vfswrap_getxattrat_state *state = tevent_req_data(
3792 req, struct vfswrap_getxattrat_state);
3795 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3796 tevent_req_received(req);
3800 *aio_state = state->vfs_aio_state;
3801 xattr_size = state->xattr_size;
3802 if (xattr_value != NULL) {
3803 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3806 tevent_req_received(req);
3810 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3812 int fd = fsp_get_pathref_fd(fsp);
3814 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3816 if (!fsp->fsp_flags.is_pathref) {
3817 return flistxattr(fd, list, size);
3820 if (fsp->fsp_flags.have_proc_fds) {
3821 struct sys_proc_fd_path_buf buf;
3823 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3827 * This is no longer a handle based call.
3829 return listxattr(fsp->fsp_name->base_name, list, size);
3832 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3834 int fd = fsp_get_pathref_fd(fsp);
3836 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3838 if (!fsp->fsp_flags.is_pathref) {
3839 return fremovexattr(fd, name);
3842 if (fsp->fsp_flags.have_proc_fds) {
3843 struct sys_proc_fd_path_buf buf;
3845 return removexattr(sys_proc_fd_path(fd, &buf), name);
3849 * This is no longer a handle based call.
3851 return removexattr(fsp->fsp_name->base_name, name);
3854 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3856 int fd = fsp_get_pathref_fd(fsp);
3858 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3860 if (!fsp->fsp_flags.is_pathref) {
3861 return fsetxattr(fd, name, value, size, flags);
3864 if (fsp->fsp_flags.have_proc_fds) {
3865 struct sys_proc_fd_path_buf buf;
3867 return setxattr(sys_proc_fd_path(fd, &buf),
3875 * This is no longer a handle based call.
3877 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3880 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3885 static bool vfswrap_is_offline(struct connection_struct *conn,
3886 const struct smb_filename *fname)
3890 bool offline = false;
3892 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3896 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3897 #if defined(ENOTSUP)
3903 status = get_full_smb_filename(talloc_tos(), fname, &path);
3904 if (!NT_STATUS_IS_OK(status)) {
3905 errno = map_errno_from_nt_status(status);
3909 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3916 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3917 struct files_struct *fsp,
3918 TALLOC_CTX *mem_ctx,
3921 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3924 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3925 struct files_struct *fsp,
3926 const DATA_BLOB old_cookie,
3927 TALLOC_CTX *mem_ctx,
3928 DATA_BLOB *new_cookie)
3930 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3934 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3935 struct smb_request *smb1req,
3936 struct smbXsrv_open *op,
3937 const DATA_BLOB old_cookie,
3938 TALLOC_CTX *mem_ctx,
3939 struct files_struct **fsp,
3940 DATA_BLOB *new_cookie)
3942 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3943 old_cookie, mem_ctx,
3947 static struct vfs_fn_pointers vfs_default_fns = {
3948 /* Disk operations */
3950 .connect_fn = vfswrap_connect,
3951 .disconnect_fn = vfswrap_disconnect,
3952 .disk_free_fn = vfswrap_disk_free,
3953 .get_quota_fn = vfswrap_get_quota,
3954 .set_quota_fn = vfswrap_set_quota,
3955 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3956 .statvfs_fn = vfswrap_statvfs,
3957 .fs_capabilities_fn = vfswrap_fs_capabilities,
3958 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3959 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3960 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3961 .snap_check_path_fn = vfswrap_snap_check_path,
3962 .snap_create_fn = vfswrap_snap_create,
3963 .snap_delete_fn = vfswrap_snap_delete,
3965 /* Directory operations */
3967 .fdopendir_fn = vfswrap_fdopendir,
3968 .readdir_fn = vfswrap_readdir,
3969 .freaddir_attr_fn = vfswrap_freaddir_attr,
3970 .rewind_dir_fn = vfswrap_rewinddir,
3971 .mkdirat_fn = vfswrap_mkdirat,
3972 .closedir_fn = vfswrap_closedir,
3974 /* File operations */
3976 .openat_fn = vfswrap_openat,
3977 .create_file_fn = vfswrap_create_file,
3978 .close_fn = vfswrap_close,
3979 .pread_fn = vfswrap_pread,
3980 .pread_send_fn = vfswrap_pread_send,
3981 .pread_recv_fn = vfswrap_pread_recv,
3982 .pwrite_fn = vfswrap_pwrite,
3983 .pwrite_send_fn = vfswrap_pwrite_send,
3984 .pwrite_recv_fn = vfswrap_pwrite_recv,
3985 .lseek_fn = vfswrap_lseek,
3986 .sendfile_fn = vfswrap_sendfile,
3987 .recvfile_fn = vfswrap_recvfile,
3988 .renameat_fn = vfswrap_renameat,
3989 .fsync_send_fn = vfswrap_fsync_send,
3990 .fsync_recv_fn = vfswrap_fsync_recv,
3991 .stat_fn = vfswrap_stat,
3992 .fstat_fn = vfswrap_fstat,
3993 .lstat_fn = vfswrap_lstat,
3994 .fstatat_fn = vfswrap_fstatat,
3995 .get_alloc_size_fn = vfswrap_get_alloc_size,
3996 .unlinkat_fn = vfswrap_unlinkat,
3997 .fchmod_fn = vfswrap_fchmod,
3998 .fchown_fn = vfswrap_fchown,
3999 .lchown_fn = vfswrap_lchown,
4000 .chdir_fn = vfswrap_chdir,
4001 .getwd_fn = vfswrap_getwd,
4002 .fntimes_fn = vfswrap_fntimes,
4003 .ftruncate_fn = vfswrap_ftruncate,
4004 .fallocate_fn = vfswrap_fallocate,
4005 .lock_fn = vfswrap_lock,
4006 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4007 .fcntl_fn = vfswrap_fcntl,
4008 .linux_setlease_fn = vfswrap_linux_setlease,
4009 .getlock_fn = vfswrap_getlock,
4010 .symlinkat_fn = vfswrap_symlinkat,
4011 .readlinkat_fn = vfswrap_readlinkat,
4012 .linkat_fn = vfswrap_linkat,
4013 .mknodat_fn = vfswrap_mknodat,
4014 .realpath_fn = vfswrap_realpath,
4015 .fchflags_fn = vfswrap_fchflags,
4016 .file_id_create_fn = vfswrap_file_id_create,
4017 .fs_file_id_fn = vfswrap_fs_file_id,
4018 .fstreaminfo_fn = vfswrap_fstreaminfo,
4019 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4020 .connectpath_fn = vfswrap_connectpath,
4021 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4022 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4023 .strict_lock_check_fn = vfswrap_strict_lock_check,
4024 .translate_name_fn = vfswrap_translate_name,
4025 .parent_pathname_fn = vfswrap_parent_pathname,
4026 .fsctl_fn = vfswrap_fsctl,
4027 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4028 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4029 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4030 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4031 .offload_read_send_fn = vfswrap_offload_read_send,
4032 .offload_read_recv_fn = vfswrap_offload_read_recv,
4033 .offload_write_send_fn = vfswrap_offload_write_send,
4034 .offload_write_recv_fn = vfswrap_offload_write_recv,
4035 .fget_compression_fn = vfswrap_fget_compression,
4036 .set_compression_fn = vfswrap_set_compression,
4038 /* NT ACL operations. */
4040 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4041 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4042 .audit_file_fn = vfswrap_audit_file,
4044 /* POSIX ACL operations. */
4046 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4047 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4048 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4049 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4051 /* EA operations. */
4052 .getxattrat_send_fn = vfswrap_getxattrat_send,
4053 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4054 .fgetxattr_fn = vfswrap_fgetxattr,
4055 .flistxattr_fn = vfswrap_flistxattr,
4056 .fremovexattr_fn = vfswrap_fremovexattr,
4057 .fsetxattr_fn = vfswrap_fsetxattr,
4059 /* aio operations */
4060 .aio_force_fn = vfswrap_aio_force,
4062 /* durable handle operations */
4063 .durable_cookie_fn = vfswrap_durable_cookie,
4064 .durable_disconnect_fn = vfswrap_durable_disconnect,
4065 .durable_reconnect_fn = vfswrap_durable_reconnect,
4069 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4072 * Here we need to implement every call!
4074 * As this is the end of the vfs module chain.
4076 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4077 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4078 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);