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,
748 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
751 * "/proc/self/fd/-1" never exists. Indicate to upper
752 * layers that for this fsp a possible name-based
753 * fallback is the only way to go.
755 fsp->fsp_flags.have_proc_fds = false;
759 END_PROFILE(syscall_openat);
762 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
763 struct smb_request *req,
764 struct files_struct *dirfsp,
765 struct smb_filename *smb_fname,
766 uint32_t access_mask,
767 uint32_t share_access,
768 uint32_t create_disposition,
769 uint32_t create_options,
770 uint32_t file_attributes,
771 uint32_t oplock_request,
772 const struct smb2_lease *lease,
773 uint64_t allocation_size,
774 uint32_t private_flags,
775 struct security_descriptor *sd,
776 struct ea_list *ea_list,
777 files_struct **result,
779 const struct smb2_create_blobs *in_context_blobs,
780 struct smb2_create_blobs *out_context_blobs)
782 return create_file_default(handle->conn, req, dirfsp, smb_fname,
783 access_mask, share_access,
784 create_disposition, create_options,
785 file_attributes, oplock_request, lease,
786 allocation_size, private_flags,
788 pinfo, in_context_blobs, out_context_blobs);
791 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
795 START_PROFILE(syscall_close);
796 result = fd_close_posix(fsp);
797 END_PROFILE(syscall_close);
801 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
802 size_t n, off_t offset)
806 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
807 START_PROFILE_BYTES(syscall_pread, n);
808 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
809 END_PROFILE_BYTES(syscall_pread);
811 if (result == -1 && errno == ESPIPE) {
812 /* Maintain the fiction that pipes can be seeked (sought?) on. */
813 result = sys_read(fsp_get_io_fd(fsp), data, n);
814 fh_set_pos(fsp->fh, 0);
817 #else /* HAVE_PREAD */
820 #endif /* HAVE_PREAD */
825 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
826 size_t n, off_t offset)
830 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
831 START_PROFILE_BYTES(syscall_pwrite, n);
832 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
833 END_PROFILE_BYTES(syscall_pwrite);
835 if (result == -1 && errno == ESPIPE) {
836 /* Maintain the fiction that pipes can be sought on. */
837 result = sys_write(fsp_get_io_fd(fsp), data, n);
840 #else /* HAVE_PWRITE */
843 #endif /* HAVE_PWRITE */
848 struct vfswrap_pread_state {
855 struct vfs_aio_state vfs_aio_state;
856 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
859 static void vfs_pread_do(void *private_data);
860 static void vfs_pread_done(struct tevent_req *subreq);
861 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
863 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
865 struct tevent_context *ev,
866 struct files_struct *fsp,
868 size_t n, off_t offset)
870 struct tevent_req *req, *subreq;
871 struct vfswrap_pread_state *state;
873 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
879 state->fd = fsp_get_io_fd(fsp);
882 state->offset = offset;
884 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
885 state->profile_bytes, n);
886 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
888 subreq = pthreadpool_tevent_job_send(
889 state, ev, handle->conn->sconn->pool,
890 vfs_pread_do, state);
891 if (tevent_req_nomem(subreq, req)) {
892 return tevent_req_post(req, ev);
894 tevent_req_set_callback(subreq, vfs_pread_done, req);
896 talloc_set_destructor(state, vfs_pread_state_destructor);
901 static void vfs_pread_do(void *private_data)
903 struct vfswrap_pread_state *state = talloc_get_type_abort(
904 private_data, struct vfswrap_pread_state);
905 struct timespec start_time;
906 struct timespec end_time;
908 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
910 PROFILE_TIMESTAMP(&start_time);
912 state->ret = sys_pread_full(state->fd,
917 if (state->ret == -1) {
918 state->vfs_aio_state.error = errno;
921 PROFILE_TIMESTAMP(&end_time);
923 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
925 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
928 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
933 static void vfs_pread_done(struct tevent_req *subreq)
935 struct tevent_req *req = tevent_req_callback_data(
936 subreq, struct tevent_req);
937 struct vfswrap_pread_state *state = tevent_req_data(
938 req, struct vfswrap_pread_state);
941 ret = pthreadpool_tevent_job_recv(subreq);
943 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
944 talloc_set_destructor(state, NULL);
947 tevent_req_error(req, ret);
951 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
952 * means the lower level pthreadpool failed to create a new
953 * thread. Fallback to sync processing in that case to allow
954 * some progress for the client.
959 tevent_req_done(req);
962 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
963 struct vfs_aio_state *vfs_aio_state)
965 struct vfswrap_pread_state *state = tevent_req_data(
966 req, struct vfswrap_pread_state);
968 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
972 *vfs_aio_state = state->vfs_aio_state;
976 struct vfswrap_pwrite_state {
983 struct vfs_aio_state vfs_aio_state;
984 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
987 static void vfs_pwrite_do(void *private_data);
988 static void vfs_pwrite_done(struct tevent_req *subreq);
989 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
991 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
993 struct tevent_context *ev,
994 struct files_struct *fsp,
996 size_t n, off_t offset)
998 struct tevent_req *req, *subreq;
999 struct vfswrap_pwrite_state *state;
1001 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1007 state->fd = fsp_get_io_fd(fsp);
1010 state->offset = offset;
1012 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1013 state->profile_bytes, n);
1014 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1016 subreq = pthreadpool_tevent_job_send(
1017 state, ev, handle->conn->sconn->pool,
1018 vfs_pwrite_do, state);
1019 if (tevent_req_nomem(subreq, req)) {
1020 return tevent_req_post(req, ev);
1022 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1024 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1029 static void vfs_pwrite_do(void *private_data)
1031 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1032 private_data, struct vfswrap_pwrite_state);
1033 struct timespec start_time;
1034 struct timespec end_time;
1036 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1038 PROFILE_TIMESTAMP(&start_time);
1040 state->ret = sys_pwrite_full(state->fd,
1045 if (state->ret == -1) {
1046 state->vfs_aio_state.error = errno;
1049 PROFILE_TIMESTAMP(&end_time);
1051 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1053 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1056 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1061 static void vfs_pwrite_done(struct tevent_req *subreq)
1063 struct tevent_req *req = tevent_req_callback_data(
1064 subreq, struct tevent_req);
1065 struct vfswrap_pwrite_state *state = tevent_req_data(
1066 req, struct vfswrap_pwrite_state);
1069 ret = pthreadpool_tevent_job_recv(subreq);
1070 TALLOC_FREE(subreq);
1071 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1072 talloc_set_destructor(state, NULL);
1074 if (ret != EAGAIN) {
1075 tevent_req_error(req, ret);
1079 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1080 * means the lower level pthreadpool failed to create a new
1081 * thread. Fallback to sync processing in that case to allow
1082 * some progress for the client.
1084 vfs_pwrite_do(state);
1087 tevent_req_done(req);
1090 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1091 struct vfs_aio_state *vfs_aio_state)
1093 struct vfswrap_pwrite_state *state = tevent_req_data(
1094 req, struct vfswrap_pwrite_state);
1096 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1100 *vfs_aio_state = state->vfs_aio_state;
1104 struct vfswrap_fsync_state {
1108 struct vfs_aio_state vfs_aio_state;
1109 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1112 static void vfs_fsync_do(void *private_data);
1113 static void vfs_fsync_done(struct tevent_req *subreq);
1114 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1116 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1117 TALLOC_CTX *mem_ctx,
1118 struct tevent_context *ev,
1119 struct files_struct *fsp)
1121 struct tevent_req *req, *subreq;
1122 struct vfswrap_fsync_state *state;
1124 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1130 state->fd = fsp_get_io_fd(fsp);
1132 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1133 state->profile_bytes, 0);
1134 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1136 subreq = pthreadpool_tevent_job_send(
1137 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1138 if (tevent_req_nomem(subreq, req)) {
1139 return tevent_req_post(req, ev);
1141 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1143 talloc_set_destructor(state, vfs_fsync_state_destructor);
1148 static void vfs_fsync_do(void *private_data)
1150 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1151 private_data, struct vfswrap_fsync_state);
1152 struct timespec start_time;
1153 struct timespec end_time;
1155 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1157 PROFILE_TIMESTAMP(&start_time);
1160 state->ret = fsync(state->fd);
1161 } while ((state->ret == -1) && (errno == EINTR));
1163 if (state->ret == -1) {
1164 state->vfs_aio_state.error = errno;
1167 PROFILE_TIMESTAMP(&end_time);
1169 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1171 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1174 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1179 static void vfs_fsync_done(struct tevent_req *subreq)
1181 struct tevent_req *req = tevent_req_callback_data(
1182 subreq, struct tevent_req);
1183 struct vfswrap_fsync_state *state = tevent_req_data(
1184 req, struct vfswrap_fsync_state);
1187 ret = pthreadpool_tevent_job_recv(subreq);
1188 TALLOC_FREE(subreq);
1189 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1190 talloc_set_destructor(state, NULL);
1192 if (ret != EAGAIN) {
1193 tevent_req_error(req, ret);
1197 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1198 * means the lower level pthreadpool failed to create a new
1199 * thread. Fallback to sync processing in that case to allow
1200 * some progress for the client.
1202 vfs_fsync_do(state);
1205 tevent_req_done(req);
1208 static int vfswrap_fsync_recv(struct tevent_req *req,
1209 struct vfs_aio_state *vfs_aio_state)
1211 struct vfswrap_fsync_state *state = tevent_req_data(
1212 req, struct vfswrap_fsync_state);
1214 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1218 *vfs_aio_state = state->vfs_aio_state;
1222 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1226 START_PROFILE(syscall_lseek);
1228 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1230 * We want to maintain the fiction that we can seek
1231 * on a fifo for file system purposes. This allows
1232 * people to set up UNIX fifo's that feed data to Windows
1233 * applications. JRA.
1236 if((result == -1) && (errno == ESPIPE)) {
1241 END_PROFILE(syscall_lseek);
1245 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1246 off_t offset, size_t n)
1250 START_PROFILE_BYTES(syscall_sendfile, n);
1251 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1252 END_PROFILE_BYTES(syscall_sendfile);
1256 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1258 files_struct *tofsp,
1264 START_PROFILE_BYTES(syscall_recvfile, n);
1265 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1266 END_PROFILE_BYTES(syscall_recvfile);
1270 static int vfswrap_renameat(vfs_handle_struct *handle,
1271 files_struct *srcfsp,
1272 const struct smb_filename *smb_fname_src,
1273 files_struct *dstfsp,
1274 const struct smb_filename *smb_fname_dst)
1278 START_PROFILE(syscall_renameat);
1280 SMB_ASSERT(!is_named_stream(smb_fname_src));
1281 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1283 result = renameat(fsp_get_pathref_fd(srcfsp),
1284 smb_fname_src->base_name,
1285 fsp_get_pathref_fd(dstfsp),
1286 smb_fname_dst->base_name);
1288 END_PROFILE(syscall_renameat);
1292 static int vfswrap_stat(vfs_handle_struct *handle,
1293 struct smb_filename *smb_fname)
1297 START_PROFILE(syscall_stat);
1299 SMB_ASSERT(!is_named_stream(smb_fname));
1301 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1302 lp_fake_directory_create_times(SNUM(handle->conn)));
1304 END_PROFILE(syscall_stat);
1308 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1312 START_PROFILE(syscall_fstat);
1313 result = sys_fstat(fsp_get_pathref_fd(fsp),
1314 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1315 END_PROFILE(syscall_fstat);
1319 static int vfswrap_lstat(vfs_handle_struct *handle,
1320 struct smb_filename *smb_fname)
1324 START_PROFILE(syscall_lstat);
1326 SMB_ASSERT(!is_named_stream(smb_fname));
1328 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1329 lp_fake_directory_create_times(SNUM(handle->conn)));
1331 END_PROFILE(syscall_lstat);
1335 static int vfswrap_fstatat(
1336 struct vfs_handle_struct *handle,
1337 const struct files_struct *dirfsp,
1338 const struct smb_filename *smb_fname,
1339 SMB_STRUCT_STAT *sbuf,
1344 START_PROFILE(syscall_fstatat);
1346 SMB_ASSERT(!is_named_stream(smb_fname));
1348 result = sys_fstatat(
1349 fsp_get_pathref_fd(dirfsp),
1350 smb_fname->base_name,
1353 lp_fake_directory_create_times(SNUM(handle->conn)));
1355 END_PROFILE(syscall_fstatat);
1359 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1361 enum vfs_translate_direction direction,
1362 TALLOC_CTX *mem_ctx,
1365 return NT_STATUS_NONE_MAPPED;
1369 * Return allocated parent directory and basename of path
1371 * Note: if requesting atname, it is returned as talloc child of the
1372 * parent. Freeing the parent is thus sufficient to free both.
1374 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1375 TALLOC_CTX *mem_ctx,
1376 const struct smb_filename *smb_fname_in,
1377 struct smb_filename **parent_dir_out,
1378 struct smb_filename **atname_out)
1380 struct smb_filename *parent = NULL;
1381 struct smb_filename *name = NULL;
1384 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1385 if (parent == NULL) {
1386 return NT_STATUS_NO_MEMORY;
1388 SET_STAT_INVALID(parent->st);
1390 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1392 TALLOC_FREE(parent->base_name);
1393 parent->base_name = talloc_strdup(parent, ".");
1394 if (parent->base_name == NULL) {
1395 TALLOC_FREE(parent);
1396 return NT_STATUS_NO_MEMORY;
1398 p = smb_fname_in->base_name;
1404 if (atname_out == NULL) {
1405 *parent_dir_out = parent;
1406 return NT_STATUS_OK;
1409 name = synthetic_smb_fname(
1412 smb_fname_in->stream_name,
1415 smb_fname_in->flags);
1417 return NT_STATUS_NO_MEMORY;
1420 *parent_dir_out = parent;
1422 return NT_STATUS_OK;
1426 * Implement the default fsctl operation.
1428 static bool vfswrap_logged_ioctl_message = false;
1430 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1431 struct files_struct *fsp,
1434 uint16_t req_flags, /* Needed for UNICODE ... */
1435 const uint8_t *_in_data,
1437 uint8_t **_out_data,
1438 uint32_t max_out_len,
1441 const char *in_data = (const char *)_in_data;
1442 char **out_data = (char **)_out_data;
1446 * Currently all fsctls operate on the base
1447 * file if given an alternate data stream.
1448 * Revisit this if we implement fsctls later
1449 * that need access to the ADS handle.
1451 fsp = metadata_fsp(fsp);
1454 case FSCTL_SET_SPARSE:
1456 bool set_sparse = true;
1458 if (in_len >= 1 && in_data[0] == 0) {
1462 status = file_set_sparse(handle->conn, fsp, set_sparse);
1464 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1465 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1466 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1467 nt_errstr(status)));
1472 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1474 unsigned char objid[16];
1475 char *return_data = NULL;
1477 /* This should return the object-id on this file.
1478 * I think I'll make this be the inode+dev. JRA.
1481 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1484 *out_len = MIN(max_out_len, 64);
1486 /* Hmmm, will this cause problems if less data asked for? */
1487 return_data = talloc_array(ctx, char, 64);
1488 if (return_data == NULL) {
1489 return NT_STATUS_NO_MEMORY;
1492 /* For backwards compatibility only store the dev/inode. */
1493 push_file_id_16(return_data, &fsp->file_id);
1494 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1495 push_file_id_16(return_data+32, &fsp->file_id);
1496 memset(return_data+48, 0, 16);
1497 *out_data = return_data;
1498 return NT_STATUS_OK;
1501 case FSCTL_GET_REPARSE_POINT:
1503 status = fsctl_get_reparse_point(
1504 fsp, ctx, out_data, max_out_len, out_len);
1508 case FSCTL_SET_REPARSE_POINT:
1510 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1514 case FSCTL_DELETE_REPARSE_POINT:
1516 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1520 case FSCTL_GET_SHADOW_COPY_DATA:
1523 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1524 * and return their volume names. If max_data_count is 16, then it is just
1525 * asking for the number of volumes and length of the combined names.
1527 * pdata is the data allocated by our caller, but that uses
1528 * total_data_count (which is 0 in our case) rather than max_data_count.
1529 * Allocate the correct amount and return the pointer to let
1530 * it be deallocated when we return.
1532 struct shadow_copy_data *shadow_data = NULL;
1533 bool labels = False;
1534 uint32_t labels_data_count = 0;
1536 char *cur_pdata = NULL;
1538 if (max_out_len < 16) {
1539 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1541 return NT_STATUS_INVALID_PARAMETER;
1544 if (max_out_len > 16) {
1548 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1549 if (shadow_data == NULL) {
1550 DBG_ERR("TALLOC_ZERO() failed!\n");
1551 return NT_STATUS_NO_MEMORY;
1555 * Call the VFS routine to actually do the work.
1557 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1558 int log_lev = DBGLVL_ERR;
1560 /* broken module didn't set errno on error */
1561 status = NT_STATUS_UNSUCCESSFUL;
1563 status = map_nt_error_from_unix(errno);
1564 if (NT_STATUS_EQUAL(status,
1565 NT_STATUS_NOT_SUPPORTED)) {
1566 log_lev = DBGLVL_INFO;
1569 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1570 "connectpath %s, failed - %s.\n",
1571 fsp->conn->connectpath,
1572 nt_errstr(status)));
1573 TALLOC_FREE(shadow_data);
1577 labels_data_count = (shadow_data->num_volumes * 2 *
1578 sizeof(SHADOW_COPY_LABEL)) + 2;
1583 *out_len = 12 + labels_data_count;
1586 if (max_out_len < *out_len) {
1587 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1588 max_out_len, *out_len);
1589 TALLOC_FREE(shadow_data);
1590 return NT_STATUS_BUFFER_TOO_SMALL;
1593 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1594 if (cur_pdata == NULL) {
1595 TALLOC_FREE(shadow_data);
1596 return NT_STATUS_NO_MEMORY;
1599 *out_data = cur_pdata;
1601 /* num_volumes 4 bytes */
1602 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1605 /* num_labels 4 bytes */
1606 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1609 /* needed_data_count 4 bytes */
1610 SIVAL(cur_pdata, 8, labels_data_count);
1614 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1615 shadow_data->num_volumes, fsp_str_dbg(fsp));
1616 if (labels && shadow_data->labels) {
1617 for (i=0; i<shadow_data->num_volumes; i++) {
1619 status = srvstr_push(cur_pdata, req_flags,
1620 cur_pdata, shadow_data->labels[i],
1621 2 * sizeof(SHADOW_COPY_LABEL),
1622 STR_UNICODE|STR_TERMINATE, &len);
1623 if (!NT_STATUS_IS_OK(status)) {
1624 TALLOC_FREE(*out_data);
1625 TALLOC_FREE(shadow_data);
1628 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1629 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1633 TALLOC_FREE(shadow_data);
1635 return NT_STATUS_OK;
1638 case FSCTL_FIND_FILES_BY_SID:
1640 /* pretend this succeeded -
1642 * we have to send back a list with all files owned by this SID
1644 * but I have to check that --metze
1648 struct dom_sid_buf buf;
1652 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1656 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1657 return NT_STATUS_INVALID_PARAMETER;
1660 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1662 /* unknown 4 bytes: this is not the length of the sid :-( */
1663 /*unknown = IVAL(pdata,0);*/
1665 ret = sid_parse(_in_data + 4, sid_len, &sid);
1667 return NT_STATUS_INVALID_PARAMETER;
1669 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1670 dom_sid_str_buf(&sid, &buf)));
1672 if (!sid_to_uid(&sid, &uid)) {
1673 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1674 dom_sid_str_buf(&sid, &buf),
1675 (unsigned long)sid_len);
1679 /* we can take a look at the find source :-)
1681 * find ./ -uid $uid -name '*' is what we need here
1684 * and send 4bytes len and then NULL terminated unicode strings
1687 * but I don't know how to deal with the paged results
1688 * (maybe we can hang the result anywhere in the fsp struct)
1690 * but I don't know how to deal with the paged results
1691 * (maybe we can hang the result anywhere in the fsp struct)
1693 * we don't send all files at once
1694 * and at the next we should *not* start from the beginning,
1695 * so we have to cache the result
1700 /* this works for now... */
1701 return NT_STATUS_OK;
1704 case FSCTL_QUERY_ALLOCATED_RANGES:
1706 /* FIXME: This is just a dummy reply, telling that all of the
1707 * file is allocated. MKS cp needs that.
1708 * Adding the real allocated ranges via FIEMAP on Linux
1709 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1710 * this FSCTL correct for sparse files.
1712 uint64_t offset, length;
1713 char *out_data_tmp = NULL;
1716 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1718 return NT_STATUS_INVALID_PARAMETER;
1721 if (max_out_len < 16) {
1722 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1724 return NT_STATUS_INVALID_PARAMETER;
1727 offset = BVAL(in_data,0);
1728 length = BVAL(in_data,8);
1730 if (offset + length < offset) {
1731 /* No 64-bit integer wrap. */
1732 return NT_STATUS_INVALID_PARAMETER;
1735 /* Shouldn't this be SMB_VFS_STAT ... ? */
1736 status = vfs_stat_fsp(fsp);
1737 if (!NT_STATUS_IS_OK(status)) {
1742 out_data_tmp = talloc_array(ctx, char, *out_len);
1743 if (out_data_tmp == NULL) {
1744 DBG_DEBUG("unable to allocate memory for response\n");
1745 return NT_STATUS_NO_MEMORY;
1748 if (offset > fsp->fsp_name->st.st_ex_size ||
1749 fsp->fsp_name->st.st_ex_size == 0 ||
1751 memset(out_data_tmp, 0, *out_len);
1753 uint64_t end = offset + length;
1754 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1755 SBVAL(out_data_tmp, 0, 0);
1756 SBVAL(out_data_tmp, 8, end);
1759 *out_data = out_data_tmp;
1761 return NT_STATUS_OK;
1764 case FSCTL_IS_VOLUME_DIRTY:
1766 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1767 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1769 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1770 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1772 return NT_STATUS_INVALID_PARAMETER;
1777 * Only print once ... unfortunately there could be lots of
1778 * different FSCTLs that are called.
1780 if (!vfswrap_logged_ioctl_message) {
1781 vfswrap_logged_ioctl_message = true;
1782 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1783 __func__, function);
1787 return NT_STATUS_NOT_SUPPORTED;
1790 static bool vfswrap_is_offline(struct connection_struct *conn,
1791 const struct smb_filename *fname);
1793 struct vfswrap_get_dos_attributes_state {
1794 struct vfs_aio_state aio_state;
1795 connection_struct *conn;
1796 TALLOC_CTX *mem_ctx;
1797 struct tevent_context *ev;
1798 files_struct *dir_fsp;
1799 struct smb_filename *smb_fname;
1804 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1806 static struct tevent_req *vfswrap_get_dos_attributes_send(
1807 TALLOC_CTX *mem_ctx,
1808 struct tevent_context *ev,
1809 struct vfs_handle_struct *handle,
1810 files_struct *dir_fsp,
1811 struct smb_filename *smb_fname)
1813 struct tevent_req *req = NULL;
1814 struct tevent_req *subreq = NULL;
1815 struct vfswrap_get_dos_attributes_state *state = NULL;
1817 SMB_ASSERT(!is_named_stream(smb_fname));
1819 req = tevent_req_create(mem_ctx, &state,
1820 struct vfswrap_get_dos_attributes_state);
1825 *state = (struct vfswrap_get_dos_attributes_state) {
1826 .conn = dir_fsp->conn,
1830 .smb_fname = smb_fname,
1833 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1834 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1835 "\"store dos attributes\" is disabled\n",
1836 dir_fsp->conn->connectpath);
1837 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1838 return tevent_req_post(req, ev);
1841 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1845 SAMBA_XATTR_DOS_ATTRIB,
1847 if (tevent_req_nomem(subreq, req)) {
1848 return tevent_req_post(req, ev);
1850 tevent_req_set_callback(subreq,
1851 vfswrap_get_dos_attributes_getxattr_done,
1857 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1859 struct tevent_req *req =
1860 tevent_req_callback_data(subreq,
1862 struct vfswrap_get_dos_attributes_state *state =
1863 tevent_req_data(req,
1864 struct vfswrap_get_dos_attributes_state);
1866 DATA_BLOB blob = {0};
1868 char *tofree = NULL;
1869 char pathbuf[PATH_MAX+1];
1871 struct smb_filename smb_fname;
1875 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1879 TALLOC_FREE(subreq);
1880 if (xattr_size == -1) {
1881 status = map_nt_error_from_unix(state->aio_state.error);
1883 if (state->as_root) {
1884 tevent_req_nterror(req, status);
1887 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1888 tevent_req_nterror(req, status);
1892 state->as_root = true;
1894 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1895 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1899 SAMBA_XATTR_DOS_ATTRIB,
1901 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1902 if (tevent_req_nomem(subreq, req)) {
1905 tevent_req_set_callback(subreq,
1906 vfswrap_get_dos_attributes_getxattr_done,
1911 blob.length = xattr_size;
1913 status = parse_dos_attribute_blob(state->smb_fname,
1916 if (!NT_STATUS_IS_OK(status)) {
1917 tevent_req_nterror(req, status);
1921 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1922 state->smb_fname->base_name,
1927 if (pathlen == -1) {
1928 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1932 smb_fname = (struct smb_filename) {
1934 .st = state->smb_fname->st,
1935 .flags = state->smb_fname->flags,
1936 .twrp = state->smb_fname->twrp,
1939 offline = vfswrap_is_offline(state->conn, &smb_fname);
1941 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1943 TALLOC_FREE(tofree);
1945 tevent_req_done(req);
1949 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1950 struct vfs_aio_state *aio_state,
1953 struct vfswrap_get_dos_attributes_state *state =
1954 tevent_req_data(req,
1955 struct vfswrap_get_dos_attributes_state);
1958 if (tevent_req_is_nterror(req, &status)) {
1959 tevent_req_received(req);
1963 *aio_state = state->aio_state;
1964 *dosmode = state->dosmode;
1965 tevent_req_received(req);
1966 return NT_STATUS_OK;
1969 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1970 struct files_struct *fsp,
1975 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1977 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1979 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1982 return fget_ea_dos_attribute(fsp, dosmode);
1985 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1986 struct files_struct *fsp,
1989 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1991 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1994 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1996 struct vfswrap_offload_read_state {
2000 static struct tevent_req *vfswrap_offload_read_send(
2001 TALLOC_CTX *mem_ctx,
2002 struct tevent_context *ev,
2003 struct vfs_handle_struct *handle,
2004 struct files_struct *fsp,
2010 struct tevent_req *req = NULL;
2011 struct vfswrap_offload_read_state *state = NULL;
2014 req = tevent_req_create(mem_ctx, &state,
2015 struct vfswrap_offload_read_state);
2020 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2021 &vfswrap_offload_ctx);
2022 if (tevent_req_nterror(req, status)) {
2023 return tevent_req_post(req, ev);
2026 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2027 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2028 return tevent_req_post(req, ev);
2031 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2033 if (tevent_req_nterror(req, status)) {
2034 return tevent_req_post(req, ev);
2037 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2039 if (tevent_req_nterror(req, status)) {
2040 return tevent_req_post(req, ev);
2043 tevent_req_done(req);
2044 return tevent_req_post(req, ev);
2047 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2048 struct vfs_handle_struct *handle,
2049 TALLOC_CTX *mem_ctx,
2054 struct vfswrap_offload_read_state *state = tevent_req_data(
2055 req, struct vfswrap_offload_read_state);
2058 if (tevent_req_is_nterror(req, &status)) {
2059 tevent_req_received(req);
2065 token->length = state->token.length;
2066 token->data = talloc_move(mem_ctx, &state->token.data);
2068 tevent_req_received(req);
2069 return NT_STATUS_OK;
2072 struct vfswrap_offload_write_state {
2074 bool read_lck_locked;
2075 bool write_lck_locked;
2077 struct tevent_context *src_ev;
2078 struct files_struct *src_fsp;
2080 struct tevent_context *dst_ev;
2081 struct files_struct *dst_fsp;
2086 size_t next_io_size;
2089 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2090 enum tevent_req_state req_state)
2092 struct vfswrap_offload_write_state *state = tevent_req_data(
2093 req, struct vfswrap_offload_write_state);
2096 if (state->dst_fsp == NULL) {
2100 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2102 state->dst_fsp = NULL;
2105 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2106 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2108 static struct tevent_req *vfswrap_offload_write_send(
2109 struct vfs_handle_struct *handle,
2110 TALLOC_CTX *mem_ctx,
2111 struct tevent_context *ev,
2114 off_t transfer_offset,
2115 struct files_struct *dest_fsp,
2119 struct tevent_req *req;
2120 struct vfswrap_offload_write_state *state = NULL;
2121 /* off_t is signed! */
2122 off_t max_offset = INT64_MAX - to_copy;
2123 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2124 files_struct *src_fsp = NULL;
2128 req = tevent_req_create(mem_ctx, &state,
2129 struct vfswrap_offload_write_state);
2134 *state = (struct vfswrap_offload_write_state) {
2136 .src_off = transfer_offset,
2138 .dst_fsp = dest_fsp,
2139 .dst_off = dest_off,
2141 .remaining = to_copy,
2144 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2147 case FSCTL_SRV_COPYCHUNK:
2148 case FSCTL_SRV_COPYCHUNK_WRITE:
2151 case FSCTL_OFFLOAD_WRITE:
2152 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2153 return tevent_req_post(req, ev);
2155 case FSCTL_DUP_EXTENTS_TO_FILE:
2156 DBG_DEBUG("COW clones not supported by vfs_default\n");
2157 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2158 return tevent_req_post(req, ev);
2161 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2162 return tevent_req_post(req, ev);
2166 * From here on we assume a copy-chunk fsctl
2170 tevent_req_done(req);
2171 return tevent_req_post(req, ev);
2174 if (state->src_off > max_offset) {
2176 * Protect integer checks below.
2178 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2179 return tevent_req_post(req, ev);
2181 if (state->src_off < 0) {
2183 * Protect integer checks below.
2185 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2186 return tevent_req_post(req, ev);
2188 if (state->dst_off > max_offset) {
2190 * Protect integer checks below.
2192 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2193 return tevent_req_post(req, ev);
2195 if (state->dst_off < 0) {
2197 * Protect integer checks below.
2199 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2200 return tevent_req_post(req, ev);
2203 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2205 if (tevent_req_nterror(req, status)) {
2206 return tevent_req_post(req, ev);
2209 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2211 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2212 if (!NT_STATUS_IS_OK(status)) {
2213 tevent_req_nterror(req, status);
2214 return tevent_req_post(req, ev);
2217 ok = change_to_user_and_service_by_fsp(src_fsp);
2219 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2220 return tevent_req_post(req, ev);
2223 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2224 state->src_fsp = src_fsp;
2226 status = vfs_stat_fsp(src_fsp);
2227 if (tevent_req_nterror(req, status)) {
2228 return tevent_req_post(req, ev);
2231 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2233 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2234 * If the SourceOffset or SourceOffset + Length extends beyond
2235 * the end of file, the server SHOULD<240> treat this as a
2236 * STATUS_END_OF_FILE error.
2238 * <240> Section 3.3.5.15.6: Windows servers will return
2239 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2241 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2242 return tevent_req_post(req, ev);
2245 status = vfswrap_offload_copy_file_range(req);
2246 if (NT_STATUS_IS_OK(status)) {
2247 tevent_req_done(req);
2248 return tevent_req_post(req, ev);
2250 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2251 tevent_req_nterror(req, status);
2252 return tevent_req_post(req, ev);
2255 state->buf = talloc_array(state, uint8_t, num);
2256 if (tevent_req_nomem(state->buf, req)) {
2257 return tevent_req_post(req, ev);
2260 status = vfswrap_offload_write_loop(req);
2261 if (!NT_STATUS_IS_OK(status)) {
2262 tevent_req_nterror(req, status);
2263 return tevent_req_post(req, ev);
2269 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2271 struct vfswrap_offload_write_state *state = tevent_req_data(
2272 req, struct vfswrap_offload_write_state);
2273 struct lock_struct lck;
2278 static bool try_copy_file_range = true;
2280 if (!try_copy_file_range) {
2281 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2284 same_file = file_id_equal(&state->src_fsp->file_id,
2285 &state->dst_fsp->file_id);
2287 sys_io_ranges_overlap(state->remaining,
2292 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2295 if (fsp_is_alternate_stream(state->src_fsp) ||
2296 fsp_is_alternate_stream(state->dst_fsp))
2298 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2301 init_strict_lock_struct(state->src_fsp,
2302 state->src_fsp->op->global->open_persistent_id,
2306 lp_posix_cifsu_locktype(state->src_fsp),
2309 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2313 return NT_STATUS_FILE_LOCK_CONFLICT;
2316 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2318 return NT_STATUS_INTERNAL_ERROR;
2321 init_strict_lock_struct(state->dst_fsp,
2322 state->dst_fsp->op->global->open_persistent_id,
2326 lp_posix_cifsu_locktype(state->dst_fsp),
2329 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2333 return NT_STATUS_FILE_LOCK_CONFLICT;
2336 while (state->remaining > 0) {
2337 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2339 fsp_get_io_fd(state->dst_fsp),
2343 if (nwritten == -1) {
2344 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2345 "n [%jd] failed: %s\n",
2346 fsp_str_dbg(state->src_fsp),
2347 (intmax_t)state->src_off,
2348 fsp_str_dbg(state->dst_fsp),
2349 (intmax_t)state->dst_off,
2350 (intmax_t)state->remaining,
2355 try_copy_file_range = false;
2356 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2359 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2362 status = map_nt_error_from_unix(errno);
2363 if (NT_STATUS_EQUAL(
2365 NT_STATUS_MORE_PROCESSING_REQUIRED))
2367 /* Avoid triggering the fallback */
2368 status = NT_STATUS_INTERNAL_ERROR;
2375 if (state->remaining < nwritten) {
2376 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2377 "n [%jd] remaining [%jd]\n",
2378 fsp_str_dbg(state->src_fsp),
2379 fsp_str_dbg(state->dst_fsp),
2381 (intmax_t)state->remaining);
2382 return NT_STATUS_INTERNAL_ERROR;
2385 if (nwritten == 0) {
2388 state->copied += nwritten;
2389 state->remaining -= nwritten;
2393 * Tell the req cleanup function there's no need to call
2394 * change_to_user_and_service_by_fsp() on the dst handle.
2396 state->dst_fsp = NULL;
2397 return NT_STATUS_OK;
2400 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2402 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2404 struct vfswrap_offload_write_state *state = tevent_req_data(
2405 req, struct vfswrap_offload_write_state);
2406 struct tevent_req *subreq = NULL;
2407 struct lock_struct read_lck;
2411 * This is called under the context of state->src_fsp.
2414 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2416 init_strict_lock_struct(state->src_fsp,
2417 state->src_fsp->op->global->open_persistent_id,
2419 state->next_io_size,
2421 lp_posix_cifsu_locktype(state->src_fsp),
2424 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2428 return NT_STATUS_FILE_LOCK_CONFLICT;
2431 subreq = SMB_VFS_PREAD_SEND(state,
2435 state->next_io_size,
2437 if (subreq == NULL) {
2438 return NT_STATUS_NO_MEMORY;
2440 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2442 return NT_STATUS_OK;
2445 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2447 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2449 struct tevent_req *req = tevent_req_callback_data(
2450 subreq, struct tevent_req);
2451 struct vfswrap_offload_write_state *state = tevent_req_data(
2452 req, struct vfswrap_offload_write_state);
2453 struct vfs_aio_state aio_state;
2454 struct lock_struct write_lck;
2458 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2459 TALLOC_FREE(subreq);
2461 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2462 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2465 if (nread != state->next_io_size) {
2466 DBG_ERR("Short read, only %zd of %zu\n",
2467 nread, state->next_io_size);
2468 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2472 state->src_off += nread;
2474 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2476 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2480 init_strict_lock_struct(state->dst_fsp,
2481 state->dst_fsp->op->global->open_persistent_id,
2483 state->next_io_size,
2485 lp_posix_cifsu_locktype(state->dst_fsp),
2488 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2492 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2496 subreq = SMB_VFS_PWRITE_SEND(state,
2500 state->next_io_size,
2502 if (subreq == NULL) {
2503 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2506 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2509 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2511 struct tevent_req *req = tevent_req_callback_data(
2512 subreq, struct tevent_req);
2513 struct vfswrap_offload_write_state *state = tevent_req_data(
2514 req, struct vfswrap_offload_write_state);
2515 struct vfs_aio_state aio_state;
2520 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2521 TALLOC_FREE(subreq);
2522 if (nwritten == -1) {
2523 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2524 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2527 if (nwritten != state->next_io_size) {
2528 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2529 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2533 state->dst_off += nwritten;
2535 if (state->remaining < nwritten) {
2536 /* Paranoia check */
2537 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2540 state->copied += nwritten;
2541 state->remaining -= nwritten;
2542 if (state->remaining == 0) {
2543 tevent_req_done(req);
2547 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2549 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2553 status = vfswrap_offload_write_loop(req);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 tevent_req_nterror(req, status);
2562 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2563 struct tevent_req *req,
2566 struct vfswrap_offload_write_state *state = tevent_req_data(
2567 req, struct vfswrap_offload_write_state);
2570 if (tevent_req_is_nterror(req, &status)) {
2571 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2573 tevent_req_received(req);
2577 *copied = state->copied;
2578 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2579 tevent_req_received(req);
2581 return NT_STATUS_OK;
2584 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2585 TALLOC_CTX *mem_ctx,
2586 struct files_struct *fsp,
2587 uint16_t *_compression_fmt)
2589 return NT_STATUS_INVALID_DEVICE_REQUEST;
2592 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2593 TALLOC_CTX *mem_ctx,
2594 struct files_struct *fsp,
2595 uint16_t compression_fmt)
2597 return NT_STATUS_INVALID_DEVICE_REQUEST;
2600 /********************************************************************
2601 Given a stat buffer return the allocated size on disk, taking into
2602 account sparse files.
2603 ********************************************************************/
2604 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2605 struct files_struct *fsp,
2606 const SMB_STRUCT_STAT *sbuf)
2610 START_PROFILE(syscall_get_alloc_size);
2612 if(S_ISDIR(sbuf->st_ex_mode)) {
2617 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2618 /* The type of st_blocksize is blkcnt_t which *MUST* be
2619 signed (according to POSIX) and can be less than 64-bits.
2620 Ensure when we're converting to 64 bits wide we don't
2622 #if defined(SIZEOF_BLKCNT_T_8)
2623 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2624 #elif defined(SIZEOF_BLKCNT_T_4)
2626 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2627 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2630 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2634 * Some file systems do not allocate a block for very
2635 * small files. But for non-empty file should report a
2639 uint64_t filesize = get_file_size_stat(sbuf);
2641 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2645 result = get_file_size_stat(sbuf);
2648 if (fsp && fsp->initial_allocation_size)
2649 result = MAX(result,fsp->initial_allocation_size);
2651 result = smb_roundup(handle->conn, result);
2654 END_PROFILE(syscall_get_alloc_size);
2658 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2659 struct files_struct *dirfsp,
2660 const struct smb_filename *smb_fname,
2665 START_PROFILE(syscall_unlinkat);
2667 SMB_ASSERT(!is_named_stream(smb_fname));
2669 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2670 smb_fname->base_name,
2673 END_PROFILE(syscall_unlinkat);
2677 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2681 START_PROFILE(syscall_fchmod);
2683 if (!fsp->fsp_flags.is_pathref) {
2684 result = fchmod(fsp_get_io_fd(fsp), mode);
2685 END_PROFILE(syscall_fchmod);
2689 if (fsp->fsp_flags.have_proc_fds) {
2690 int fd = fsp_get_pathref_fd(fsp);
2691 struct sys_proc_fd_path_buf buf;
2693 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2695 END_PROFILE(syscall_fchmod);
2700 * This is no longer a handle based call.
2702 result = chmod(fsp->fsp_name->base_name, mode);
2704 END_PROFILE(syscall_fchmod);
2708 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2713 START_PROFILE(syscall_fchown);
2714 if (!fsp->fsp_flags.is_pathref) {
2715 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2716 END_PROFILE(syscall_fchown);
2720 if (fsp->fsp_flags.have_proc_fds) {
2721 int fd = fsp_get_pathref_fd(fsp);
2722 struct sys_proc_fd_path_buf buf;
2724 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2726 END_PROFILE(syscall_fchown);
2731 * This is no longer a handle based call.
2733 result = chown(fsp->fsp_name->base_name, uid, gid);
2734 END_PROFILE(syscall_fchown);
2742 static int vfswrap_lchown(vfs_handle_struct *handle,
2743 const struct smb_filename *smb_fname,
2749 START_PROFILE(syscall_lchown);
2750 result = lchown(smb_fname->base_name, uid, gid);
2751 END_PROFILE(syscall_lchown);
2755 static int vfswrap_chdir(vfs_handle_struct *handle,
2756 const struct smb_filename *smb_fname)
2760 START_PROFILE(syscall_chdir);
2761 result = chdir(smb_fname->base_name);
2762 END_PROFILE(syscall_chdir);
2766 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2770 struct smb_filename *smb_fname = NULL;
2772 START_PROFILE(syscall_getwd);
2773 result = sys_getwd();
2774 END_PROFILE(syscall_getwd);
2776 if (result == NULL) {
2779 smb_fname = synthetic_smb_fname(ctx,
2786 * sys_getwd() *always* returns malloced memory.
2787 * We must free here to avoid leaks:
2788 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2794 /*********************************************************************
2795 nsec timestamp resolution call. Convert down to whatever the underlying
2796 system will support.
2797 **********************************************************************/
2799 static int vfswrap_fntimes(vfs_handle_struct *handle,
2801 struct smb_file_time *ft)
2804 struct timespec ts[2];
2805 struct timespec *times = NULL;
2807 START_PROFILE(syscall_fntimes);
2809 if (fsp_is_alternate_stream(fsp)) {
2815 if (is_omit_timespec(&ft->atime)) {
2816 ft->atime = fsp->fsp_name->st.st_ex_atime;
2819 if (is_omit_timespec(&ft->mtime)) {
2820 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2823 if (!is_omit_timespec(&ft->create_time)) {
2824 set_create_timespec_ea(fsp,
2828 if ((timespec_compare(&ft->atime,
2829 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2830 (timespec_compare(&ft->mtime,
2831 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2843 if (!fsp->fsp_flags.is_pathref) {
2844 result = futimens(fsp_get_io_fd(fsp), times);
2848 if (fsp->fsp_flags.have_proc_fds) {
2849 int fd = fsp_get_pathref_fd(fsp);
2850 struct sys_proc_fd_path_buf buf;
2852 result = utimensat(AT_FDCWD,
2853 sys_proc_fd_path(fd, &buf),
2861 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2862 * path translation mechanism. Fallback to path based call.
2864 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2867 END_PROFILE(syscall_fntimes);
2873 /*********************************************************************
2874 A version of ftruncate that will write the space on disk if strict
2876 **********************************************************************/
2878 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2880 off_t space_to_write;
2881 uint64_t space_avail;
2882 uint64_t bsize,dfree,dsize;
2885 SMB_STRUCT_STAT *pst;
2888 ok = vfs_valid_pwrite_range(len, 0);
2894 status = vfs_stat_fsp(fsp);
2895 if (!NT_STATUS_IS_OK(status)) {
2898 pst = &fsp->fsp_name->st;
2901 if (S_ISFIFO(pst->st_ex_mode))
2905 if (pst->st_ex_size == len)
2908 /* Shrink - just ftruncate. */
2909 if (pst->st_ex_size > len)
2910 return ftruncate(fsp_get_io_fd(fsp), len);
2912 space_to_write = len - pst->st_ex_size;
2914 /* for allocation try fallocate first. This can fail on some
2915 platforms e.g. when the filesystem doesn't support it and no
2916 emulation is being done by the libc (like on AIX with JFS1). In that
2917 case we do our own emulation. fallocate implementations can
2918 return ENOTSUP or EINVAL in cases like that. */
2919 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2920 if (ret == -1 && errno == ENOSPC) {
2926 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2927 "error %d. Falling back to slow manual allocation\n", errno);
2929 /* available disk space is enough or not? */
2931 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2932 /* space_avail is 1k blocks */
2933 if (space_avail == (uint64_t)-1 ||
2934 ((uint64_t)space_to_write/1024 > space_avail) ) {
2939 /* Write out the real space on disk. */
2940 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2948 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2951 SMB_STRUCT_STAT *pst;
2955 START_PROFILE(syscall_ftruncate);
2957 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2958 result = strict_allocate_ftruncate(handle, fsp, len);
2959 END_PROFILE(syscall_ftruncate);
2963 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2964 ftruncate if the system supports it. Then I discovered that
2965 you can have some filesystems that support ftruncate
2966 expansion and some that don't! On Linux fat can't do
2967 ftruncate extend but ext2 can. */
2969 result = ftruncate(fsp_get_io_fd(fsp), len);
2971 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2972 extend a file with ftruncate. Provide alternate implementation
2975 /* Do an fstat to see if the file is longer than the requested
2976 size in which case the ftruncate above should have
2977 succeeded or shorter, in which case seek to len - 1 and
2978 write 1 byte of zero */
2979 status = vfs_stat_fsp(fsp);
2980 if (!NT_STATUS_IS_OK(status)) {
2984 /* We need to update the files_struct after successful ftruncate */
2989 pst = &fsp->fsp_name->st;
2992 if (S_ISFIFO(pst->st_ex_mode)) {
2998 if (pst->st_ex_size == len) {
3003 if (pst->st_ex_size > len) {
3004 /* the ftruncate should have worked */
3008 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3016 END_PROFILE(syscall_ftruncate);
3020 static int vfswrap_fallocate(vfs_handle_struct *handle,
3028 START_PROFILE(syscall_fallocate);
3030 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3032 * posix_fallocate returns 0 on success, errno on error
3033 * and doesn't set errno. Make it behave like fallocate()
3034 * which returns -1, and sets errno on failure.
3041 /* sys_fallocate handles filtering of unsupported mode flags */
3042 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3044 END_PROFILE(syscall_fallocate);
3048 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3052 START_PROFILE(syscall_fcntl_lock);
3054 if (fsp->fsp_flags.use_ofd_locks) {
3055 op = map_process_lock_to_ofd_lock(op);
3058 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3059 END_PROFILE(syscall_fcntl_lock);
3063 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3065 uint32_t share_access,
3066 uint32_t access_mask)
3072 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3076 va_list dup_cmd_arg;
3080 START_PROFILE(syscall_fcntl);
3082 va_copy(dup_cmd_arg, cmd_arg);
3088 #if defined(HAVE_OFD_LOCKS)
3093 #if defined(HAVE_F_OWNER_EX)
3097 #if defined(HAVE_RW_HINTS)
3100 case F_GET_FILE_RW_HINT:
3101 case F_SET_FILE_RW_HINT:
3103 argp = va_arg(dup_cmd_arg, void *);
3104 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3107 val = va_arg(dup_cmd_arg, int);
3108 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3111 va_end(dup_cmd_arg);
3113 END_PROFILE(syscall_fcntl);
3117 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3122 START_PROFILE(syscall_fcntl_getlock);
3124 if (fsp->fsp_flags.use_ofd_locks) {
3125 op = map_process_lock_to_ofd_lock(op);
3128 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3129 END_PROFILE(syscall_fcntl_getlock);
3133 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3138 START_PROFILE(syscall_linux_setlease);
3140 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3142 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3143 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3147 END_PROFILE(syscall_linux_setlease);
3151 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3152 const struct smb_filename *link_target,
3153 struct files_struct *dirfsp,
3154 const struct smb_filename *new_smb_fname)
3158 START_PROFILE(syscall_symlinkat);
3160 SMB_ASSERT(!is_named_stream(new_smb_fname));
3162 result = symlinkat(link_target->base_name,
3163 fsp_get_pathref_fd(dirfsp),
3164 new_smb_fname->base_name);
3165 END_PROFILE(syscall_symlinkat);
3169 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3170 const struct files_struct *dirfsp,
3171 const struct smb_filename *smb_fname,
3177 START_PROFILE(syscall_readlinkat);
3179 SMB_ASSERT(!is_named_stream(smb_fname));
3181 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3182 smb_fname->base_name,
3186 END_PROFILE(syscall_readlinkat);
3190 static int vfswrap_linkat(vfs_handle_struct *handle,
3191 files_struct *srcfsp,
3192 const struct smb_filename *old_smb_fname,
3193 files_struct *dstfsp,
3194 const struct smb_filename *new_smb_fname,
3199 START_PROFILE(syscall_linkat);
3201 SMB_ASSERT(!is_named_stream(old_smb_fname));
3202 SMB_ASSERT(!is_named_stream(new_smb_fname));
3204 result = linkat(fsp_get_pathref_fd(srcfsp),
3205 old_smb_fname->base_name,
3206 fsp_get_pathref_fd(dstfsp),
3207 new_smb_fname->base_name,
3210 END_PROFILE(syscall_linkat);
3214 static int vfswrap_mknodat(vfs_handle_struct *handle,
3215 files_struct *dirfsp,
3216 const struct smb_filename *smb_fname,
3222 START_PROFILE(syscall_mknodat);
3224 SMB_ASSERT(!is_named_stream(smb_fname));
3226 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3227 smb_fname->base_name,
3231 END_PROFILE(syscall_mknodat);
3235 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3237 const struct smb_filename *smb_fname)
3240 struct smb_filename *result_fname = NULL;
3242 START_PROFILE(syscall_realpath);
3243 result = sys_realpath(smb_fname->base_name);
3244 END_PROFILE(syscall_realpath);
3246 result_fname = synthetic_smb_fname(ctx,
3254 return result_fname;
3257 static int vfswrap_fchflags(vfs_handle_struct *handle,
3258 struct files_struct *fsp,
3261 #ifdef HAVE_FCHFLAGS
3262 int fd = fsp_get_pathref_fd(fsp);
3264 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3266 if (!fsp->fsp_flags.is_pathref) {
3267 return fchflags(fd, flags);
3270 if (fsp->fsp_flags.have_proc_fds) {
3271 struct sys_proc_fd_path_buf buf;
3273 return chflags(sys_proc_fd_path(fd, &buf), flags);
3277 * This is no longer a handle based call.
3279 return chflags(fsp->fsp_name->base_name, flags);
3286 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3287 const SMB_STRUCT_STAT *sbuf)
3291 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3295 key.devid = sbuf->st_ex_dev;
3296 key.inode = sbuf->st_ex_ino;
3297 /* key.extid is unused by default. */
3302 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3303 const SMB_STRUCT_STAT *psbuf)
3307 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3308 return (uint64_t)psbuf->st_ex_ino;
3312 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3315 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3320 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3321 struct files_struct *fsp,
3322 TALLOC_CTX *mem_ctx,
3323 unsigned int *pnum_streams,
3324 struct stream_struct **pstreams)
3326 struct stream_struct *tmp_streams = NULL;
3327 unsigned int num_streams = *pnum_streams;
3328 struct stream_struct *streams = *pstreams;
3331 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3333 if (fsp->fsp_flags.is_directory) {
3335 * No default streams on directories
3339 status = vfs_stat_fsp(fsp);
3340 if (!NT_STATUS_IS_OK(status)) {
3344 if (num_streams + 1 < 1) {
3346 return NT_STATUS_INVALID_PARAMETER;
3349 tmp_streams = talloc_realloc(mem_ctx,
3351 struct stream_struct,
3353 if (tmp_streams == NULL) {
3354 return NT_STATUS_NO_MEMORY;
3356 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3357 if (tmp_streams[num_streams].name == NULL) {
3358 return NT_STATUS_NO_MEMORY;
3360 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3361 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3364 &fsp->fsp_name->st);
3367 *pnum_streams = num_streams;
3368 *pstreams = tmp_streams;
3370 return NT_STATUS_OK;
3373 static NTSTATUS vfswrap_get_real_filename_at(
3374 struct vfs_handle_struct *handle,
3375 struct files_struct *dirfsp,
3377 TALLOC_CTX *mem_ctx,
3381 * Don't fall back to get_real_filename so callers can differentiate
3382 * between a full directory scan and an actual case-insensitive stat.
3384 return NT_STATUS_NOT_SUPPORTED;
3387 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3388 const struct files_struct *dirfsp,
3389 const struct smb_filename *smb_fname)
3391 return handle->conn->connectpath;
3394 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3395 struct byte_range_lock *br_lck,
3396 struct lock_struct *plock)
3398 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3400 /* Note: blr is not used in the default implementation. */
3401 return brl_lock_windows_default(br_lck, plock);
3404 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3405 struct byte_range_lock *br_lck,
3406 const struct lock_struct *plock)
3408 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3410 return brl_unlock_windows_default(br_lck, plock);
3413 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3415 struct lock_struct *plock)
3417 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3418 plock->lock_type == WRITE_LOCK);
3420 return strict_lock_check_default(fsp, plock);
3423 /* NT ACL operations. */
3425 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3427 uint32_t security_info,
3428 TALLOC_CTX *mem_ctx,
3429 struct security_descriptor **ppdesc)
3433 START_PROFILE(fget_nt_acl);
3435 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3437 result = posix_fget_nt_acl(fsp, security_info,
3439 END_PROFILE(fget_nt_acl);
3443 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3447 START_PROFILE(fset_nt_acl);
3449 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3451 result = set_nt_acl(fsp, security_info_sent, psd);
3452 END_PROFILE(fset_nt_acl);
3456 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3457 struct smb_filename *file,
3458 struct security_acl *sacl,
3459 uint32_t access_requested,
3460 uint32_t access_denied)
3462 return NT_STATUS_OK; /* Nothing to do here ... */
3465 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3467 SMB_ACL_TYPE_T type,
3468 TALLOC_CTX *mem_ctx)
3470 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3472 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3475 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3477 SMB_ACL_TYPE_T type,
3480 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3482 return sys_acl_set_fd(handle, fsp, type, theacl);
3485 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3488 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3490 return sys_acl_delete_def_fd(handle, fsp);
3493 /****************************************************************
3494 Extended attribute operations.
3495 *****************************************************************/
3497 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3498 struct files_struct *fsp,
3503 int fd = fsp_get_pathref_fd(fsp);
3505 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3507 if (!fsp->fsp_flags.is_pathref) {
3508 return fgetxattr(fd, name, value, size);
3511 if (fsp->fsp_flags.have_proc_fds) {
3512 struct sys_proc_fd_path_buf buf;
3514 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3518 * This is no longer a handle based call.
3520 return getxattr(fsp->fsp_name->base_name, name, value, size);
3523 struct vfswrap_getxattrat_state {
3524 struct tevent_context *ev;
3525 struct vfs_handle_struct *handle;
3526 files_struct *dir_fsp;
3527 const struct smb_filename *smb_fname;
3530 * The following variables are talloced off "state" which is protected
3531 * by a destructor and thus are guaranteed to be safe to be used in the
3532 * job function in the worker thread.
3535 const char *xattr_name;
3536 uint8_t *xattr_value;
3537 struct security_unix_token *token;
3540 struct vfs_aio_state vfs_aio_state;
3541 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3544 static int vfswrap_getxattrat_state_destructor(
3545 struct vfswrap_getxattrat_state *state)
3550 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3551 static void vfswrap_getxattrat_do_async(void *private_data);
3552 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3554 static struct tevent_req *vfswrap_getxattrat_send(
3555 TALLOC_CTX *mem_ctx,
3556 struct tevent_context *ev,
3557 struct vfs_handle_struct *handle,
3558 files_struct *dir_fsp,
3559 const struct smb_filename *smb_fname,
3560 const char *xattr_name,
3563 struct tevent_req *req = NULL;
3564 struct tevent_req *subreq = NULL;
3565 struct vfswrap_getxattrat_state *state = NULL;
3566 size_t max_threads = 0;
3567 bool have_per_thread_cwd = false;
3568 bool have_per_thread_creds = false;
3569 bool do_async = false;
3571 SMB_ASSERT(!is_named_stream(smb_fname));
3573 req = tevent_req_create(mem_ctx, &state,
3574 struct vfswrap_getxattrat_state);
3578 *state = (struct vfswrap_getxattrat_state) {
3582 .smb_fname = smb_fname,
3585 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3586 if (max_threads >= 1) {
3588 * We need a non sync threadpool!
3590 have_per_thread_cwd = per_thread_cwd_supported();
3592 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3593 have_per_thread_creds = true;
3595 if (have_per_thread_cwd && have_per_thread_creds) {
3599 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3600 state->profile_bytes, 0);
3602 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3603 DBG_ERR("Need a valid directory fd\n");
3604 tevent_req_error(req, EINVAL);
3605 return tevent_req_post(req, ev);
3608 if (alloc_hint > 0) {
3609 state->xattr_value = talloc_zero_array(state,
3612 if (tevent_req_nomem(state->xattr_value, req)) {
3613 return tevent_req_post(req, ev);
3618 vfswrap_getxattrat_do_sync(req);
3619 return tevent_req_post(req, ev);
3623 * Now allocate all parameters from a memory context that won't go away
3624 * no matter what. These parameters will get used in threads and we
3625 * can't reliably cancel threads, so all buffers passed to the threads
3626 * must not be freed before all referencing threads terminate.
3629 state->name = talloc_strdup(state, smb_fname->base_name);
3630 if (tevent_req_nomem(state->name, req)) {
3631 return tevent_req_post(req, ev);
3634 state->xattr_name = talloc_strdup(state, xattr_name);
3635 if (tevent_req_nomem(state->xattr_name, req)) {
3636 return tevent_req_post(req, ev);
3640 * This is a hot codepath so at first glance one might think we should
3641 * somehow optimize away the token allocation and do a
3642 * talloc_reference() or similar black magic instead. But due to the
3643 * talloc_stackframe pool per SMB2 request this should be a simple copy
3644 * without a malloc in most cases.
3646 if (geteuid() == sec_initial_uid()) {
3647 state->token = root_unix_token(state);
3649 state->token = copy_unix_token(
3651 dir_fsp->conn->session_info->unix_token);
3653 if (tevent_req_nomem(state->token, req)) {
3654 return tevent_req_post(req, ev);
3657 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3659 subreq = pthreadpool_tevent_job_send(
3662 dir_fsp->conn->sconn->pool,
3663 vfswrap_getxattrat_do_async,
3665 if (tevent_req_nomem(subreq, req)) {
3666 return tevent_req_post(req, ev);
3668 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3670 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3675 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3677 struct vfswrap_getxattrat_state *state = tevent_req_data(
3678 req, struct vfswrap_getxattrat_state);
3680 state->xattr_size = vfswrap_fgetxattr(state->handle,
3681 state->smb_fname->fsp,
3684 talloc_array_length(state->xattr_value));
3685 if (state->xattr_size == -1) {
3686 tevent_req_error(req, errno);
3690 tevent_req_done(req);
3694 static void vfswrap_getxattrat_do_async(void *private_data)
3696 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3697 private_data, struct vfswrap_getxattrat_state);
3698 struct timespec start_time;
3699 struct timespec end_time;
3702 PROFILE_TIMESTAMP(&start_time);
3703 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3706 * Here we simulate a getxattrat()
3707 * call using fchdir();getxattr()
3710 per_thread_cwd_activate();
3712 /* Become the correct credential on this thread. */
3713 ret = set_thread_credentials(state->token->uid,
3715 (size_t)state->token->ngroups,
3716 state->token->groups);
3718 state->xattr_size = -1;
3719 state->vfs_aio_state.error = errno;
3723 state->xattr_size = vfswrap_fgetxattr(state->handle,
3724 state->smb_fname->fsp,
3727 talloc_array_length(state->xattr_value));
3728 if (state->xattr_size == -1) {
3729 state->vfs_aio_state.error = errno;
3733 PROFILE_TIMESTAMP(&end_time);
3734 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3735 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3738 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3740 struct tevent_req *req = tevent_req_callback_data(
3741 subreq, struct tevent_req);
3742 struct vfswrap_getxattrat_state *state = tevent_req_data(
3743 req, struct vfswrap_getxattrat_state);
3748 * Make sure we run as the user again
3750 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3753 ret = pthreadpool_tevent_job_recv(subreq);
3754 TALLOC_FREE(subreq);
3755 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3756 talloc_set_destructor(state, NULL);
3758 if (ret != EAGAIN) {
3759 tevent_req_error(req, ret);
3763 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3764 * means the lower level pthreadpool failed to create a new
3765 * thread. Fallback to sync processing in that case to allow
3766 * some progress for the client.
3768 vfswrap_getxattrat_do_sync(req);
3772 if (state->xattr_size == -1) {
3773 tevent_req_error(req, state->vfs_aio_state.error);
3777 if (state->xattr_value == NULL) {
3779 * The caller only wanted the size.
3781 tevent_req_done(req);
3786 * shrink the buffer to the returned size.
3787 * (can't fail). It means NULL if size is 0.
3789 state->xattr_value = talloc_realloc(state,
3794 tevent_req_done(req);
3797 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3798 struct vfs_aio_state *aio_state,
3799 TALLOC_CTX *mem_ctx,
3800 uint8_t **xattr_value)
3802 struct vfswrap_getxattrat_state *state = tevent_req_data(
3803 req, struct vfswrap_getxattrat_state);
3806 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3807 tevent_req_received(req);
3811 *aio_state = state->vfs_aio_state;
3812 xattr_size = state->xattr_size;
3813 if (xattr_value != NULL) {
3814 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3817 tevent_req_received(req);
3821 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3823 int fd = fsp_get_pathref_fd(fsp);
3825 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3827 if (!fsp->fsp_flags.is_pathref) {
3828 return flistxattr(fd, list, size);
3831 if (fsp->fsp_flags.have_proc_fds) {
3832 struct sys_proc_fd_path_buf buf;
3834 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3838 * This is no longer a handle based call.
3840 return listxattr(fsp->fsp_name->base_name, list, size);
3843 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3845 int fd = fsp_get_pathref_fd(fsp);
3847 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3849 if (!fsp->fsp_flags.is_pathref) {
3850 return fremovexattr(fd, name);
3853 if (fsp->fsp_flags.have_proc_fds) {
3854 struct sys_proc_fd_path_buf buf;
3856 return removexattr(sys_proc_fd_path(fd, &buf), name);
3860 * This is no longer a handle based call.
3862 return removexattr(fsp->fsp_name->base_name, name);
3865 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3867 int fd = fsp_get_pathref_fd(fsp);
3869 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3871 if (!fsp->fsp_flags.is_pathref) {
3872 return fsetxattr(fd, name, value, size, flags);
3875 if (fsp->fsp_flags.have_proc_fds) {
3876 struct sys_proc_fd_path_buf buf;
3878 return setxattr(sys_proc_fd_path(fd, &buf),
3886 * This is no longer a handle based call.
3888 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3891 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3896 static bool vfswrap_is_offline(struct connection_struct *conn,
3897 const struct smb_filename *fname)
3901 bool offline = false;
3903 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3907 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3908 #if defined(ENOTSUP)
3914 status = get_full_smb_filename(talloc_tos(), fname, &path);
3915 if (!NT_STATUS_IS_OK(status)) {
3916 errno = map_errno_from_nt_status(status);
3920 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3927 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3928 struct files_struct *fsp,
3929 TALLOC_CTX *mem_ctx,
3932 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3935 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3936 struct files_struct *fsp,
3937 const DATA_BLOB old_cookie,
3938 TALLOC_CTX *mem_ctx,
3939 DATA_BLOB *new_cookie)
3941 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3945 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3946 struct smb_request *smb1req,
3947 struct smbXsrv_open *op,
3948 const DATA_BLOB old_cookie,
3949 TALLOC_CTX *mem_ctx,
3950 struct files_struct **fsp,
3951 DATA_BLOB *new_cookie)
3953 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3954 old_cookie, mem_ctx,
3958 static struct vfs_fn_pointers vfs_default_fns = {
3959 /* Disk operations */
3961 .connect_fn = vfswrap_connect,
3962 .disconnect_fn = vfswrap_disconnect,
3963 .disk_free_fn = vfswrap_disk_free,
3964 .get_quota_fn = vfswrap_get_quota,
3965 .set_quota_fn = vfswrap_set_quota,
3966 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3967 .statvfs_fn = vfswrap_statvfs,
3968 .fs_capabilities_fn = vfswrap_fs_capabilities,
3969 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3970 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3971 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3972 .snap_check_path_fn = vfswrap_snap_check_path,
3973 .snap_create_fn = vfswrap_snap_create,
3974 .snap_delete_fn = vfswrap_snap_delete,
3976 /* Directory operations */
3978 .fdopendir_fn = vfswrap_fdopendir,
3979 .readdir_fn = vfswrap_readdir,
3980 .freaddir_attr_fn = vfswrap_freaddir_attr,
3981 .rewind_dir_fn = vfswrap_rewinddir,
3982 .mkdirat_fn = vfswrap_mkdirat,
3983 .closedir_fn = vfswrap_closedir,
3985 /* File operations */
3987 .openat_fn = vfswrap_openat,
3988 .create_file_fn = vfswrap_create_file,
3989 .close_fn = vfswrap_close,
3990 .pread_fn = vfswrap_pread,
3991 .pread_send_fn = vfswrap_pread_send,
3992 .pread_recv_fn = vfswrap_pread_recv,
3993 .pwrite_fn = vfswrap_pwrite,
3994 .pwrite_send_fn = vfswrap_pwrite_send,
3995 .pwrite_recv_fn = vfswrap_pwrite_recv,
3996 .lseek_fn = vfswrap_lseek,
3997 .sendfile_fn = vfswrap_sendfile,
3998 .recvfile_fn = vfswrap_recvfile,
3999 .renameat_fn = vfswrap_renameat,
4000 .fsync_send_fn = vfswrap_fsync_send,
4001 .fsync_recv_fn = vfswrap_fsync_recv,
4002 .stat_fn = vfswrap_stat,
4003 .fstat_fn = vfswrap_fstat,
4004 .lstat_fn = vfswrap_lstat,
4005 .fstatat_fn = vfswrap_fstatat,
4006 .get_alloc_size_fn = vfswrap_get_alloc_size,
4007 .unlinkat_fn = vfswrap_unlinkat,
4008 .fchmod_fn = vfswrap_fchmod,
4009 .fchown_fn = vfswrap_fchown,
4010 .lchown_fn = vfswrap_lchown,
4011 .chdir_fn = vfswrap_chdir,
4012 .getwd_fn = vfswrap_getwd,
4013 .fntimes_fn = vfswrap_fntimes,
4014 .ftruncate_fn = vfswrap_ftruncate,
4015 .fallocate_fn = vfswrap_fallocate,
4016 .lock_fn = vfswrap_lock,
4017 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4018 .fcntl_fn = vfswrap_fcntl,
4019 .linux_setlease_fn = vfswrap_linux_setlease,
4020 .getlock_fn = vfswrap_getlock,
4021 .symlinkat_fn = vfswrap_symlinkat,
4022 .readlinkat_fn = vfswrap_readlinkat,
4023 .linkat_fn = vfswrap_linkat,
4024 .mknodat_fn = vfswrap_mknodat,
4025 .realpath_fn = vfswrap_realpath,
4026 .fchflags_fn = vfswrap_fchflags,
4027 .file_id_create_fn = vfswrap_file_id_create,
4028 .fs_file_id_fn = vfswrap_fs_file_id,
4029 .fstreaminfo_fn = vfswrap_fstreaminfo,
4030 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4031 .connectpath_fn = vfswrap_connectpath,
4032 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4033 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4034 .strict_lock_check_fn = vfswrap_strict_lock_check,
4035 .translate_name_fn = vfswrap_translate_name,
4036 .parent_pathname_fn = vfswrap_parent_pathname,
4037 .fsctl_fn = vfswrap_fsctl,
4038 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4039 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4040 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4041 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4042 .offload_read_send_fn = vfswrap_offload_read_send,
4043 .offload_read_recv_fn = vfswrap_offload_read_recv,
4044 .offload_write_send_fn = vfswrap_offload_write_send,
4045 .offload_write_recv_fn = vfswrap_offload_write_recv,
4046 .fget_compression_fn = vfswrap_fget_compression,
4047 .set_compression_fn = vfswrap_set_compression,
4049 /* NT ACL operations. */
4051 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4052 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4053 .audit_file_fn = vfswrap_audit_file,
4055 /* POSIX ACL operations. */
4057 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4058 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4059 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4060 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4062 /* EA operations. */
4063 .getxattrat_send_fn = vfswrap_getxattrat_send,
4064 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4065 .fgetxattr_fn = vfswrap_fgetxattr,
4066 .flistxattr_fn = vfswrap_flistxattr,
4067 .fremovexattr_fn = vfswrap_fremovexattr,
4068 .fsetxattr_fn = vfswrap_fsetxattr,
4070 /* aio operations */
4071 .aio_force_fn = vfswrap_aio_force,
4073 /* durable handle operations */
4074 .durable_cookie_fn = vfswrap_durable_cookie,
4075 .durable_disconnect_fn = vfswrap_durable_disconnect,
4076 .durable_reconnect_fn = vfswrap_durable_reconnect,
4080 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4083 * Here we need to implement every call!
4085 * As this is the end of the vfs module chain.
4087 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4088 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4089 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);