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,
747 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
750 END_PROFILE(syscall_openat);
753 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
754 struct smb_request *req,
755 struct files_struct *dirfsp,
756 struct smb_filename *smb_fname,
757 uint32_t access_mask,
758 uint32_t share_access,
759 uint32_t create_disposition,
760 uint32_t create_options,
761 uint32_t file_attributes,
762 uint32_t oplock_request,
763 const struct smb2_lease *lease,
764 uint64_t allocation_size,
765 uint32_t private_flags,
766 struct security_descriptor *sd,
767 struct ea_list *ea_list,
768 files_struct **result,
770 const struct smb2_create_blobs *in_context_blobs,
771 struct smb2_create_blobs *out_context_blobs)
773 return create_file_default(handle->conn, req, dirfsp, smb_fname,
774 access_mask, share_access,
775 create_disposition, create_options,
776 file_attributes, oplock_request, lease,
777 allocation_size, private_flags,
779 pinfo, in_context_blobs, out_context_blobs);
782 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
786 START_PROFILE(syscall_close);
787 result = fd_close_posix(fsp);
788 END_PROFILE(syscall_close);
792 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
793 size_t n, off_t offset)
797 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
798 START_PROFILE_BYTES(syscall_pread, n);
799 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
800 END_PROFILE_BYTES(syscall_pread);
802 if (result == -1 && errno == ESPIPE) {
803 /* Maintain the fiction that pipes can be seeked (sought?) on. */
804 result = sys_read(fsp_get_io_fd(fsp), data, n);
805 fh_set_pos(fsp->fh, 0);
808 #else /* HAVE_PREAD */
811 #endif /* HAVE_PREAD */
816 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
817 size_t n, off_t offset)
821 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
822 START_PROFILE_BYTES(syscall_pwrite, n);
823 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
824 END_PROFILE_BYTES(syscall_pwrite);
826 if (result == -1 && errno == ESPIPE) {
827 /* Maintain the fiction that pipes can be sought on. */
828 result = sys_write(fsp_get_io_fd(fsp), data, n);
831 #else /* HAVE_PWRITE */
834 #endif /* HAVE_PWRITE */
839 struct vfswrap_pread_state {
846 struct vfs_aio_state vfs_aio_state;
847 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
850 static void vfs_pread_do(void *private_data);
851 static void vfs_pread_done(struct tevent_req *subreq);
852 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
854 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
856 struct tevent_context *ev,
857 struct files_struct *fsp,
859 size_t n, off_t offset)
861 struct tevent_req *req, *subreq;
862 struct vfswrap_pread_state *state;
864 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
870 state->fd = fsp_get_io_fd(fsp);
873 state->offset = offset;
875 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
876 state->profile_bytes, n);
877 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
879 subreq = pthreadpool_tevent_job_send(
880 state, ev, handle->conn->sconn->pool,
881 vfs_pread_do, state);
882 if (tevent_req_nomem(subreq, req)) {
883 return tevent_req_post(req, ev);
885 tevent_req_set_callback(subreq, vfs_pread_done, req);
887 talloc_set_destructor(state, vfs_pread_state_destructor);
892 static void vfs_pread_do(void *private_data)
894 struct vfswrap_pread_state *state = talloc_get_type_abort(
895 private_data, struct vfswrap_pread_state);
896 struct timespec start_time;
897 struct timespec end_time;
899 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
901 PROFILE_TIMESTAMP(&start_time);
903 state->ret = sys_pread_full(state->fd,
908 if (state->ret == -1) {
909 state->vfs_aio_state.error = errno;
912 PROFILE_TIMESTAMP(&end_time);
914 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
916 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
919 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
924 static void vfs_pread_done(struct tevent_req *subreq)
926 struct tevent_req *req = tevent_req_callback_data(
927 subreq, struct tevent_req);
928 struct vfswrap_pread_state *state = tevent_req_data(
929 req, struct vfswrap_pread_state);
932 ret = pthreadpool_tevent_job_recv(subreq);
934 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
935 talloc_set_destructor(state, NULL);
938 tevent_req_error(req, ret);
942 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
943 * means the lower level pthreadpool failed to create a new
944 * thread. Fallback to sync processing in that case to allow
945 * some progress for the client.
950 tevent_req_done(req);
953 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
954 struct vfs_aio_state *vfs_aio_state)
956 struct vfswrap_pread_state *state = tevent_req_data(
957 req, struct vfswrap_pread_state);
959 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
963 *vfs_aio_state = state->vfs_aio_state;
967 struct vfswrap_pwrite_state {
974 struct vfs_aio_state vfs_aio_state;
975 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
978 static void vfs_pwrite_do(void *private_data);
979 static void vfs_pwrite_done(struct tevent_req *subreq);
980 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
982 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
984 struct tevent_context *ev,
985 struct files_struct *fsp,
987 size_t n, off_t offset)
989 struct tevent_req *req, *subreq;
990 struct vfswrap_pwrite_state *state;
992 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
998 state->fd = fsp_get_io_fd(fsp);
1001 state->offset = offset;
1003 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1004 state->profile_bytes, n);
1005 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1007 subreq = pthreadpool_tevent_job_send(
1008 state, ev, handle->conn->sconn->pool,
1009 vfs_pwrite_do, state);
1010 if (tevent_req_nomem(subreq, req)) {
1011 return tevent_req_post(req, ev);
1013 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1015 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1020 static void vfs_pwrite_do(void *private_data)
1022 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1023 private_data, struct vfswrap_pwrite_state);
1024 struct timespec start_time;
1025 struct timespec end_time;
1027 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1029 PROFILE_TIMESTAMP(&start_time);
1031 state->ret = sys_pwrite_full(state->fd,
1036 if (state->ret == -1) {
1037 state->vfs_aio_state.error = errno;
1040 PROFILE_TIMESTAMP(&end_time);
1042 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1044 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1047 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1052 static void vfs_pwrite_done(struct tevent_req *subreq)
1054 struct tevent_req *req = tevent_req_callback_data(
1055 subreq, struct tevent_req);
1056 struct vfswrap_pwrite_state *state = tevent_req_data(
1057 req, struct vfswrap_pwrite_state);
1060 ret = pthreadpool_tevent_job_recv(subreq);
1061 TALLOC_FREE(subreq);
1062 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1063 talloc_set_destructor(state, NULL);
1065 if (ret != EAGAIN) {
1066 tevent_req_error(req, ret);
1070 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1071 * means the lower level pthreadpool failed to create a new
1072 * thread. Fallback to sync processing in that case to allow
1073 * some progress for the client.
1075 vfs_pwrite_do(state);
1078 tevent_req_done(req);
1081 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1082 struct vfs_aio_state *vfs_aio_state)
1084 struct vfswrap_pwrite_state *state = tevent_req_data(
1085 req, struct vfswrap_pwrite_state);
1087 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1091 *vfs_aio_state = state->vfs_aio_state;
1095 struct vfswrap_fsync_state {
1099 struct vfs_aio_state vfs_aio_state;
1100 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1103 static void vfs_fsync_do(void *private_data);
1104 static void vfs_fsync_done(struct tevent_req *subreq);
1105 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1107 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1108 TALLOC_CTX *mem_ctx,
1109 struct tevent_context *ev,
1110 struct files_struct *fsp)
1112 struct tevent_req *req, *subreq;
1113 struct vfswrap_fsync_state *state;
1115 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1121 state->fd = fsp_get_io_fd(fsp);
1123 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1124 state->profile_bytes, 0);
1125 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1127 subreq = pthreadpool_tevent_job_send(
1128 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1129 if (tevent_req_nomem(subreq, req)) {
1130 return tevent_req_post(req, ev);
1132 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1134 talloc_set_destructor(state, vfs_fsync_state_destructor);
1139 static void vfs_fsync_do(void *private_data)
1141 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1142 private_data, struct vfswrap_fsync_state);
1143 struct timespec start_time;
1144 struct timespec end_time;
1146 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1148 PROFILE_TIMESTAMP(&start_time);
1151 state->ret = fsync(state->fd);
1152 } while ((state->ret == -1) && (errno == EINTR));
1154 if (state->ret == -1) {
1155 state->vfs_aio_state.error = errno;
1158 PROFILE_TIMESTAMP(&end_time);
1160 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1162 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1165 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1170 static void vfs_fsync_done(struct tevent_req *subreq)
1172 struct tevent_req *req = tevent_req_callback_data(
1173 subreq, struct tevent_req);
1174 struct vfswrap_fsync_state *state = tevent_req_data(
1175 req, struct vfswrap_fsync_state);
1178 ret = pthreadpool_tevent_job_recv(subreq);
1179 TALLOC_FREE(subreq);
1180 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1181 talloc_set_destructor(state, NULL);
1183 if (ret != EAGAIN) {
1184 tevent_req_error(req, ret);
1188 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1189 * means the lower level pthreadpool failed to create a new
1190 * thread. Fallback to sync processing in that case to allow
1191 * some progress for the client.
1193 vfs_fsync_do(state);
1196 tevent_req_done(req);
1199 static int vfswrap_fsync_recv(struct tevent_req *req,
1200 struct vfs_aio_state *vfs_aio_state)
1202 struct vfswrap_fsync_state *state = tevent_req_data(
1203 req, struct vfswrap_fsync_state);
1205 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1209 *vfs_aio_state = state->vfs_aio_state;
1213 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1217 START_PROFILE(syscall_lseek);
1219 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1221 * We want to maintain the fiction that we can seek
1222 * on a fifo for file system purposes. This allows
1223 * people to set up UNIX fifo's that feed data to Windows
1224 * applications. JRA.
1227 if((result == -1) && (errno == ESPIPE)) {
1232 END_PROFILE(syscall_lseek);
1236 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1237 off_t offset, size_t n)
1241 START_PROFILE_BYTES(syscall_sendfile, n);
1242 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1243 END_PROFILE_BYTES(syscall_sendfile);
1247 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1249 files_struct *tofsp,
1255 START_PROFILE_BYTES(syscall_recvfile, n);
1256 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1257 END_PROFILE_BYTES(syscall_recvfile);
1261 static int vfswrap_renameat(vfs_handle_struct *handle,
1262 files_struct *srcfsp,
1263 const struct smb_filename *smb_fname_src,
1264 files_struct *dstfsp,
1265 const struct smb_filename *smb_fname_dst)
1269 START_PROFILE(syscall_renameat);
1271 SMB_ASSERT(!is_named_stream(smb_fname_src));
1272 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1274 result = renameat(fsp_get_pathref_fd(srcfsp),
1275 smb_fname_src->base_name,
1276 fsp_get_pathref_fd(dstfsp),
1277 smb_fname_dst->base_name);
1279 END_PROFILE(syscall_renameat);
1283 static int vfswrap_stat(vfs_handle_struct *handle,
1284 struct smb_filename *smb_fname)
1288 START_PROFILE(syscall_stat);
1290 SMB_ASSERT(!is_named_stream(smb_fname));
1292 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1293 lp_fake_directory_create_times(SNUM(handle->conn)));
1295 END_PROFILE(syscall_stat);
1299 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1303 START_PROFILE(syscall_fstat);
1304 result = sys_fstat(fsp_get_pathref_fd(fsp),
1305 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1306 END_PROFILE(syscall_fstat);
1310 static int vfswrap_lstat(vfs_handle_struct *handle,
1311 struct smb_filename *smb_fname)
1315 START_PROFILE(syscall_lstat);
1317 SMB_ASSERT(!is_named_stream(smb_fname));
1319 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1320 lp_fake_directory_create_times(SNUM(handle->conn)));
1322 END_PROFILE(syscall_lstat);
1326 static int vfswrap_fstatat(
1327 struct vfs_handle_struct *handle,
1328 const struct files_struct *dirfsp,
1329 const struct smb_filename *smb_fname,
1330 SMB_STRUCT_STAT *sbuf,
1335 START_PROFILE(syscall_fstatat);
1337 SMB_ASSERT(!is_named_stream(smb_fname));
1339 result = sys_fstatat(
1340 fsp_get_pathref_fd(dirfsp),
1341 smb_fname->base_name,
1344 lp_fake_directory_create_times(SNUM(handle->conn)));
1346 END_PROFILE(syscall_fstatat);
1350 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1352 enum vfs_translate_direction direction,
1353 TALLOC_CTX *mem_ctx,
1356 return NT_STATUS_NONE_MAPPED;
1360 * Return allocated parent directory and basename of path
1362 * Note: if requesting atname, it is returned as talloc child of the
1363 * parent. Freeing the parent is thus sufficient to free both.
1365 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1366 TALLOC_CTX *mem_ctx,
1367 const struct smb_filename *smb_fname_in,
1368 struct smb_filename **parent_dir_out,
1369 struct smb_filename **atname_out)
1371 struct smb_filename *parent = NULL;
1372 struct smb_filename *name = NULL;
1375 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1376 if (parent == NULL) {
1377 return NT_STATUS_NO_MEMORY;
1379 SET_STAT_INVALID(parent->st);
1381 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1383 TALLOC_FREE(parent->base_name);
1384 parent->base_name = talloc_strdup(parent, ".");
1385 if (parent->base_name == NULL) {
1386 TALLOC_FREE(parent);
1387 return NT_STATUS_NO_MEMORY;
1389 p = smb_fname_in->base_name;
1395 if (atname_out == NULL) {
1396 *parent_dir_out = parent;
1397 return NT_STATUS_OK;
1400 name = synthetic_smb_fname(
1403 smb_fname_in->stream_name,
1406 smb_fname_in->flags);
1408 return NT_STATUS_NO_MEMORY;
1411 *parent_dir_out = parent;
1413 return NT_STATUS_OK;
1417 * Implement the default fsctl operation.
1419 static bool vfswrap_logged_ioctl_message = false;
1421 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1422 struct files_struct *fsp,
1425 uint16_t req_flags, /* Needed for UNICODE ... */
1426 const uint8_t *_in_data,
1428 uint8_t **_out_data,
1429 uint32_t max_out_len,
1432 const char *in_data = (const char *)_in_data;
1433 char **out_data = (char **)_out_data;
1437 * Currently all fsctls operate on the base
1438 * file if given an alternate data stream.
1439 * Revisit this if we implement fsctls later
1440 * that need access to the ADS handle.
1442 fsp = metadata_fsp(fsp);
1445 case FSCTL_SET_SPARSE:
1447 bool set_sparse = true;
1449 if (in_len >= 1 && in_data[0] == 0) {
1453 status = file_set_sparse(handle->conn, fsp, set_sparse);
1455 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1456 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1457 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1458 nt_errstr(status)));
1463 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1465 unsigned char objid[16];
1466 char *return_data = NULL;
1468 /* This should return the object-id on this file.
1469 * I think I'll make this be the inode+dev. JRA.
1472 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1475 *out_len = MIN(max_out_len, 64);
1477 /* Hmmm, will this cause problems if less data asked for? */
1478 return_data = talloc_array(ctx, char, 64);
1479 if (return_data == NULL) {
1480 return NT_STATUS_NO_MEMORY;
1483 /* For backwards compatibility only store the dev/inode. */
1484 push_file_id_16(return_data, &fsp->file_id);
1485 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1486 push_file_id_16(return_data+32, &fsp->file_id);
1487 memset(return_data+48, 0, 16);
1488 *out_data = return_data;
1489 return NT_STATUS_OK;
1492 case FSCTL_GET_REPARSE_POINT:
1494 status = fsctl_get_reparse_point(
1495 fsp, ctx, out_data, max_out_len, out_len);
1499 case FSCTL_SET_REPARSE_POINT:
1501 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1505 case FSCTL_DELETE_REPARSE_POINT:
1507 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1511 case FSCTL_GET_SHADOW_COPY_DATA:
1514 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1515 * and return their volume names. If max_data_count is 16, then it is just
1516 * asking for the number of volumes and length of the combined names.
1518 * pdata is the data allocated by our caller, but that uses
1519 * total_data_count (which is 0 in our case) rather than max_data_count.
1520 * Allocate the correct amount and return the pointer to let
1521 * it be deallocated when we return.
1523 struct shadow_copy_data *shadow_data = NULL;
1524 bool labels = False;
1525 uint32_t labels_data_count = 0;
1527 char *cur_pdata = NULL;
1529 if (max_out_len < 16) {
1530 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1532 return NT_STATUS_INVALID_PARAMETER;
1535 if (max_out_len > 16) {
1539 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1540 if (shadow_data == NULL) {
1541 DBG_ERR("TALLOC_ZERO() failed!\n");
1542 return NT_STATUS_NO_MEMORY;
1546 * Call the VFS routine to actually do the work.
1548 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1549 int log_lev = DBGLVL_ERR;
1551 /* broken module didn't set errno on error */
1552 status = NT_STATUS_UNSUCCESSFUL;
1554 status = map_nt_error_from_unix(errno);
1555 if (NT_STATUS_EQUAL(status,
1556 NT_STATUS_NOT_SUPPORTED)) {
1557 log_lev = DBGLVL_INFO;
1560 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1561 "connectpath %s, failed - %s.\n",
1562 fsp->conn->connectpath,
1563 nt_errstr(status)));
1564 TALLOC_FREE(shadow_data);
1568 labels_data_count = (shadow_data->num_volumes * 2 *
1569 sizeof(SHADOW_COPY_LABEL)) + 2;
1574 *out_len = 12 + labels_data_count;
1577 if (max_out_len < *out_len) {
1578 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1579 max_out_len, *out_len);
1580 TALLOC_FREE(shadow_data);
1581 return NT_STATUS_BUFFER_TOO_SMALL;
1584 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1585 if (cur_pdata == NULL) {
1586 TALLOC_FREE(shadow_data);
1587 return NT_STATUS_NO_MEMORY;
1590 *out_data = cur_pdata;
1592 /* num_volumes 4 bytes */
1593 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1596 /* num_labels 4 bytes */
1597 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1600 /* needed_data_count 4 bytes */
1601 SIVAL(cur_pdata, 8, labels_data_count);
1605 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1606 shadow_data->num_volumes, fsp_str_dbg(fsp));
1607 if (labels && shadow_data->labels) {
1608 for (i=0; i<shadow_data->num_volumes; i++) {
1610 status = srvstr_push(cur_pdata, req_flags,
1611 cur_pdata, shadow_data->labels[i],
1612 2 * sizeof(SHADOW_COPY_LABEL),
1613 STR_UNICODE|STR_TERMINATE, &len);
1614 if (!NT_STATUS_IS_OK(status)) {
1615 TALLOC_FREE(*out_data);
1616 TALLOC_FREE(shadow_data);
1619 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1620 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1624 TALLOC_FREE(shadow_data);
1626 return NT_STATUS_OK;
1629 case FSCTL_FIND_FILES_BY_SID:
1631 /* pretend this succeeded -
1633 * we have to send back a list with all files owned by this SID
1635 * but I have to check that --metze
1639 struct dom_sid_buf buf;
1643 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1647 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1648 return NT_STATUS_INVALID_PARAMETER;
1651 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1653 /* unknown 4 bytes: this is not the length of the sid :-( */
1654 /*unknown = IVAL(pdata,0);*/
1656 ret = sid_parse(_in_data + 4, sid_len, &sid);
1658 return NT_STATUS_INVALID_PARAMETER;
1660 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1661 dom_sid_str_buf(&sid, &buf)));
1663 if (!sid_to_uid(&sid, &uid)) {
1664 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1665 dom_sid_str_buf(&sid, &buf),
1666 (unsigned long)sid_len);
1670 /* we can take a look at the find source :-)
1672 * find ./ -uid $uid -name '*' is what we need here
1675 * and send 4bytes len and then NULL terminated unicode strings
1678 * but I don't know how to deal with the paged results
1679 * (maybe we can hang the result anywhere in the fsp struct)
1681 * but I don't know how to deal with the paged results
1682 * (maybe we can hang the result anywhere in the fsp struct)
1684 * we don't send all files at once
1685 * and at the next we should *not* start from the beginning,
1686 * so we have to cache the result
1691 /* this works for now... */
1692 return NT_STATUS_OK;
1695 case FSCTL_QUERY_ALLOCATED_RANGES:
1697 /* FIXME: This is just a dummy reply, telling that all of the
1698 * file is allocated. MKS cp needs that.
1699 * Adding the real allocated ranges via FIEMAP on Linux
1700 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1701 * this FSCTL correct for sparse files.
1703 uint64_t offset, length;
1704 char *out_data_tmp = NULL;
1707 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1709 return NT_STATUS_INVALID_PARAMETER;
1712 if (max_out_len < 16) {
1713 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1715 return NT_STATUS_INVALID_PARAMETER;
1718 offset = BVAL(in_data,0);
1719 length = BVAL(in_data,8);
1721 if (offset + length < offset) {
1722 /* No 64-bit integer wrap. */
1723 return NT_STATUS_INVALID_PARAMETER;
1726 /* Shouldn't this be SMB_VFS_STAT ... ? */
1727 status = vfs_stat_fsp(fsp);
1728 if (!NT_STATUS_IS_OK(status)) {
1733 out_data_tmp = talloc_array(ctx, char, *out_len);
1734 if (out_data_tmp == NULL) {
1735 DBG_DEBUG("unable to allocate memory for response\n");
1736 return NT_STATUS_NO_MEMORY;
1739 if (offset > fsp->fsp_name->st.st_ex_size ||
1740 fsp->fsp_name->st.st_ex_size == 0 ||
1742 memset(out_data_tmp, 0, *out_len);
1744 uint64_t end = offset + length;
1745 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1746 SBVAL(out_data_tmp, 0, 0);
1747 SBVAL(out_data_tmp, 8, end);
1750 *out_data = out_data_tmp;
1752 return NT_STATUS_OK;
1755 case FSCTL_IS_VOLUME_DIRTY:
1757 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1758 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1760 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1761 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1763 return NT_STATUS_INVALID_PARAMETER;
1768 * Only print once ... unfortunately there could be lots of
1769 * different FSCTLs that are called.
1771 if (!vfswrap_logged_ioctl_message) {
1772 vfswrap_logged_ioctl_message = true;
1773 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1774 __func__, function);
1778 return NT_STATUS_NOT_SUPPORTED;
1781 static bool vfswrap_is_offline(struct connection_struct *conn,
1782 const struct smb_filename *fname);
1784 struct vfswrap_get_dos_attributes_state {
1785 struct vfs_aio_state aio_state;
1786 connection_struct *conn;
1787 TALLOC_CTX *mem_ctx;
1788 struct tevent_context *ev;
1789 files_struct *dir_fsp;
1790 struct smb_filename *smb_fname;
1795 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1797 static struct tevent_req *vfswrap_get_dos_attributes_send(
1798 TALLOC_CTX *mem_ctx,
1799 struct tevent_context *ev,
1800 struct vfs_handle_struct *handle,
1801 files_struct *dir_fsp,
1802 struct smb_filename *smb_fname)
1804 struct tevent_req *req = NULL;
1805 struct tevent_req *subreq = NULL;
1806 struct vfswrap_get_dos_attributes_state *state = NULL;
1808 SMB_ASSERT(!is_named_stream(smb_fname));
1810 req = tevent_req_create(mem_ctx, &state,
1811 struct vfswrap_get_dos_attributes_state);
1816 *state = (struct vfswrap_get_dos_attributes_state) {
1817 .conn = dir_fsp->conn,
1821 .smb_fname = smb_fname,
1824 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1825 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1826 "\"store dos attributes\" is disabled\n",
1827 dir_fsp->conn->connectpath);
1828 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1829 return tevent_req_post(req, ev);
1832 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1836 SAMBA_XATTR_DOS_ATTRIB,
1838 if (tevent_req_nomem(subreq, req)) {
1839 return tevent_req_post(req, ev);
1841 tevent_req_set_callback(subreq,
1842 vfswrap_get_dos_attributes_getxattr_done,
1848 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1850 struct tevent_req *req =
1851 tevent_req_callback_data(subreq,
1853 struct vfswrap_get_dos_attributes_state *state =
1854 tevent_req_data(req,
1855 struct vfswrap_get_dos_attributes_state);
1857 DATA_BLOB blob = {0};
1859 char *tofree = NULL;
1860 char pathbuf[PATH_MAX+1];
1862 struct smb_filename smb_fname;
1866 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1870 TALLOC_FREE(subreq);
1871 if (xattr_size == -1) {
1872 status = map_nt_error_from_unix(state->aio_state.error);
1874 if (state->as_root) {
1875 tevent_req_nterror(req, status);
1878 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1879 tevent_req_nterror(req, status);
1883 state->as_root = true;
1886 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1890 SAMBA_XATTR_DOS_ATTRIB,
1893 if (tevent_req_nomem(subreq, req)) {
1896 tevent_req_set_callback(subreq,
1897 vfswrap_get_dos_attributes_getxattr_done,
1902 blob.length = xattr_size;
1904 status = parse_dos_attribute_blob(state->smb_fname,
1907 if (!NT_STATUS_IS_OK(status)) {
1908 tevent_req_nterror(req, status);
1912 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1913 state->smb_fname->base_name,
1918 if (pathlen == -1) {
1919 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1923 smb_fname = (struct smb_filename) {
1925 .st = state->smb_fname->st,
1926 .flags = state->smb_fname->flags,
1927 .twrp = state->smb_fname->twrp,
1930 offline = vfswrap_is_offline(state->conn, &smb_fname);
1932 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1934 TALLOC_FREE(tofree);
1936 tevent_req_done(req);
1940 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1941 struct vfs_aio_state *aio_state,
1944 struct vfswrap_get_dos_attributes_state *state =
1945 tevent_req_data(req,
1946 struct vfswrap_get_dos_attributes_state);
1949 if (tevent_req_is_nterror(req, &status)) {
1950 tevent_req_received(req);
1954 *aio_state = state->aio_state;
1955 *dosmode = state->dosmode;
1956 tevent_req_received(req);
1957 return NT_STATUS_OK;
1960 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1961 struct files_struct *fsp,
1966 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1968 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1970 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1973 return fget_ea_dos_attribute(fsp, dosmode);
1976 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1977 struct files_struct *fsp,
1980 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1982 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1985 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1987 struct vfswrap_offload_read_state {
1991 static struct tevent_req *vfswrap_offload_read_send(
1992 TALLOC_CTX *mem_ctx,
1993 struct tevent_context *ev,
1994 struct vfs_handle_struct *handle,
1995 struct files_struct *fsp,
2001 struct tevent_req *req = NULL;
2002 struct vfswrap_offload_read_state *state = NULL;
2005 req = tevent_req_create(mem_ctx, &state,
2006 struct vfswrap_offload_read_state);
2011 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2012 &vfswrap_offload_ctx);
2013 if (tevent_req_nterror(req, status)) {
2014 return tevent_req_post(req, ev);
2017 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2018 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2019 return tevent_req_post(req, ev);
2022 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2024 if (tevent_req_nterror(req, status)) {
2025 return tevent_req_post(req, ev);
2028 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2030 if (tevent_req_nterror(req, status)) {
2031 return tevent_req_post(req, ev);
2034 tevent_req_done(req);
2035 return tevent_req_post(req, ev);
2038 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2039 struct vfs_handle_struct *handle,
2040 TALLOC_CTX *mem_ctx,
2045 struct vfswrap_offload_read_state *state = tevent_req_data(
2046 req, struct vfswrap_offload_read_state);
2049 if (tevent_req_is_nterror(req, &status)) {
2050 tevent_req_received(req);
2056 token->length = state->token.length;
2057 token->data = talloc_move(mem_ctx, &state->token.data);
2059 tevent_req_received(req);
2060 return NT_STATUS_OK;
2063 struct vfswrap_offload_write_state {
2065 bool read_lck_locked;
2066 bool write_lck_locked;
2068 struct tevent_context *src_ev;
2069 struct files_struct *src_fsp;
2071 struct tevent_context *dst_ev;
2072 struct files_struct *dst_fsp;
2077 size_t next_io_size;
2080 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2081 enum tevent_req_state req_state)
2083 struct vfswrap_offload_write_state *state = tevent_req_data(
2084 req, struct vfswrap_offload_write_state);
2087 if (state->dst_fsp == NULL) {
2091 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2093 state->dst_fsp = NULL;
2096 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2097 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2099 static struct tevent_req *vfswrap_offload_write_send(
2100 struct vfs_handle_struct *handle,
2101 TALLOC_CTX *mem_ctx,
2102 struct tevent_context *ev,
2105 off_t transfer_offset,
2106 struct files_struct *dest_fsp,
2110 struct tevent_req *req;
2111 struct vfswrap_offload_write_state *state = NULL;
2112 /* off_t is signed! */
2113 off_t max_offset = INT64_MAX - to_copy;
2114 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2115 files_struct *src_fsp = NULL;
2119 req = tevent_req_create(mem_ctx, &state,
2120 struct vfswrap_offload_write_state);
2125 *state = (struct vfswrap_offload_write_state) {
2127 .src_off = transfer_offset,
2129 .dst_fsp = dest_fsp,
2130 .dst_off = dest_off,
2132 .remaining = to_copy,
2135 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2138 case FSCTL_SRV_COPYCHUNK:
2139 case FSCTL_SRV_COPYCHUNK_WRITE:
2142 case FSCTL_OFFLOAD_WRITE:
2143 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2144 return tevent_req_post(req, ev);
2146 case FSCTL_DUP_EXTENTS_TO_FILE:
2147 DBG_DEBUG("COW clones not supported by vfs_default\n");
2148 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2149 return tevent_req_post(req, ev);
2152 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2153 return tevent_req_post(req, ev);
2157 * From here on we assume a copy-chunk fsctl
2161 tevent_req_done(req);
2162 return tevent_req_post(req, ev);
2165 if (state->src_off > max_offset) {
2167 * Protect integer checks below.
2169 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2170 return tevent_req_post(req, ev);
2172 if (state->src_off < 0) {
2174 * Protect integer checks below.
2176 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2177 return tevent_req_post(req, ev);
2179 if (state->dst_off > max_offset) {
2181 * Protect integer checks below.
2183 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2184 return tevent_req_post(req, ev);
2186 if (state->dst_off < 0) {
2188 * Protect integer checks below.
2190 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2191 return tevent_req_post(req, ev);
2194 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2196 if (tevent_req_nterror(req, status)) {
2197 return tevent_req_post(req, ev);
2200 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2202 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2203 if (!NT_STATUS_IS_OK(status)) {
2204 tevent_req_nterror(req, status);
2205 return tevent_req_post(req, ev);
2208 ok = change_to_user_and_service_by_fsp(src_fsp);
2210 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2211 return tevent_req_post(req, ev);
2214 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2215 state->src_fsp = src_fsp;
2217 status = vfs_stat_fsp(src_fsp);
2218 if (tevent_req_nterror(req, status)) {
2219 return tevent_req_post(req, ev);
2222 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2224 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2225 * If the SourceOffset or SourceOffset + Length extends beyond
2226 * the end of file, the server SHOULD<240> treat this as a
2227 * STATUS_END_OF_FILE error.
2229 * <240> Section 3.3.5.15.6: Windows servers will return
2230 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2232 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2233 return tevent_req_post(req, ev);
2236 status = vfswrap_offload_copy_file_range(req);
2237 if (NT_STATUS_IS_OK(status)) {
2238 tevent_req_done(req);
2239 return tevent_req_post(req, ev);
2241 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2242 tevent_req_nterror(req, status);
2243 return tevent_req_post(req, ev);
2246 state->buf = talloc_array(state, uint8_t, num);
2247 if (tevent_req_nomem(state->buf, req)) {
2248 return tevent_req_post(req, ev);
2251 status = vfswrap_offload_write_loop(req);
2252 if (!NT_STATUS_IS_OK(status)) {
2253 tevent_req_nterror(req, status);
2254 return tevent_req_post(req, ev);
2260 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2262 struct vfswrap_offload_write_state *state = tevent_req_data(
2263 req, struct vfswrap_offload_write_state);
2264 struct lock_struct lck;
2269 static bool try_copy_file_range = true;
2271 if (!try_copy_file_range) {
2272 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2275 same_file = file_id_equal(&state->src_fsp->file_id,
2276 &state->dst_fsp->file_id);
2278 sys_io_ranges_overlap(state->remaining,
2283 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2286 if (fsp_is_alternate_stream(state->src_fsp) ||
2287 fsp_is_alternate_stream(state->dst_fsp))
2289 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2292 init_strict_lock_struct(state->src_fsp,
2293 state->src_fsp->op->global->open_persistent_id,
2297 lp_posix_cifsu_locktype(state->src_fsp),
2300 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2304 return NT_STATUS_FILE_LOCK_CONFLICT;
2307 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2309 return NT_STATUS_INTERNAL_ERROR;
2312 init_strict_lock_struct(state->dst_fsp,
2313 state->dst_fsp->op->global->open_persistent_id,
2317 lp_posix_cifsu_locktype(state->dst_fsp),
2320 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2324 return NT_STATUS_FILE_LOCK_CONFLICT;
2327 while (state->remaining > 0) {
2328 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2330 fsp_get_io_fd(state->dst_fsp),
2334 if (nwritten == -1) {
2335 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2336 "n [%jd] failed: %s\n",
2337 fsp_str_dbg(state->src_fsp),
2338 (intmax_t)state->src_off,
2339 fsp_str_dbg(state->dst_fsp),
2340 (intmax_t)state->dst_off,
2341 (intmax_t)state->remaining,
2346 try_copy_file_range = false;
2347 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2350 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2353 status = map_nt_error_from_unix(errno);
2354 if (NT_STATUS_EQUAL(
2356 NT_STATUS_MORE_PROCESSING_REQUIRED))
2358 /* Avoid triggering the fallback */
2359 status = NT_STATUS_INTERNAL_ERROR;
2366 if (state->remaining < nwritten) {
2367 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2368 "n [%jd] remaining [%jd]\n",
2369 fsp_str_dbg(state->src_fsp),
2370 fsp_str_dbg(state->dst_fsp),
2372 (intmax_t)state->remaining);
2373 return NT_STATUS_INTERNAL_ERROR;
2376 if (nwritten == 0) {
2379 state->copied += nwritten;
2380 state->remaining -= nwritten;
2384 * Tell the req cleanup function there's no need to call
2385 * change_to_user_and_service_by_fsp() on the dst handle.
2387 state->dst_fsp = NULL;
2388 return NT_STATUS_OK;
2391 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2393 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2395 struct vfswrap_offload_write_state *state = tevent_req_data(
2396 req, struct vfswrap_offload_write_state);
2397 struct tevent_req *subreq = NULL;
2398 struct lock_struct read_lck;
2402 * This is called under the context of state->src_fsp.
2405 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2407 init_strict_lock_struct(state->src_fsp,
2408 state->src_fsp->op->global->open_persistent_id,
2410 state->next_io_size,
2412 lp_posix_cifsu_locktype(state->src_fsp),
2415 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2419 return NT_STATUS_FILE_LOCK_CONFLICT;
2422 subreq = SMB_VFS_PREAD_SEND(state,
2426 state->next_io_size,
2428 if (subreq == NULL) {
2429 return NT_STATUS_NO_MEMORY;
2431 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2433 return NT_STATUS_OK;
2436 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2438 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2440 struct tevent_req *req = tevent_req_callback_data(
2441 subreq, struct tevent_req);
2442 struct vfswrap_offload_write_state *state = tevent_req_data(
2443 req, struct vfswrap_offload_write_state);
2444 struct vfs_aio_state aio_state;
2445 struct lock_struct write_lck;
2449 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2450 TALLOC_FREE(subreq);
2452 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2453 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2456 if (nread != state->next_io_size) {
2457 DBG_ERR("Short read, only %zd of %zu\n",
2458 nread, state->next_io_size);
2459 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2463 state->src_off += nread;
2465 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2467 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2471 init_strict_lock_struct(state->dst_fsp,
2472 state->dst_fsp->op->global->open_persistent_id,
2474 state->next_io_size,
2476 lp_posix_cifsu_locktype(state->dst_fsp),
2479 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2483 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2487 subreq = SMB_VFS_PWRITE_SEND(state,
2491 state->next_io_size,
2493 if (subreq == NULL) {
2494 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2497 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2500 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2502 struct tevent_req *req = tevent_req_callback_data(
2503 subreq, struct tevent_req);
2504 struct vfswrap_offload_write_state *state = tevent_req_data(
2505 req, struct vfswrap_offload_write_state);
2506 struct vfs_aio_state aio_state;
2511 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2512 TALLOC_FREE(subreq);
2513 if (nwritten == -1) {
2514 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2515 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2518 if (nwritten != state->next_io_size) {
2519 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2520 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2524 state->dst_off += nwritten;
2526 if (state->remaining < nwritten) {
2527 /* Paranoia check */
2528 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2531 state->copied += nwritten;
2532 state->remaining -= nwritten;
2533 if (state->remaining == 0) {
2534 tevent_req_done(req);
2538 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2540 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2544 status = vfswrap_offload_write_loop(req);
2545 if (!NT_STATUS_IS_OK(status)) {
2546 tevent_req_nterror(req, status);
2553 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2554 struct tevent_req *req,
2557 struct vfswrap_offload_write_state *state = tevent_req_data(
2558 req, struct vfswrap_offload_write_state);
2561 if (tevent_req_is_nterror(req, &status)) {
2562 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2564 tevent_req_received(req);
2568 *copied = state->copied;
2569 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2570 tevent_req_received(req);
2572 return NT_STATUS_OK;
2575 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2576 TALLOC_CTX *mem_ctx,
2577 struct files_struct *fsp,
2578 uint16_t *_compression_fmt)
2580 return NT_STATUS_INVALID_DEVICE_REQUEST;
2583 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2584 TALLOC_CTX *mem_ctx,
2585 struct files_struct *fsp,
2586 uint16_t compression_fmt)
2588 return NT_STATUS_INVALID_DEVICE_REQUEST;
2591 /********************************************************************
2592 Given a stat buffer return the allocated size on disk, taking into
2593 account sparse files.
2594 ********************************************************************/
2595 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2596 struct files_struct *fsp,
2597 const SMB_STRUCT_STAT *sbuf)
2601 START_PROFILE(syscall_get_alloc_size);
2603 if(S_ISDIR(sbuf->st_ex_mode)) {
2608 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2609 /* The type of st_blocksize is blkcnt_t which *MUST* be
2610 signed (according to POSIX) and can be less than 64-bits.
2611 Ensure when we're converting to 64 bits wide we don't
2613 #if defined(SIZEOF_BLKCNT_T_8)
2614 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2615 #elif defined(SIZEOF_BLKCNT_T_4)
2617 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2618 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2621 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2625 * Some file systems do not allocate a block for very
2626 * small files. But for non-empty file should report a
2630 uint64_t filesize = get_file_size_stat(sbuf);
2632 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2636 result = get_file_size_stat(sbuf);
2639 if (fsp && fsp->initial_allocation_size)
2640 result = MAX(result,fsp->initial_allocation_size);
2642 result = smb_roundup(handle->conn, result);
2645 END_PROFILE(syscall_get_alloc_size);
2649 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2650 struct files_struct *dirfsp,
2651 const struct smb_filename *smb_fname,
2656 START_PROFILE(syscall_unlinkat);
2658 SMB_ASSERT(!is_named_stream(smb_fname));
2660 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2661 smb_fname->base_name,
2664 END_PROFILE(syscall_unlinkat);
2668 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2672 START_PROFILE(syscall_fchmod);
2674 if (!fsp->fsp_flags.is_pathref) {
2675 result = fchmod(fsp_get_io_fd(fsp), mode);
2676 END_PROFILE(syscall_fchmod);
2680 if (fsp->fsp_flags.have_proc_fds) {
2681 int fd = fsp_get_pathref_fd(fsp);
2682 struct sys_proc_fd_path_buf buf;
2684 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2686 END_PROFILE(syscall_fchmod);
2691 * This is no longer a handle based call.
2693 result = chmod(fsp->fsp_name->base_name, mode);
2695 END_PROFILE(syscall_fchmod);
2699 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2704 START_PROFILE(syscall_fchown);
2705 if (!fsp->fsp_flags.is_pathref) {
2706 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2707 END_PROFILE(syscall_fchown);
2711 if (fsp->fsp_flags.have_proc_fds) {
2712 int fd = fsp_get_pathref_fd(fsp);
2713 struct sys_proc_fd_path_buf buf;
2715 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2717 END_PROFILE(syscall_fchown);
2722 * This is no longer a handle based call.
2724 result = chown(fsp->fsp_name->base_name, uid, gid);
2725 END_PROFILE(syscall_fchown);
2733 static int vfswrap_lchown(vfs_handle_struct *handle,
2734 const struct smb_filename *smb_fname,
2740 START_PROFILE(syscall_lchown);
2741 result = lchown(smb_fname->base_name, uid, gid);
2742 END_PROFILE(syscall_lchown);
2746 static int vfswrap_chdir(vfs_handle_struct *handle,
2747 const struct smb_filename *smb_fname)
2751 START_PROFILE(syscall_chdir);
2752 result = chdir(smb_fname->base_name);
2753 END_PROFILE(syscall_chdir);
2757 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2761 struct smb_filename *smb_fname = NULL;
2763 START_PROFILE(syscall_getwd);
2764 result = sys_getwd();
2765 END_PROFILE(syscall_getwd);
2767 if (result == NULL) {
2770 smb_fname = synthetic_smb_fname(ctx,
2777 * sys_getwd() *always* returns malloced memory.
2778 * We must free here to avoid leaks:
2779 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2785 /*********************************************************************
2786 nsec timestamp resolution call. Convert down to whatever the underlying
2787 system will support.
2788 **********************************************************************/
2790 static int vfswrap_fntimes(vfs_handle_struct *handle,
2792 struct smb_file_time *ft)
2795 struct timespec ts[2];
2796 struct timespec *times = NULL;
2798 START_PROFILE(syscall_fntimes);
2800 if (fsp_is_alternate_stream(fsp)) {
2806 if (is_omit_timespec(&ft->atime)) {
2807 ft->atime = fsp->fsp_name->st.st_ex_atime;
2810 if (is_omit_timespec(&ft->mtime)) {
2811 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2814 if (!is_omit_timespec(&ft->create_time)) {
2815 set_create_timespec_ea(fsp,
2819 if ((timespec_compare(&ft->atime,
2820 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2821 (timespec_compare(&ft->mtime,
2822 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2834 if (!fsp->fsp_flags.is_pathref) {
2835 result = futimens(fsp_get_io_fd(fsp), times);
2839 if (fsp->fsp_flags.have_proc_fds) {
2840 int fd = fsp_get_pathref_fd(fsp);
2841 struct sys_proc_fd_path_buf buf;
2843 result = utimensat(AT_FDCWD,
2844 sys_proc_fd_path(fd, &buf),
2852 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2853 * path translation mechanism. Fallback to path based call.
2855 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2858 END_PROFILE(syscall_fntimes);
2864 /*********************************************************************
2865 A version of ftruncate that will write the space on disk if strict
2867 **********************************************************************/
2869 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2871 off_t space_to_write;
2872 uint64_t space_avail;
2873 uint64_t bsize,dfree,dsize;
2876 SMB_STRUCT_STAT *pst;
2879 ok = vfs_valid_pwrite_range(len, 0);
2885 status = vfs_stat_fsp(fsp);
2886 if (!NT_STATUS_IS_OK(status)) {
2889 pst = &fsp->fsp_name->st;
2892 if (S_ISFIFO(pst->st_ex_mode))
2896 if (pst->st_ex_size == len)
2899 /* Shrink - just ftruncate. */
2900 if (pst->st_ex_size > len)
2901 return ftruncate(fsp_get_io_fd(fsp), len);
2903 space_to_write = len - pst->st_ex_size;
2905 /* for allocation try fallocate first. This can fail on some
2906 platforms e.g. when the filesystem doesn't support it and no
2907 emulation is being done by the libc (like on AIX with JFS1). In that
2908 case we do our own emulation. fallocate implementations can
2909 return ENOTSUP or EINVAL in cases like that. */
2910 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2911 if (ret == -1 && errno == ENOSPC) {
2917 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2918 "error %d. Falling back to slow manual allocation\n", errno);
2920 /* available disk space is enough or not? */
2922 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2923 /* space_avail is 1k blocks */
2924 if (space_avail == (uint64_t)-1 ||
2925 ((uint64_t)space_to_write/1024 > space_avail) ) {
2930 /* Write out the real space on disk. */
2931 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2939 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2942 SMB_STRUCT_STAT *pst;
2946 START_PROFILE(syscall_ftruncate);
2948 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2949 result = strict_allocate_ftruncate(handle, fsp, len);
2950 END_PROFILE(syscall_ftruncate);
2954 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2955 ftruncate if the system supports it. Then I discovered that
2956 you can have some filesystems that support ftruncate
2957 expansion and some that don't! On Linux fat can't do
2958 ftruncate extend but ext2 can. */
2960 result = ftruncate(fsp_get_io_fd(fsp), len);
2962 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2963 extend a file with ftruncate. Provide alternate implementation
2966 /* Do an fstat to see if the file is longer than the requested
2967 size in which case the ftruncate above should have
2968 succeeded or shorter, in which case seek to len - 1 and
2969 write 1 byte of zero */
2970 status = vfs_stat_fsp(fsp);
2971 if (!NT_STATUS_IS_OK(status)) {
2975 /* We need to update the files_struct after successful ftruncate */
2980 pst = &fsp->fsp_name->st;
2983 if (S_ISFIFO(pst->st_ex_mode)) {
2989 if (pst->st_ex_size == len) {
2994 if (pst->st_ex_size > len) {
2995 /* the ftruncate should have worked */
2999 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3007 END_PROFILE(syscall_ftruncate);
3011 static int vfswrap_fallocate(vfs_handle_struct *handle,
3019 START_PROFILE(syscall_fallocate);
3021 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3023 * posix_fallocate returns 0 on success, errno on error
3024 * and doesn't set errno. Make it behave like fallocate()
3025 * which returns -1, and sets errno on failure.
3032 /* sys_fallocate handles filtering of unsupported mode flags */
3033 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3035 END_PROFILE(syscall_fallocate);
3039 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3043 START_PROFILE(syscall_fcntl_lock);
3045 if (fsp->fsp_flags.use_ofd_locks) {
3046 op = map_process_lock_to_ofd_lock(op);
3049 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3050 END_PROFILE(syscall_fcntl_lock);
3054 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3056 uint32_t share_access,
3057 uint32_t access_mask)
3063 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3067 va_list dup_cmd_arg;
3071 START_PROFILE(syscall_fcntl);
3073 va_copy(dup_cmd_arg, cmd_arg);
3079 #if defined(HAVE_OFD_LOCKS)
3084 #if defined(HAVE_F_OWNER_EX)
3088 #if defined(HAVE_RW_HINTS)
3091 case F_GET_FILE_RW_HINT:
3092 case F_SET_FILE_RW_HINT:
3094 argp = va_arg(dup_cmd_arg, void *);
3095 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3098 val = va_arg(dup_cmd_arg, int);
3099 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3102 va_end(dup_cmd_arg);
3104 END_PROFILE(syscall_fcntl);
3108 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3113 START_PROFILE(syscall_fcntl_getlock);
3115 if (fsp->fsp_flags.use_ofd_locks) {
3116 op = map_process_lock_to_ofd_lock(op);
3119 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3120 END_PROFILE(syscall_fcntl_getlock);
3124 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3129 START_PROFILE(syscall_linux_setlease);
3131 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3133 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3134 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3138 END_PROFILE(syscall_linux_setlease);
3142 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3143 const struct smb_filename *link_target,
3144 struct files_struct *dirfsp,
3145 const struct smb_filename *new_smb_fname)
3149 START_PROFILE(syscall_symlinkat);
3151 SMB_ASSERT(!is_named_stream(new_smb_fname));
3153 result = symlinkat(link_target->base_name,
3154 fsp_get_pathref_fd(dirfsp),
3155 new_smb_fname->base_name);
3156 END_PROFILE(syscall_symlinkat);
3160 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3161 const struct files_struct *dirfsp,
3162 const struct smb_filename *smb_fname,
3168 START_PROFILE(syscall_readlinkat);
3170 SMB_ASSERT(!is_named_stream(smb_fname));
3172 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3173 smb_fname->base_name,
3177 END_PROFILE(syscall_readlinkat);
3181 static int vfswrap_linkat(vfs_handle_struct *handle,
3182 files_struct *srcfsp,
3183 const struct smb_filename *old_smb_fname,
3184 files_struct *dstfsp,
3185 const struct smb_filename *new_smb_fname,
3190 START_PROFILE(syscall_linkat);
3192 SMB_ASSERT(!is_named_stream(old_smb_fname));
3193 SMB_ASSERT(!is_named_stream(new_smb_fname));
3195 result = linkat(fsp_get_pathref_fd(srcfsp),
3196 old_smb_fname->base_name,
3197 fsp_get_pathref_fd(dstfsp),
3198 new_smb_fname->base_name,
3201 END_PROFILE(syscall_linkat);
3205 static int vfswrap_mknodat(vfs_handle_struct *handle,
3206 files_struct *dirfsp,
3207 const struct smb_filename *smb_fname,
3213 START_PROFILE(syscall_mknodat);
3215 SMB_ASSERT(!is_named_stream(smb_fname));
3217 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3218 smb_fname->base_name,
3222 END_PROFILE(syscall_mknodat);
3226 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3228 const struct smb_filename *smb_fname)
3231 struct smb_filename *result_fname = NULL;
3233 START_PROFILE(syscall_realpath);
3234 result = sys_realpath(smb_fname->base_name);
3235 END_PROFILE(syscall_realpath);
3237 result_fname = synthetic_smb_fname(ctx,
3245 return result_fname;
3248 static int vfswrap_fchflags(vfs_handle_struct *handle,
3249 struct files_struct *fsp,
3252 #ifdef HAVE_FCHFLAGS
3253 int fd = fsp_get_pathref_fd(fsp);
3255 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3257 if (!fsp->fsp_flags.is_pathref) {
3258 return fchflags(fd, flags);
3261 if (fsp->fsp_flags.have_proc_fds) {
3262 struct sys_proc_fd_path_buf buf;
3264 return chflags(sys_proc_fd_path(fd, &buf), flags);
3268 * This is no longer a handle based call.
3270 return chflags(fsp->fsp_name->base_name, flags);
3277 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3278 const SMB_STRUCT_STAT *sbuf)
3282 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3286 key.devid = sbuf->st_ex_dev;
3287 key.inode = sbuf->st_ex_ino;
3288 /* key.extid is unused by default. */
3293 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3294 const SMB_STRUCT_STAT *psbuf)
3298 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3299 return (uint64_t)psbuf->st_ex_ino;
3303 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3306 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3311 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3312 struct files_struct *fsp,
3313 TALLOC_CTX *mem_ctx,
3314 unsigned int *pnum_streams,
3315 struct stream_struct **pstreams)
3317 struct stream_struct *tmp_streams = NULL;
3318 unsigned int num_streams = *pnum_streams;
3319 struct stream_struct *streams = *pstreams;
3322 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3324 if (fsp->fsp_flags.is_directory) {
3326 * No default streams on directories
3330 status = vfs_stat_fsp(fsp);
3331 if (!NT_STATUS_IS_OK(status)) {
3335 if (num_streams + 1 < 1) {
3337 return NT_STATUS_INVALID_PARAMETER;
3340 tmp_streams = talloc_realloc(mem_ctx,
3342 struct stream_struct,
3344 if (tmp_streams == NULL) {
3345 return NT_STATUS_NO_MEMORY;
3347 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3348 if (tmp_streams[num_streams].name == NULL) {
3349 return NT_STATUS_NO_MEMORY;
3351 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3352 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3355 &fsp->fsp_name->st);
3358 *pnum_streams = num_streams;
3359 *pstreams = tmp_streams;
3361 return NT_STATUS_OK;
3364 static NTSTATUS vfswrap_get_real_filename_at(
3365 struct vfs_handle_struct *handle,
3366 struct files_struct *dirfsp,
3368 TALLOC_CTX *mem_ctx,
3372 * Don't fall back to get_real_filename so callers can differentiate
3373 * between a full directory scan and an actual case-insensitive stat.
3375 return NT_STATUS_NOT_SUPPORTED;
3378 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3379 const struct files_struct *dirfsp,
3380 const struct smb_filename *smb_fname)
3382 return handle->conn->connectpath;
3385 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3386 struct byte_range_lock *br_lck,
3387 struct lock_struct *plock)
3389 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3391 /* Note: blr is not used in the default implementation. */
3392 return brl_lock_windows_default(br_lck, plock);
3395 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3396 struct byte_range_lock *br_lck,
3397 const struct lock_struct *plock)
3399 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3401 return brl_unlock_windows_default(br_lck, plock);
3404 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3406 struct lock_struct *plock)
3408 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3409 plock->lock_type == WRITE_LOCK);
3411 return strict_lock_check_default(fsp, plock);
3414 /* NT ACL operations. */
3416 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3418 uint32_t security_info,
3419 TALLOC_CTX *mem_ctx,
3420 struct security_descriptor **ppdesc)
3424 START_PROFILE(fget_nt_acl);
3426 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3428 result = posix_fget_nt_acl(fsp, security_info,
3430 END_PROFILE(fget_nt_acl);
3434 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3438 START_PROFILE(fset_nt_acl);
3440 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3442 result = set_nt_acl(fsp, security_info_sent, psd);
3443 END_PROFILE(fset_nt_acl);
3447 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3448 struct smb_filename *file,
3449 struct security_acl *sacl,
3450 uint32_t access_requested,
3451 uint32_t access_denied)
3453 return NT_STATUS_OK; /* Nothing to do here ... */
3456 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3458 SMB_ACL_TYPE_T type,
3459 TALLOC_CTX *mem_ctx)
3461 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3463 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3466 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3468 SMB_ACL_TYPE_T type,
3471 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3473 return sys_acl_set_fd(handle, fsp, type, theacl);
3476 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3479 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3481 return sys_acl_delete_def_fd(handle, fsp);
3484 /****************************************************************
3485 Extended attribute operations.
3486 *****************************************************************/
3488 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3489 struct files_struct *fsp,
3494 int fd = fsp_get_pathref_fd(fsp);
3496 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3498 if (!fsp->fsp_flags.is_pathref) {
3499 return fgetxattr(fd, name, value, size);
3502 if (fsp->fsp_flags.have_proc_fds) {
3503 struct sys_proc_fd_path_buf buf;
3505 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3509 * This is no longer a handle based call.
3511 return getxattr(fsp->fsp_name->base_name, name, value, size);
3514 struct vfswrap_getxattrat_state {
3515 struct tevent_context *ev;
3516 struct vfs_handle_struct *handle;
3517 files_struct *dir_fsp;
3518 const struct smb_filename *smb_fname;
3521 * The following variables are talloced off "state" which is protected
3522 * by a destructor and thus are guaranteed to be safe to be used in the
3523 * job function in the worker thread.
3526 const char *xattr_name;
3527 uint8_t *xattr_value;
3528 struct security_unix_token *token;
3531 struct vfs_aio_state vfs_aio_state;
3532 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3535 static int vfswrap_getxattrat_state_destructor(
3536 struct vfswrap_getxattrat_state *state)
3541 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3542 static void vfswrap_getxattrat_do_async(void *private_data);
3543 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3545 static struct tevent_req *vfswrap_getxattrat_send(
3546 TALLOC_CTX *mem_ctx,
3547 struct tevent_context *ev,
3548 struct vfs_handle_struct *handle,
3549 files_struct *dir_fsp,
3550 const struct smb_filename *smb_fname,
3551 const char *xattr_name,
3554 struct tevent_req *req = NULL;
3555 struct tevent_req *subreq = NULL;
3556 struct vfswrap_getxattrat_state *state = NULL;
3557 size_t max_threads = 0;
3558 bool have_per_thread_cwd = false;
3559 bool have_per_thread_creds = false;
3560 bool do_async = false;
3562 SMB_ASSERT(!is_named_stream(smb_fname));
3564 req = tevent_req_create(mem_ctx, &state,
3565 struct vfswrap_getxattrat_state);
3569 *state = (struct vfswrap_getxattrat_state) {
3573 .smb_fname = smb_fname,
3576 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3577 if (max_threads >= 1) {
3579 * We need a non sync threadpool!
3581 have_per_thread_cwd = per_thread_cwd_supported();
3583 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3584 have_per_thread_creds = true;
3586 if (have_per_thread_cwd && have_per_thread_creds) {
3590 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3591 state->profile_bytes, 0);
3593 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3594 DBG_ERR("Need a valid directory fd\n");
3595 tevent_req_error(req, EINVAL);
3596 return tevent_req_post(req, ev);
3599 if (alloc_hint > 0) {
3600 state->xattr_value = talloc_zero_array(state,
3603 if (tevent_req_nomem(state->xattr_value, req)) {
3604 return tevent_req_post(req, ev);
3609 vfswrap_getxattrat_do_sync(req);
3610 return tevent_req_post(req, ev);
3614 * Now allocate all parameters from a memory context that won't go away
3615 * no matter what. These parameters will get used in threads and we
3616 * can't reliably cancel threads, so all buffers passed to the threads
3617 * must not be freed before all referencing threads terminate.
3620 state->name = talloc_strdup(state, smb_fname->base_name);
3621 if (tevent_req_nomem(state->name, req)) {
3622 return tevent_req_post(req, ev);
3625 state->xattr_name = talloc_strdup(state, xattr_name);
3626 if (tevent_req_nomem(state->xattr_name, req)) {
3627 return tevent_req_post(req, ev);
3631 * This is a hot codepath so at first glance one might think we should
3632 * somehow optimize away the token allocation and do a
3633 * talloc_reference() or similar black magic instead. But due to the
3634 * talloc_stackframe pool per SMB2 request this should be a simple copy
3635 * without a malloc in most cases.
3637 if (geteuid() == sec_initial_uid()) {
3638 state->token = root_unix_token(state);
3640 state->token = copy_unix_token(
3642 dir_fsp->conn->session_info->unix_token);
3644 if (tevent_req_nomem(state->token, req)) {
3645 return tevent_req_post(req, ev);
3648 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3650 subreq = pthreadpool_tevent_job_send(
3653 dir_fsp->conn->sconn->pool,
3654 vfswrap_getxattrat_do_async,
3656 if (tevent_req_nomem(subreq, req)) {
3657 return tevent_req_post(req, ev);
3659 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3661 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3666 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3668 struct vfswrap_getxattrat_state *state = tevent_req_data(
3669 req, struct vfswrap_getxattrat_state);
3671 state->xattr_size = vfswrap_fgetxattr(state->handle,
3672 state->smb_fname->fsp,
3675 talloc_array_length(state->xattr_value));
3676 if (state->xattr_size == -1) {
3677 tevent_req_error(req, errno);
3681 tevent_req_done(req);
3685 static void vfswrap_getxattrat_do_async(void *private_data)
3687 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3688 private_data, struct vfswrap_getxattrat_state);
3689 struct timespec start_time;
3690 struct timespec end_time;
3693 PROFILE_TIMESTAMP(&start_time);
3694 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3697 * Here we simulate a getxattrat()
3698 * call using fchdir();getxattr()
3701 per_thread_cwd_activate();
3703 /* Become the correct credential on this thread. */
3704 ret = set_thread_credentials(state->token->uid,
3706 (size_t)state->token->ngroups,
3707 state->token->groups);
3709 state->xattr_size = -1;
3710 state->vfs_aio_state.error = errno;
3714 state->xattr_size = vfswrap_fgetxattr(state->handle,
3715 state->smb_fname->fsp,
3718 talloc_array_length(state->xattr_value));
3719 if (state->xattr_size == -1) {
3720 state->vfs_aio_state.error = errno;
3724 PROFILE_TIMESTAMP(&end_time);
3725 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3726 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3729 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3731 struct tevent_req *req = tevent_req_callback_data(
3732 subreq, struct tevent_req);
3733 struct vfswrap_getxattrat_state *state = tevent_req_data(
3734 req, struct vfswrap_getxattrat_state);
3739 * Make sure we run as the user again
3741 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3744 ret = pthreadpool_tevent_job_recv(subreq);
3745 TALLOC_FREE(subreq);
3746 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3747 talloc_set_destructor(state, NULL);
3749 if (ret != EAGAIN) {
3750 tevent_req_error(req, ret);
3754 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3755 * means the lower level pthreadpool failed to create a new
3756 * thread. Fallback to sync processing in that case to allow
3757 * some progress for the client.
3759 vfswrap_getxattrat_do_sync(req);
3763 if (state->xattr_size == -1) {
3764 tevent_req_error(req, state->vfs_aio_state.error);
3768 if (state->xattr_value == NULL) {
3770 * The caller only wanted the size.
3772 tevent_req_done(req);
3777 * shrink the buffer to the returned size.
3778 * (can't fail). It means NULL if size is 0.
3780 state->xattr_value = talloc_realloc(state,
3785 tevent_req_done(req);
3788 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3789 struct vfs_aio_state *aio_state,
3790 TALLOC_CTX *mem_ctx,
3791 uint8_t **xattr_value)
3793 struct vfswrap_getxattrat_state *state = tevent_req_data(
3794 req, struct vfswrap_getxattrat_state);
3797 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3798 tevent_req_received(req);
3802 *aio_state = state->vfs_aio_state;
3803 xattr_size = state->xattr_size;
3804 if (xattr_value != NULL) {
3805 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3808 tevent_req_received(req);
3812 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3814 int fd = fsp_get_pathref_fd(fsp);
3816 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3818 if (!fsp->fsp_flags.is_pathref) {
3819 return flistxattr(fd, list, size);
3822 if (fsp->fsp_flags.have_proc_fds) {
3823 struct sys_proc_fd_path_buf buf;
3825 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3829 * This is no longer a handle based call.
3831 return listxattr(fsp->fsp_name->base_name, list, size);
3834 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3836 int fd = fsp_get_pathref_fd(fsp);
3838 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3840 if (!fsp->fsp_flags.is_pathref) {
3841 return fremovexattr(fd, name);
3844 if (fsp->fsp_flags.have_proc_fds) {
3845 struct sys_proc_fd_path_buf buf;
3847 return removexattr(sys_proc_fd_path(fd, &buf), name);
3851 * This is no longer a handle based call.
3853 return removexattr(fsp->fsp_name->base_name, name);
3856 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3858 int fd = fsp_get_pathref_fd(fsp);
3860 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3862 if (!fsp->fsp_flags.is_pathref) {
3863 return fsetxattr(fd, name, value, size, flags);
3866 if (fsp->fsp_flags.have_proc_fds) {
3867 struct sys_proc_fd_path_buf buf;
3869 return setxattr(sys_proc_fd_path(fd, &buf),
3877 * This is no longer a handle based call.
3879 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3882 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3887 static bool vfswrap_is_offline(struct connection_struct *conn,
3888 const struct smb_filename *fname)
3892 bool offline = false;
3894 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3898 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3899 #if defined(ENOTSUP)
3905 status = get_full_smb_filename(talloc_tos(), fname, &path);
3906 if (!NT_STATUS_IS_OK(status)) {
3907 errno = map_errno_from_nt_status(status);
3911 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3918 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3919 struct files_struct *fsp,
3920 TALLOC_CTX *mem_ctx,
3923 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3926 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3927 struct files_struct *fsp,
3928 const DATA_BLOB old_cookie,
3929 TALLOC_CTX *mem_ctx,
3930 DATA_BLOB *new_cookie)
3932 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3936 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3937 struct smb_request *smb1req,
3938 struct smbXsrv_open *op,
3939 const DATA_BLOB old_cookie,
3940 TALLOC_CTX *mem_ctx,
3941 struct files_struct **fsp,
3942 DATA_BLOB *new_cookie)
3944 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3945 old_cookie, mem_ctx,
3949 static struct vfs_fn_pointers vfs_default_fns = {
3950 /* Disk operations */
3952 .connect_fn = vfswrap_connect,
3953 .disconnect_fn = vfswrap_disconnect,
3954 .disk_free_fn = vfswrap_disk_free,
3955 .get_quota_fn = vfswrap_get_quota,
3956 .set_quota_fn = vfswrap_set_quota,
3957 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3958 .statvfs_fn = vfswrap_statvfs,
3959 .fs_capabilities_fn = vfswrap_fs_capabilities,
3960 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3961 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3962 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3963 .snap_check_path_fn = vfswrap_snap_check_path,
3964 .snap_create_fn = vfswrap_snap_create,
3965 .snap_delete_fn = vfswrap_snap_delete,
3967 /* Directory operations */
3969 .fdopendir_fn = vfswrap_fdopendir,
3970 .readdir_fn = vfswrap_readdir,
3971 .freaddir_attr_fn = vfswrap_freaddir_attr,
3972 .rewind_dir_fn = vfswrap_rewinddir,
3973 .mkdirat_fn = vfswrap_mkdirat,
3974 .closedir_fn = vfswrap_closedir,
3976 /* File operations */
3978 .openat_fn = vfswrap_openat,
3979 .create_file_fn = vfswrap_create_file,
3980 .close_fn = vfswrap_close,
3981 .pread_fn = vfswrap_pread,
3982 .pread_send_fn = vfswrap_pread_send,
3983 .pread_recv_fn = vfswrap_pread_recv,
3984 .pwrite_fn = vfswrap_pwrite,
3985 .pwrite_send_fn = vfswrap_pwrite_send,
3986 .pwrite_recv_fn = vfswrap_pwrite_recv,
3987 .lseek_fn = vfswrap_lseek,
3988 .sendfile_fn = vfswrap_sendfile,
3989 .recvfile_fn = vfswrap_recvfile,
3990 .renameat_fn = vfswrap_renameat,
3991 .fsync_send_fn = vfswrap_fsync_send,
3992 .fsync_recv_fn = vfswrap_fsync_recv,
3993 .stat_fn = vfswrap_stat,
3994 .fstat_fn = vfswrap_fstat,
3995 .lstat_fn = vfswrap_lstat,
3996 .fstatat_fn = vfswrap_fstatat,
3997 .get_alloc_size_fn = vfswrap_get_alloc_size,
3998 .unlinkat_fn = vfswrap_unlinkat,
3999 .fchmod_fn = vfswrap_fchmod,
4000 .fchown_fn = vfswrap_fchown,
4001 .lchown_fn = vfswrap_lchown,
4002 .chdir_fn = vfswrap_chdir,
4003 .getwd_fn = vfswrap_getwd,
4004 .fntimes_fn = vfswrap_fntimes,
4005 .ftruncate_fn = vfswrap_ftruncate,
4006 .fallocate_fn = vfswrap_fallocate,
4007 .lock_fn = vfswrap_lock,
4008 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4009 .fcntl_fn = vfswrap_fcntl,
4010 .linux_setlease_fn = vfswrap_linux_setlease,
4011 .getlock_fn = vfswrap_getlock,
4012 .symlinkat_fn = vfswrap_symlinkat,
4013 .readlinkat_fn = vfswrap_readlinkat,
4014 .linkat_fn = vfswrap_linkat,
4015 .mknodat_fn = vfswrap_mknodat,
4016 .realpath_fn = vfswrap_realpath,
4017 .fchflags_fn = vfswrap_fchflags,
4018 .file_id_create_fn = vfswrap_file_id_create,
4019 .fs_file_id_fn = vfswrap_fs_file_id,
4020 .fstreaminfo_fn = vfswrap_fstreaminfo,
4021 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4022 .connectpath_fn = vfswrap_connectpath,
4023 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4024 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4025 .strict_lock_check_fn = vfswrap_strict_lock_check,
4026 .translate_name_fn = vfswrap_translate_name,
4027 .parent_pathname_fn = vfswrap_parent_pathname,
4028 .fsctl_fn = vfswrap_fsctl,
4029 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4030 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4031 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4032 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4033 .offload_read_send_fn = vfswrap_offload_read_send,
4034 .offload_read_recv_fn = vfswrap_offload_read_recv,
4035 .offload_write_send_fn = vfswrap_offload_write_send,
4036 .offload_write_recv_fn = vfswrap_offload_write_recv,
4037 .fget_compression_fn = vfswrap_fget_compression,
4038 .set_compression_fn = vfswrap_set_compression,
4040 /* NT ACL operations. */
4042 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4043 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4044 .audit_file_fn = vfswrap_audit_file,
4046 /* POSIX ACL operations. */
4048 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4049 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4050 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4051 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4053 /* EA operations. */
4054 .getxattrat_send_fn = vfswrap_getxattrat_send,
4055 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4056 .fgetxattr_fn = vfswrap_fgetxattr,
4057 .flistxattr_fn = vfswrap_flistxattr,
4058 .fremovexattr_fn = vfswrap_fremovexattr,
4059 .fsetxattr_fn = vfswrap_fsetxattr,
4061 /* aio operations */
4062 .aio_force_fn = vfswrap_aio_force,
4064 /* durable handle operations */
4065 .durable_cookie_fn = vfswrap_durable_cookie,
4066 .durable_disconnect_fn = vfswrap_durable_disconnect,
4067 .durable_reconnect_fn = vfswrap_durable_reconnect,
4071 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4074 * Here we need to implement every call!
4076 * As this is the end of the vfs module chain.
4078 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4079 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4080 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);