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 DEBUG(10,("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),
208 conn->connectpath ));
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;
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';
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 DEBUG(0,("Invalid dfs referral version: %d\n",
387 max_referral_level));
388 return NT_STATUS_INVALID_LEVEL;
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);
598 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
599 struct files_struct *dirfsp,
601 SMB_STRUCT_STAT *sbuf)
603 struct dirent *result;
604 bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
605 int flags = AT_SYMLINK_NOFOLLOW;
609 START_PROFILE(syscall_readdir);
611 result = readdir(dirp);
612 END_PROFILE(syscall_readdir);
617 if (result == NULL) {
622 * Default Posix readdir() does not give us stat info.
623 * Set to invalid to indicate we didn't return this info.
625 SET_STAT_INVALID(*sbuf);
627 ret = sys_fstatat(dirfd(dirp),
637 * As this is an optimization, ignore it if we stat'ed a
638 * symlink for non-POSIX context. Make the caller do it again
639 * as we don't know if they wanted the link info, or its
642 if (S_ISLNK(st.st_ex_mode) &&
643 !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
652 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
653 struct files_struct *fsp,
655 struct readdir_attr_data **attr_data)
657 return NT_STATUS_NOT_SUPPORTED;
660 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
662 START_PROFILE(syscall_seekdir);
663 seekdir(dirp, offset);
664 END_PROFILE(syscall_seekdir);
667 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
670 START_PROFILE(syscall_telldir);
671 result = telldir(dirp);
672 END_PROFILE(syscall_telldir);
676 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
678 START_PROFILE(syscall_rewinddir);
680 END_PROFILE(syscall_rewinddir);
683 static int vfswrap_mkdirat(vfs_handle_struct *handle,
684 struct files_struct *dirfsp,
685 const struct smb_filename *smb_fname,
690 START_PROFILE(syscall_mkdirat);
692 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
694 END_PROFILE(syscall_mkdirat);
698 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
702 START_PROFILE(syscall_closedir);
703 result = closedir(dirp);
704 END_PROFILE(syscall_closedir);
708 /* File operations */
710 static int vfswrap_openat(vfs_handle_struct *handle,
711 const struct files_struct *dirfsp,
712 const struct smb_filename *smb_fname,
714 const struct vfs_open_how *how)
716 int flags = how->flags;
717 mode_t mode = how->mode;
718 bool have_opath = false;
719 bool became_root = false;
722 START_PROFILE(syscall_openat);
724 if (how->resolve & ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
730 SMB_ASSERT(!is_named_stream(smb_fname));
734 if (fsp->fsp_flags.is_pathref) {
737 if (flags & O_PATH) {
739 * From "man 2 openat":
741 * When O_PATH is specified in flags, flag bits other than
742 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
744 * From "man 2 openat2":
746 * Whereas openat(2) ignores unknown bits in its flags
747 * argument, openat2() returns an error if unknown or
748 * conflicting flags are specified in how.flags.
750 * So we better clear ignored/invalid flags
751 * and only keep the exptected once.
753 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
757 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
758 struct open_how linux_how = {
761 .resolve = RESOLVE_NO_SYMLINKS,
764 result = openat2(fsp_get_pathref_fd(dirfsp),
765 smb_fname->base_name,
769 if (errno == ENOSYS) {
771 * The kernel doesn't support
772 * openat2(), so indicate to
774 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
775 * would just be a waste of time.
777 fsp->conn->open_how_resolve &=
778 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
786 if (fsp->fsp_flags.is_pathref && !have_opath) {
791 result = openat(fsp_get_pathref_fd(dirfsp),
792 smb_fname->base_name,
801 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
804 END_PROFILE(syscall_openat);
807 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
808 struct smb_request *req,
809 struct files_struct *dirfsp,
810 struct smb_filename *smb_fname,
811 uint32_t access_mask,
812 uint32_t share_access,
813 uint32_t create_disposition,
814 uint32_t create_options,
815 uint32_t file_attributes,
816 uint32_t oplock_request,
817 const struct smb2_lease *lease,
818 uint64_t allocation_size,
819 uint32_t private_flags,
820 struct security_descriptor *sd,
821 struct ea_list *ea_list,
822 files_struct **result,
824 const struct smb2_create_blobs *in_context_blobs,
825 struct smb2_create_blobs *out_context_blobs)
827 return create_file_default(handle->conn, req, dirfsp, smb_fname,
828 access_mask, share_access,
829 create_disposition, create_options,
830 file_attributes, oplock_request, lease,
831 allocation_size, private_flags,
833 pinfo, in_context_blobs, out_context_blobs);
836 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
840 START_PROFILE(syscall_close);
841 result = fd_close_posix(fsp);
842 END_PROFILE(syscall_close);
846 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
847 size_t n, off_t offset)
851 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
852 START_PROFILE_BYTES(syscall_pread, n);
853 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
854 END_PROFILE_BYTES(syscall_pread);
856 if (result == -1 && errno == ESPIPE) {
857 /* Maintain the fiction that pipes can be seeked (sought?) on. */
858 result = sys_read(fsp_get_io_fd(fsp), data, n);
859 fh_set_pos(fsp->fh, 0);
862 #else /* HAVE_PREAD */
865 #endif /* HAVE_PREAD */
870 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
871 size_t n, off_t offset)
875 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
876 START_PROFILE_BYTES(syscall_pwrite, n);
877 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
878 END_PROFILE_BYTES(syscall_pwrite);
880 if (result == -1 && errno == ESPIPE) {
881 /* Maintain the fiction that pipes can be sought on. */
882 result = sys_write(fsp_get_io_fd(fsp), data, n);
885 #else /* HAVE_PWRITE */
888 #endif /* HAVE_PWRITE */
893 struct vfswrap_pread_state {
900 struct vfs_aio_state vfs_aio_state;
901 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
904 static void vfs_pread_do(void *private_data);
905 static void vfs_pread_done(struct tevent_req *subreq);
906 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
908 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
910 struct tevent_context *ev,
911 struct files_struct *fsp,
913 size_t n, off_t offset)
915 struct tevent_req *req, *subreq;
916 struct vfswrap_pread_state *state;
918 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
924 state->fd = fsp_get_io_fd(fsp);
927 state->offset = offset;
929 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
930 state->profile_bytes, n);
931 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
933 subreq = pthreadpool_tevent_job_send(
934 state, ev, handle->conn->sconn->pool,
935 vfs_pread_do, state);
936 if (tevent_req_nomem(subreq, req)) {
937 return tevent_req_post(req, ev);
939 tevent_req_set_callback(subreq, vfs_pread_done, req);
941 talloc_set_destructor(state, vfs_pread_state_destructor);
946 static void vfs_pread_do(void *private_data)
948 struct vfswrap_pread_state *state = talloc_get_type_abort(
949 private_data, struct vfswrap_pread_state);
950 struct timespec start_time;
951 struct timespec end_time;
953 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
955 PROFILE_TIMESTAMP(&start_time);
957 state->ret = sys_pread_full(state->fd,
962 if (state->ret == -1) {
963 state->vfs_aio_state.error = errno;
966 PROFILE_TIMESTAMP(&end_time);
968 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
970 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
973 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
978 static void vfs_pread_done(struct tevent_req *subreq)
980 struct tevent_req *req = tevent_req_callback_data(
981 subreq, struct tevent_req);
982 struct vfswrap_pread_state *state = tevent_req_data(
983 req, struct vfswrap_pread_state);
986 ret = pthreadpool_tevent_job_recv(subreq);
988 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
989 talloc_set_destructor(state, NULL);
992 tevent_req_error(req, ret);
996 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
997 * means the lower level pthreadpool failed to create a new
998 * thread. Fallback to sync processing in that case to allow
999 * some progress for the client.
1001 vfs_pread_do(state);
1004 tevent_req_done(req);
1007 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
1008 struct vfs_aio_state *vfs_aio_state)
1010 struct vfswrap_pread_state *state = tevent_req_data(
1011 req, struct vfswrap_pread_state);
1013 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1017 *vfs_aio_state = state->vfs_aio_state;
1021 struct vfswrap_pwrite_state {
1028 struct vfs_aio_state vfs_aio_state;
1029 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1032 static void vfs_pwrite_do(void *private_data);
1033 static void vfs_pwrite_done(struct tevent_req *subreq);
1034 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
1036 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
1037 TALLOC_CTX *mem_ctx,
1038 struct tevent_context *ev,
1039 struct files_struct *fsp,
1041 size_t n, off_t offset)
1043 struct tevent_req *req, *subreq;
1044 struct vfswrap_pwrite_state *state;
1046 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1052 state->fd = fsp_get_io_fd(fsp);
1055 state->offset = offset;
1057 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1058 state->profile_bytes, n);
1059 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1061 subreq = pthreadpool_tevent_job_send(
1062 state, ev, handle->conn->sconn->pool,
1063 vfs_pwrite_do, state);
1064 if (tevent_req_nomem(subreq, req)) {
1065 return tevent_req_post(req, ev);
1067 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1069 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1074 static void vfs_pwrite_do(void *private_data)
1076 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1077 private_data, struct vfswrap_pwrite_state);
1078 struct timespec start_time;
1079 struct timespec end_time;
1081 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1083 PROFILE_TIMESTAMP(&start_time);
1085 state->ret = sys_pwrite_full(state->fd,
1090 if (state->ret == -1) {
1091 state->vfs_aio_state.error = errno;
1094 PROFILE_TIMESTAMP(&end_time);
1096 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1098 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1101 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1106 static void vfs_pwrite_done(struct tevent_req *subreq)
1108 struct tevent_req *req = tevent_req_callback_data(
1109 subreq, struct tevent_req);
1110 struct vfswrap_pwrite_state *state = tevent_req_data(
1111 req, struct vfswrap_pwrite_state);
1114 ret = pthreadpool_tevent_job_recv(subreq);
1115 TALLOC_FREE(subreq);
1116 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1117 talloc_set_destructor(state, NULL);
1119 if (ret != EAGAIN) {
1120 tevent_req_error(req, ret);
1124 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1125 * means the lower level pthreadpool failed to create a new
1126 * thread. Fallback to sync processing in that case to allow
1127 * some progress for the client.
1129 vfs_pwrite_do(state);
1132 tevent_req_done(req);
1135 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1136 struct vfs_aio_state *vfs_aio_state)
1138 struct vfswrap_pwrite_state *state = tevent_req_data(
1139 req, struct vfswrap_pwrite_state);
1141 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1145 *vfs_aio_state = state->vfs_aio_state;
1149 struct vfswrap_fsync_state {
1153 struct vfs_aio_state vfs_aio_state;
1154 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1157 static void vfs_fsync_do(void *private_data);
1158 static void vfs_fsync_done(struct tevent_req *subreq);
1159 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1161 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1162 TALLOC_CTX *mem_ctx,
1163 struct tevent_context *ev,
1164 struct files_struct *fsp)
1166 struct tevent_req *req, *subreq;
1167 struct vfswrap_fsync_state *state;
1169 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1175 state->fd = fsp_get_io_fd(fsp);
1177 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1178 state->profile_bytes, 0);
1179 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1181 subreq = pthreadpool_tevent_job_send(
1182 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1183 if (tevent_req_nomem(subreq, req)) {
1184 return tevent_req_post(req, ev);
1186 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1188 talloc_set_destructor(state, vfs_fsync_state_destructor);
1193 static void vfs_fsync_do(void *private_data)
1195 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1196 private_data, struct vfswrap_fsync_state);
1197 struct timespec start_time;
1198 struct timespec end_time;
1200 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1202 PROFILE_TIMESTAMP(&start_time);
1205 state->ret = fsync(state->fd);
1206 } while ((state->ret == -1) && (errno == EINTR));
1208 if (state->ret == -1) {
1209 state->vfs_aio_state.error = errno;
1212 PROFILE_TIMESTAMP(&end_time);
1214 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1216 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1219 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1224 static void vfs_fsync_done(struct tevent_req *subreq)
1226 struct tevent_req *req = tevent_req_callback_data(
1227 subreq, struct tevent_req);
1228 struct vfswrap_fsync_state *state = tevent_req_data(
1229 req, struct vfswrap_fsync_state);
1232 ret = pthreadpool_tevent_job_recv(subreq);
1233 TALLOC_FREE(subreq);
1234 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1235 talloc_set_destructor(state, NULL);
1237 if (ret != EAGAIN) {
1238 tevent_req_error(req, ret);
1242 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1243 * means the lower level pthreadpool failed to create a new
1244 * thread. Fallback to sync processing in that case to allow
1245 * some progress for the client.
1247 vfs_fsync_do(state);
1250 tevent_req_done(req);
1253 static int vfswrap_fsync_recv(struct tevent_req *req,
1254 struct vfs_aio_state *vfs_aio_state)
1256 struct vfswrap_fsync_state *state = tevent_req_data(
1257 req, struct vfswrap_fsync_state);
1259 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1263 *vfs_aio_state = state->vfs_aio_state;
1267 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1271 START_PROFILE(syscall_lseek);
1273 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1275 * We want to maintain the fiction that we can seek
1276 * on a fifo for file system purposes. This allows
1277 * people to set up UNIX fifo's that feed data to Windows
1278 * applications. JRA.
1281 if((result == -1) && (errno == ESPIPE)) {
1286 END_PROFILE(syscall_lseek);
1290 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1291 off_t offset, size_t n)
1295 START_PROFILE_BYTES(syscall_sendfile, n);
1296 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1297 END_PROFILE_BYTES(syscall_sendfile);
1301 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1303 files_struct *tofsp,
1309 START_PROFILE_BYTES(syscall_recvfile, n);
1310 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1311 END_PROFILE_BYTES(syscall_recvfile);
1315 static int vfswrap_renameat(vfs_handle_struct *handle,
1316 files_struct *srcfsp,
1317 const struct smb_filename *smb_fname_src,
1318 files_struct *dstfsp,
1319 const struct smb_filename *smb_fname_dst)
1323 START_PROFILE(syscall_renameat);
1325 SMB_ASSERT(!is_named_stream(smb_fname_src));
1326 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1328 result = renameat(fsp_get_pathref_fd(srcfsp),
1329 smb_fname_src->base_name,
1330 fsp_get_pathref_fd(dstfsp),
1331 smb_fname_dst->base_name);
1333 END_PROFILE(syscall_renameat);
1337 static int vfswrap_stat(vfs_handle_struct *handle,
1338 struct smb_filename *smb_fname)
1342 START_PROFILE(syscall_stat);
1344 SMB_ASSERT(!is_named_stream(smb_fname));
1346 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1347 lp_fake_directory_create_times(SNUM(handle->conn)));
1349 END_PROFILE(syscall_stat);
1353 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1357 START_PROFILE(syscall_fstat);
1358 result = sys_fstat(fsp_get_pathref_fd(fsp),
1359 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1360 END_PROFILE(syscall_fstat);
1364 static int vfswrap_lstat(vfs_handle_struct *handle,
1365 struct smb_filename *smb_fname)
1369 START_PROFILE(syscall_lstat);
1371 SMB_ASSERT(!is_named_stream(smb_fname));
1373 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1374 lp_fake_directory_create_times(SNUM(handle->conn)));
1376 END_PROFILE(syscall_lstat);
1380 static int vfswrap_fstatat(
1381 struct vfs_handle_struct *handle,
1382 const struct files_struct *dirfsp,
1383 const struct smb_filename *smb_fname,
1384 SMB_STRUCT_STAT *sbuf,
1389 START_PROFILE(syscall_fstatat);
1391 SMB_ASSERT(!is_named_stream(smb_fname));
1393 result = sys_fstatat(
1394 fsp_get_pathref_fd(dirfsp),
1395 smb_fname->base_name,
1398 lp_fake_directory_create_times(SNUM(handle->conn)));
1400 END_PROFILE(syscall_fstatat);
1404 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1406 enum vfs_translate_direction direction,
1407 TALLOC_CTX *mem_ctx,
1410 return NT_STATUS_NONE_MAPPED;
1414 * Return allocated parent directory and basename of path
1416 * Note: if requesting atname, it is returned as talloc child of the
1417 * parent. Freeing the parent is thus sufficient to free both.
1419 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1420 TALLOC_CTX *mem_ctx,
1421 const struct smb_filename *smb_fname_in,
1422 struct smb_filename **parent_dir_out,
1423 struct smb_filename **atname_out)
1425 TALLOC_CTX *frame = talloc_stackframe();
1426 struct smb_filename *parent = NULL;
1427 struct smb_filename *name = NULL;
1430 parent = cp_smb_filename_nostream(frame, smb_fname_in);
1431 if (parent == NULL) {
1433 return NT_STATUS_NO_MEMORY;
1435 SET_STAT_INVALID(parent->st);
1437 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1439 TALLOC_FREE(parent->base_name);
1440 parent->base_name = talloc_strdup(parent, ".");
1441 if (parent->base_name == NULL) {
1443 return NT_STATUS_NO_MEMORY;
1445 p = smb_fname_in->base_name;
1451 if (atname_out == NULL) {
1452 *parent_dir_out = talloc_move(mem_ctx, &parent);
1454 return NT_STATUS_OK;
1457 name = cp_smb_filename(frame, smb_fname_in);
1460 return NT_STATUS_NO_MEMORY;
1462 TALLOC_FREE(name->base_name);
1464 name->base_name = talloc_strdup(name, p);
1465 if (name->base_name == NULL) {
1467 return NT_STATUS_NO_MEMORY;
1470 *parent_dir_out = talloc_move(mem_ctx, &parent);
1471 *atname_out = talloc_move(*parent_dir_out, &name);
1473 return NT_STATUS_OK;
1477 * Implement the default fsctl operation.
1479 static bool vfswrap_logged_ioctl_message = false;
1481 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1482 struct files_struct *fsp,
1485 uint16_t req_flags, /* Needed for UNICODE ... */
1486 const uint8_t *_in_data,
1488 uint8_t **_out_data,
1489 uint32_t max_out_len,
1492 const char *in_data = (const char *)_in_data;
1493 char **out_data = (char **)_out_data;
1496 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1499 case FSCTL_SET_SPARSE:
1501 bool set_sparse = true;
1503 if (in_len >= 1 && in_data[0] == 0) {
1507 status = file_set_sparse(handle->conn, fsp, set_sparse);
1509 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1510 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1511 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1512 nt_errstr(status)));
1517 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1519 unsigned char objid[16];
1520 char *return_data = NULL;
1522 /* This should return the object-id on this file.
1523 * I think I'll make this be the inode+dev. JRA.
1526 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1527 fsp_fnum_dbg(fsp)));
1529 *out_len = MIN(max_out_len, 64);
1531 /* Hmmm, will this cause problems if less data asked for? */
1532 return_data = talloc_array(ctx, char, 64);
1533 if (return_data == NULL) {
1534 return NT_STATUS_NO_MEMORY;
1537 /* For backwards compatibility only store the dev/inode. */
1538 push_file_id_16(return_data, &fsp->file_id);
1539 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1540 push_file_id_16(return_data+32, &fsp->file_id);
1541 memset(return_data+48, 0, 16);
1542 *out_data = return_data;
1543 return NT_STATUS_OK;
1546 case FSCTL_GET_REPARSE_POINT:
1548 status = fsctl_get_reparse_point(
1549 fsp, ctx, out_data, max_out_len, out_len);
1553 case FSCTL_SET_REPARSE_POINT:
1555 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1559 case FSCTL_DELETE_REPARSE_POINT:
1561 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1565 case FSCTL_GET_SHADOW_COPY_DATA:
1568 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1569 * and return their volume names. If max_data_count is 16, then it is just
1570 * asking for the number of volumes and length of the combined names.
1572 * pdata is the data allocated by our caller, but that uses
1573 * total_data_count (which is 0 in our case) rather than max_data_count.
1574 * Allocate the correct amount and return the pointer to let
1575 * it be deallocated when we return.
1577 struct shadow_copy_data *shadow_data = NULL;
1578 bool labels = False;
1579 uint32_t labels_data_count = 0;
1581 char *cur_pdata = NULL;
1583 if (max_out_len < 16) {
1584 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1586 return NT_STATUS_INVALID_PARAMETER;
1589 if (max_out_len > 16) {
1593 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1594 if (shadow_data == NULL) {
1595 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1596 return NT_STATUS_NO_MEMORY;
1600 * Call the VFS routine to actually do the work.
1602 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1605 /* broken module didn't set errno on error */
1606 status = NT_STATUS_UNSUCCESSFUL;
1608 status = map_nt_error_from_unix(errno);
1609 if (NT_STATUS_EQUAL(status,
1610 NT_STATUS_NOT_SUPPORTED)) {
1614 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1615 "connectpath %s, failed - %s.\n",
1616 fsp->conn->connectpath,
1617 nt_errstr(status)));
1618 TALLOC_FREE(shadow_data);
1622 labels_data_count = (shadow_data->num_volumes * 2 *
1623 sizeof(SHADOW_COPY_LABEL)) + 2;
1628 *out_len = 12 + labels_data_count;
1631 if (max_out_len < *out_len) {
1632 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1633 max_out_len, *out_len));
1634 TALLOC_FREE(shadow_data);
1635 return NT_STATUS_BUFFER_TOO_SMALL;
1638 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1639 if (cur_pdata == NULL) {
1640 TALLOC_FREE(shadow_data);
1641 return NT_STATUS_NO_MEMORY;
1644 *out_data = cur_pdata;
1646 /* num_volumes 4 bytes */
1647 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1650 /* num_labels 4 bytes */
1651 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1654 /* needed_data_count 4 bytes */
1655 SIVAL(cur_pdata, 8, labels_data_count);
1659 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1660 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1661 if (labels && shadow_data->labels) {
1662 for (i=0; i<shadow_data->num_volumes; i++) {
1664 status = srvstr_push(cur_pdata, req_flags,
1665 cur_pdata, shadow_data->labels[i],
1666 2 * sizeof(SHADOW_COPY_LABEL),
1667 STR_UNICODE|STR_TERMINATE, &len);
1668 if (!NT_STATUS_IS_OK(status)) {
1669 TALLOC_FREE(*out_data);
1670 TALLOC_FREE(shadow_data);
1673 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1674 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1678 TALLOC_FREE(shadow_data);
1680 return NT_STATUS_OK;
1683 case FSCTL_FIND_FILES_BY_SID:
1685 /* pretend this succeeded -
1687 * we have to send back a list with all files owned by this SID
1689 * but I have to check that --metze
1693 struct dom_sid_buf buf;
1697 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1698 fsp_fnum_dbg(fsp)));
1701 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1702 return NT_STATUS_INVALID_PARAMETER;
1705 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1707 /* unknown 4 bytes: this is not the length of the sid :-( */
1708 /*unknown = IVAL(pdata,0);*/
1710 ret = sid_parse(_in_data + 4, sid_len, &sid);
1712 return NT_STATUS_INVALID_PARAMETER;
1714 DEBUGADD(10, ("for SID: %s\n",
1715 dom_sid_str_buf(&sid, &buf)));
1717 if (!sid_to_uid(&sid, &uid)) {
1718 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1719 dom_sid_str_buf(&sid, &buf),
1720 (unsigned long)sid_len));
1724 /* we can take a look at the find source :-)
1726 * find ./ -uid $uid -name '*' is what we need here
1729 * and send 4bytes len and then NULL terminated unicode strings
1732 * but I don't know how to deal with the paged results
1733 * (maybe we can hang the result anywhere in the fsp struct)
1735 * but I don't know how to deal with the paged results
1736 * (maybe we can hang the result anywhere in the fsp struct)
1738 * we don't send all files at once
1739 * and at the next we should *not* start from the beginning,
1740 * so we have to cache the result
1745 /* this works for now... */
1746 return NT_STATUS_OK;
1749 case FSCTL_QUERY_ALLOCATED_RANGES:
1751 /* FIXME: This is just a dummy reply, telling that all of the
1752 * file is allocated. MKS cp needs that.
1753 * Adding the real allocated ranges via FIEMAP on Linux
1754 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1755 * this FSCTL correct for sparse files.
1757 uint64_t offset, length;
1758 char *out_data_tmp = NULL;
1761 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1763 return NT_STATUS_INVALID_PARAMETER;
1766 if (max_out_len < 16) {
1767 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1769 return NT_STATUS_INVALID_PARAMETER;
1772 offset = BVAL(in_data,0);
1773 length = BVAL(in_data,8);
1775 if (offset + length < offset) {
1776 /* No 64-bit integer wrap. */
1777 return NT_STATUS_INVALID_PARAMETER;
1780 /* Shouldn't this be SMB_VFS_STAT ... ? */
1781 status = vfs_stat_fsp(fsp);
1782 if (!NT_STATUS_IS_OK(status)) {
1787 out_data_tmp = talloc_array(ctx, char, *out_len);
1788 if (out_data_tmp == NULL) {
1789 DEBUG(10, ("unable to allocate memory for response\n"));
1790 return NT_STATUS_NO_MEMORY;
1793 if (offset > fsp->fsp_name->st.st_ex_size ||
1794 fsp->fsp_name->st.st_ex_size == 0 ||
1796 memset(out_data_tmp, 0, *out_len);
1798 uint64_t end = offset + length;
1799 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1800 SBVAL(out_data_tmp, 0, 0);
1801 SBVAL(out_data_tmp, 8, end);
1804 *out_data = out_data_tmp;
1806 return NT_STATUS_OK;
1809 case FSCTL_IS_VOLUME_DIRTY:
1811 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1812 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1814 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1815 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1817 return NT_STATUS_INVALID_PARAMETER;
1822 * Only print once ... unfortunately there could be lots of
1823 * different FSCTLs that are called.
1825 if (!vfswrap_logged_ioctl_message) {
1826 vfswrap_logged_ioctl_message = true;
1827 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1828 __func__, function));
1832 return NT_STATUS_NOT_SUPPORTED;
1835 static bool vfswrap_is_offline(struct connection_struct *conn,
1836 const struct smb_filename *fname);
1838 struct vfswrap_get_dos_attributes_state {
1839 struct vfs_aio_state aio_state;
1840 connection_struct *conn;
1841 TALLOC_CTX *mem_ctx;
1842 struct tevent_context *ev;
1843 files_struct *dir_fsp;
1844 struct smb_filename *smb_fname;
1849 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1851 static struct tevent_req *vfswrap_get_dos_attributes_send(
1852 TALLOC_CTX *mem_ctx,
1853 struct tevent_context *ev,
1854 struct vfs_handle_struct *handle,
1855 files_struct *dir_fsp,
1856 struct smb_filename *smb_fname)
1858 struct tevent_req *req = NULL;
1859 struct tevent_req *subreq = NULL;
1860 struct vfswrap_get_dos_attributes_state *state = NULL;
1862 SMB_ASSERT(!is_named_stream(smb_fname));
1864 req = tevent_req_create(mem_ctx, &state,
1865 struct vfswrap_get_dos_attributes_state);
1870 *state = (struct vfswrap_get_dos_attributes_state) {
1871 .conn = dir_fsp->conn,
1875 .smb_fname = smb_fname,
1878 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1879 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1880 "\"store dos attributes\" is disabled\n",
1881 dir_fsp->conn->connectpath);
1882 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1883 return tevent_req_post(req, ev);
1886 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1890 SAMBA_XATTR_DOS_ATTRIB,
1892 if (tevent_req_nomem(subreq, req)) {
1893 return tevent_req_post(req, ev);
1895 tevent_req_set_callback(subreq,
1896 vfswrap_get_dos_attributes_getxattr_done,
1902 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1904 struct tevent_req *req =
1905 tevent_req_callback_data(subreq,
1907 struct vfswrap_get_dos_attributes_state *state =
1908 tevent_req_data(req,
1909 struct vfswrap_get_dos_attributes_state);
1911 DATA_BLOB blob = {0};
1913 char *tofree = NULL;
1914 char pathbuf[PATH_MAX+1];
1916 struct smb_filename smb_fname;
1920 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1924 TALLOC_FREE(subreq);
1925 if (xattr_size == -1) {
1926 status = map_nt_error_from_unix(state->aio_state.error);
1928 if (state->as_root) {
1929 tevent_req_nterror(req, status);
1932 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1933 tevent_req_nterror(req, status);
1937 state->as_root = true;
1940 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1944 SAMBA_XATTR_DOS_ATTRIB,
1947 if (tevent_req_nomem(subreq, req)) {
1950 tevent_req_set_callback(subreq,
1951 vfswrap_get_dos_attributes_getxattr_done,
1956 blob.length = xattr_size;
1958 status = parse_dos_attribute_blob(state->smb_fname,
1961 if (!NT_STATUS_IS_OK(status)) {
1962 tevent_req_nterror(req, status);
1966 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1967 state->smb_fname->base_name,
1972 if (pathlen == -1) {
1973 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1977 smb_fname = (struct smb_filename) {
1979 .st = state->smb_fname->st,
1980 .flags = state->smb_fname->flags,
1981 .twrp = state->smb_fname->twrp,
1984 offline = vfswrap_is_offline(state->conn, &smb_fname);
1986 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1988 TALLOC_FREE(tofree);
1990 tevent_req_done(req);
1994 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1995 struct vfs_aio_state *aio_state,
1998 struct vfswrap_get_dos_attributes_state *state =
1999 tevent_req_data(req,
2000 struct vfswrap_get_dos_attributes_state);
2003 if (tevent_req_is_nterror(req, &status)) {
2004 tevent_req_received(req);
2008 *aio_state = state->aio_state;
2009 *dosmode = state->dosmode;
2010 tevent_req_received(req);
2011 return NT_STATUS_OK;
2014 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
2015 struct files_struct *fsp,
2020 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2022 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
2024 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
2027 return fget_ea_dos_attribute(fsp, dosmode);
2030 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
2031 struct files_struct *fsp,
2034 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2036 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2039 static struct vfs_offload_ctx *vfswrap_offload_ctx;
2041 struct vfswrap_offload_read_state {
2045 static struct tevent_req *vfswrap_offload_read_send(
2046 TALLOC_CTX *mem_ctx,
2047 struct tevent_context *ev,
2048 struct vfs_handle_struct *handle,
2049 struct files_struct *fsp,
2055 struct tevent_req *req = NULL;
2056 struct vfswrap_offload_read_state *state = NULL;
2059 req = tevent_req_create(mem_ctx, &state,
2060 struct vfswrap_offload_read_state);
2065 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2066 &vfswrap_offload_ctx);
2067 if (tevent_req_nterror(req, status)) {
2068 return tevent_req_post(req, ev);
2071 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2072 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2073 return tevent_req_post(req, ev);
2076 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2078 if (tevent_req_nterror(req, status)) {
2079 return tevent_req_post(req, ev);
2082 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2084 if (tevent_req_nterror(req, status)) {
2085 return tevent_req_post(req, ev);
2088 tevent_req_done(req);
2089 return tevent_req_post(req, ev);
2092 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2093 struct vfs_handle_struct *handle,
2094 TALLOC_CTX *mem_ctx,
2099 struct vfswrap_offload_read_state *state = tevent_req_data(
2100 req, struct vfswrap_offload_read_state);
2103 if (tevent_req_is_nterror(req, &status)) {
2104 tevent_req_received(req);
2110 token->length = state->token.length;
2111 token->data = talloc_move(mem_ctx, &state->token.data);
2113 tevent_req_received(req);
2114 return NT_STATUS_OK;
2117 struct vfswrap_offload_write_state {
2119 bool read_lck_locked;
2120 bool write_lck_locked;
2122 struct tevent_context *src_ev;
2123 struct files_struct *src_fsp;
2125 struct tevent_context *dst_ev;
2126 struct files_struct *dst_fsp;
2131 size_t next_io_size;
2134 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2135 enum tevent_req_state req_state)
2137 struct vfswrap_offload_write_state *state = tevent_req_data(
2138 req, struct vfswrap_offload_write_state);
2141 if (state->dst_fsp == NULL) {
2145 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2147 state->dst_fsp = NULL;
2150 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2151 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2153 static struct tevent_req *vfswrap_offload_write_send(
2154 struct vfs_handle_struct *handle,
2155 TALLOC_CTX *mem_ctx,
2156 struct tevent_context *ev,
2159 off_t transfer_offset,
2160 struct files_struct *dest_fsp,
2164 struct tevent_req *req;
2165 struct vfswrap_offload_write_state *state = NULL;
2166 /* off_t is signed! */
2167 off_t max_offset = INT64_MAX - to_copy;
2168 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2169 files_struct *src_fsp = NULL;
2173 req = tevent_req_create(mem_ctx, &state,
2174 struct vfswrap_offload_write_state);
2179 *state = (struct vfswrap_offload_write_state) {
2181 .src_off = transfer_offset,
2183 .dst_fsp = dest_fsp,
2184 .dst_off = dest_off,
2186 .remaining = to_copy,
2189 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2192 case FSCTL_SRV_COPYCHUNK:
2193 case FSCTL_SRV_COPYCHUNK_WRITE:
2196 case FSCTL_OFFLOAD_WRITE:
2197 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2198 return tevent_req_post(req, ev);
2200 case FSCTL_DUP_EXTENTS_TO_FILE:
2201 DBG_DEBUG("COW clones not supported by vfs_default\n");
2202 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2203 return tevent_req_post(req, ev);
2206 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2207 return tevent_req_post(req, ev);
2211 * From here on we assume a copy-chunk fsctl
2215 tevent_req_done(req);
2216 return tevent_req_post(req, ev);
2219 if (state->src_off > max_offset) {
2221 * Protect integer checks below.
2223 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2224 return tevent_req_post(req, ev);
2226 if (state->src_off < 0) {
2228 * Protect integer checks below.
2230 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2231 return tevent_req_post(req, ev);
2233 if (state->dst_off > max_offset) {
2235 * Protect integer checks below.
2237 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2238 return tevent_req_post(req, ev);
2240 if (state->dst_off < 0) {
2242 * Protect integer checks below.
2244 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2245 return tevent_req_post(req, ev);
2248 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2250 if (tevent_req_nterror(req, status)) {
2251 return tevent_req_post(req, ev);
2254 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2256 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2257 if (!NT_STATUS_IS_OK(status)) {
2258 tevent_req_nterror(req, status);
2259 return tevent_req_post(req, ev);
2262 ok = change_to_user_and_service_by_fsp(src_fsp);
2264 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2265 return tevent_req_post(req, ev);
2268 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2269 state->src_fsp = src_fsp;
2271 status = vfs_stat_fsp(src_fsp);
2272 if (tevent_req_nterror(req, status)) {
2273 return tevent_req_post(req, ev);
2276 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2278 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2279 * If the SourceOffset or SourceOffset + Length extends beyond
2280 * the end of file, the server SHOULD<240> treat this as a
2281 * STATUS_END_OF_FILE error.
2283 * <240> Section 3.3.5.15.6: Windows servers will return
2284 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2286 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2287 return tevent_req_post(req, ev);
2290 status = vfswrap_offload_copy_file_range(req);
2291 if (NT_STATUS_IS_OK(status)) {
2292 tevent_req_done(req);
2293 return tevent_req_post(req, ev);
2295 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2296 tevent_req_nterror(req, status);
2297 return tevent_req_post(req, ev);
2300 state->buf = talloc_array(state, uint8_t, num);
2301 if (tevent_req_nomem(state->buf, req)) {
2302 return tevent_req_post(req, ev);
2305 status = vfswrap_offload_write_loop(req);
2306 if (!NT_STATUS_IS_OK(status)) {
2307 tevent_req_nterror(req, status);
2308 return tevent_req_post(req, ev);
2314 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2316 struct vfswrap_offload_write_state *state = tevent_req_data(
2317 req, struct vfswrap_offload_write_state);
2318 struct lock_struct lck;
2323 static bool try_copy_file_range = true;
2325 if (!try_copy_file_range) {
2326 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2329 same_file = file_id_equal(&state->src_fsp->file_id,
2330 &state->dst_fsp->file_id);
2332 sys_io_ranges_overlap(state->remaining,
2337 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2340 if (fsp_is_alternate_stream(state->src_fsp) ||
2341 fsp_is_alternate_stream(state->dst_fsp))
2343 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2346 init_strict_lock_struct(state->src_fsp,
2347 state->src_fsp->op->global->open_persistent_id,
2351 lp_posix_cifsu_locktype(state->src_fsp),
2354 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2358 return NT_STATUS_FILE_LOCK_CONFLICT;
2361 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2363 return NT_STATUS_INTERNAL_ERROR;
2366 init_strict_lock_struct(state->dst_fsp,
2367 state->dst_fsp->op->global->open_persistent_id,
2371 lp_posix_cifsu_locktype(state->dst_fsp),
2374 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2378 return NT_STATUS_FILE_LOCK_CONFLICT;
2381 while (state->remaining > 0) {
2382 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2384 fsp_get_io_fd(state->dst_fsp),
2388 if (nwritten == -1) {
2389 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2390 "n [%jd] failed: %s\n",
2391 fsp_str_dbg(state->src_fsp),
2392 (intmax_t)state->src_off,
2393 fsp_str_dbg(state->dst_fsp),
2394 (intmax_t)state->dst_off,
2395 (intmax_t)state->remaining,
2400 try_copy_file_range = false;
2401 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2404 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2407 status = map_nt_error_from_unix(errno);
2408 if (NT_STATUS_EQUAL(
2410 NT_STATUS_MORE_PROCESSING_REQUIRED))
2412 /* Avoid triggering the fallback */
2413 status = NT_STATUS_INTERNAL_ERROR;
2420 if (state->remaining < nwritten) {
2421 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2422 "n [%jd] remaining [%jd]\n",
2423 fsp_str_dbg(state->src_fsp),
2424 fsp_str_dbg(state->dst_fsp),
2426 (intmax_t)state->remaining);
2427 return NT_STATUS_INTERNAL_ERROR;
2430 if (nwritten == 0) {
2433 state->copied += nwritten;
2434 state->remaining -= nwritten;
2438 * Tell the req cleanup function there's no need to call
2439 * change_to_user_and_service_by_fsp() on the dst handle.
2441 state->dst_fsp = NULL;
2442 return NT_STATUS_OK;
2445 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2447 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2449 struct vfswrap_offload_write_state *state = tevent_req_data(
2450 req, struct vfswrap_offload_write_state);
2451 struct tevent_req *subreq = NULL;
2452 struct lock_struct read_lck;
2456 * This is called under the context of state->src_fsp.
2459 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2461 init_strict_lock_struct(state->src_fsp,
2462 state->src_fsp->op->global->open_persistent_id,
2464 state->next_io_size,
2466 lp_posix_cifsu_locktype(state->src_fsp),
2469 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2473 return NT_STATUS_FILE_LOCK_CONFLICT;
2476 subreq = SMB_VFS_PREAD_SEND(state,
2480 state->next_io_size,
2482 if (subreq == NULL) {
2483 return NT_STATUS_NO_MEMORY;
2485 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2487 return NT_STATUS_OK;
2490 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2492 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2494 struct tevent_req *req = tevent_req_callback_data(
2495 subreq, struct tevent_req);
2496 struct vfswrap_offload_write_state *state = tevent_req_data(
2497 req, struct vfswrap_offload_write_state);
2498 struct vfs_aio_state aio_state;
2499 struct lock_struct write_lck;
2503 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2504 TALLOC_FREE(subreq);
2506 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2507 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2510 if (nread != state->next_io_size) {
2511 DBG_ERR("Short read, only %zd of %zu\n",
2512 nread, state->next_io_size);
2513 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2517 state->src_off += nread;
2519 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2521 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2525 init_strict_lock_struct(state->dst_fsp,
2526 state->dst_fsp->op->global->open_persistent_id,
2528 state->next_io_size,
2530 lp_posix_cifsu_locktype(state->dst_fsp),
2533 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2537 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2541 subreq = SMB_VFS_PWRITE_SEND(state,
2545 state->next_io_size,
2547 if (subreq == NULL) {
2548 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2551 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2554 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2556 struct tevent_req *req = tevent_req_callback_data(
2557 subreq, struct tevent_req);
2558 struct vfswrap_offload_write_state *state = tevent_req_data(
2559 req, struct vfswrap_offload_write_state);
2560 struct vfs_aio_state aio_state;
2565 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2566 TALLOC_FREE(subreq);
2567 if (nwritten == -1) {
2568 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2569 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2572 if (nwritten != state->next_io_size) {
2573 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2574 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2578 state->dst_off += nwritten;
2580 if (state->remaining < nwritten) {
2581 /* Paranoia check */
2582 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2585 state->copied += nwritten;
2586 state->remaining -= nwritten;
2587 if (state->remaining == 0) {
2588 tevent_req_done(req);
2592 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2594 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2598 status = vfswrap_offload_write_loop(req);
2599 if (!NT_STATUS_IS_OK(status)) {
2600 tevent_req_nterror(req, status);
2607 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2608 struct tevent_req *req,
2611 struct vfswrap_offload_write_state *state = tevent_req_data(
2612 req, struct vfswrap_offload_write_state);
2615 if (tevent_req_is_nterror(req, &status)) {
2616 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2618 tevent_req_received(req);
2622 *copied = state->copied;
2623 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2624 tevent_req_received(req);
2626 return NT_STATUS_OK;
2629 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2630 TALLOC_CTX *mem_ctx,
2631 struct files_struct *fsp,
2632 uint16_t *_compression_fmt)
2634 return NT_STATUS_INVALID_DEVICE_REQUEST;
2637 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2638 TALLOC_CTX *mem_ctx,
2639 struct files_struct *fsp,
2640 uint16_t compression_fmt)
2642 return NT_STATUS_INVALID_DEVICE_REQUEST;
2645 /********************************************************************
2646 Given a stat buffer return the allocated size on disk, taking into
2647 account sparse files.
2648 ********************************************************************/
2649 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2650 struct files_struct *fsp,
2651 const SMB_STRUCT_STAT *sbuf)
2655 START_PROFILE(syscall_get_alloc_size);
2657 if(S_ISDIR(sbuf->st_ex_mode)) {
2662 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2663 /* The type of st_blocksize is blkcnt_t which *MUST* be
2664 signed (according to POSIX) and can be less than 64-bits.
2665 Ensure when we're converting to 64 bits wide we don't
2667 #if defined(SIZEOF_BLKCNT_T_8)
2668 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2669 #elif defined(SIZEOF_BLKCNT_T_4)
2671 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2672 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2675 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2679 * Some file systems do not allocate a block for very
2680 * small files. But for non-empty file should report a
2684 uint64_t filesize = get_file_size_stat(sbuf);
2686 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2690 result = get_file_size_stat(sbuf);
2693 if (fsp && fsp->initial_allocation_size)
2694 result = MAX(result,fsp->initial_allocation_size);
2696 result = smb_roundup(handle->conn, result);
2699 END_PROFILE(syscall_get_alloc_size);
2703 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2704 struct files_struct *dirfsp,
2705 const struct smb_filename *smb_fname,
2710 START_PROFILE(syscall_unlinkat);
2712 SMB_ASSERT(!is_named_stream(smb_fname));
2714 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2715 smb_fname->base_name,
2718 END_PROFILE(syscall_unlinkat);
2722 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2726 START_PROFILE(syscall_fchmod);
2728 if (!fsp->fsp_flags.is_pathref) {
2729 result = fchmod(fsp_get_io_fd(fsp), mode);
2730 END_PROFILE(syscall_fchmod);
2734 if (fsp->fsp_flags.have_proc_fds) {
2735 int fd = fsp_get_pathref_fd(fsp);
2736 const char *p = NULL;
2739 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2741 result = chmod(p, mode);
2745 END_PROFILE(syscall_fchmod);
2750 * This is no longer a handle based call.
2752 result = chmod(fsp->fsp_name->base_name, mode);
2754 END_PROFILE(syscall_fchmod);
2758 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2763 START_PROFILE(syscall_fchown);
2764 if (!fsp->fsp_flags.is_pathref) {
2765 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2766 END_PROFILE(syscall_fchown);
2770 if (fsp->fsp_flags.have_proc_fds) {
2771 int fd = fsp_get_pathref_fd(fsp);
2772 const char *p = NULL;
2775 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2777 result = chown(p, uid, gid);
2781 END_PROFILE(syscall_fchown);
2786 * This is no longer a handle based call.
2788 result = chown(fsp->fsp_name->base_name, uid, gid);
2789 END_PROFILE(syscall_fchown);
2797 static int vfswrap_lchown(vfs_handle_struct *handle,
2798 const struct smb_filename *smb_fname,
2804 START_PROFILE(syscall_lchown);
2805 result = lchown(smb_fname->base_name, uid, gid);
2806 END_PROFILE(syscall_lchown);
2810 static int vfswrap_chdir(vfs_handle_struct *handle,
2811 const struct smb_filename *smb_fname)
2815 START_PROFILE(syscall_chdir);
2816 result = chdir(smb_fname->base_name);
2817 END_PROFILE(syscall_chdir);
2821 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2825 struct smb_filename *smb_fname = NULL;
2827 START_PROFILE(syscall_getwd);
2828 result = sys_getwd();
2829 END_PROFILE(syscall_getwd);
2831 if (result == NULL) {
2834 smb_fname = synthetic_smb_fname(ctx,
2841 * sys_getwd() *always* returns malloced memory.
2842 * We must free here to avoid leaks:
2843 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2849 /*********************************************************************
2850 nsec timestamp resolution call. Convert down to whatever the underlying
2851 system will support.
2852 **********************************************************************/
2854 static int vfswrap_fntimes(vfs_handle_struct *handle,
2856 struct smb_file_time *ft)
2859 struct timespec ts[2];
2860 struct timespec *times = NULL;
2862 START_PROFILE(syscall_fntimes);
2864 if (fsp_is_alternate_stream(fsp)) {
2870 if (is_omit_timespec(&ft->atime)) {
2871 ft->atime = fsp->fsp_name->st.st_ex_atime;
2874 if (is_omit_timespec(&ft->mtime)) {
2875 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2878 if (!is_omit_timespec(&ft->create_time)) {
2879 set_create_timespec_ea(fsp,
2883 if ((timespec_compare(&ft->atime,
2884 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2885 (timespec_compare(&ft->mtime,
2886 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2898 if (!fsp->fsp_flags.is_pathref) {
2899 result = futimens(fsp_get_io_fd(fsp), times);
2903 if (fsp->fsp_flags.have_proc_fds) {
2904 int fd = fsp_get_pathref_fd(fsp);
2905 const char *p = NULL;
2908 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2911 * The dirfd argument of utimensat is ignored when
2912 * pathname is an absolute path
2914 result = utimensat(AT_FDCWD, p, times, 0);
2923 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2924 * path translation mechanism. Fallback to path based call.
2926 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2929 END_PROFILE(syscall_fntimes);
2935 /*********************************************************************
2936 A version of ftruncate that will write the space on disk if strict
2938 **********************************************************************/
2940 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2942 off_t space_to_write;
2943 uint64_t space_avail;
2944 uint64_t bsize,dfree,dsize;
2947 SMB_STRUCT_STAT *pst;
2950 ok = vfs_valid_pwrite_range(len, 0);
2956 status = vfs_stat_fsp(fsp);
2957 if (!NT_STATUS_IS_OK(status)) {
2960 pst = &fsp->fsp_name->st;
2963 if (S_ISFIFO(pst->st_ex_mode))
2967 if (pst->st_ex_size == len)
2970 /* Shrink - just ftruncate. */
2971 if (pst->st_ex_size > len)
2972 return ftruncate(fsp_get_io_fd(fsp), len);
2974 space_to_write = len - pst->st_ex_size;
2976 /* for allocation try fallocate first. This can fail on some
2977 platforms e.g. when the filesystem doesn't support it and no
2978 emulation is being done by the libc (like on AIX with JFS1). In that
2979 case we do our own emulation. fallocate implementations can
2980 return ENOTSUP or EINVAL in cases like that. */
2981 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2982 if (ret == -1 && errno == ENOSPC) {
2988 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2989 "error %d. Falling back to slow manual allocation\n", errno));
2991 /* available disk space is enough or not? */
2993 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2994 /* space_avail is 1k blocks */
2995 if (space_avail == (uint64_t)-1 ||
2996 ((uint64_t)space_to_write/1024 > space_avail) ) {
3001 /* Write out the real space on disk. */
3002 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
3010 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
3013 SMB_STRUCT_STAT *pst;
3017 START_PROFILE(syscall_ftruncate);
3019 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
3020 result = strict_allocate_ftruncate(handle, fsp, len);
3021 END_PROFILE(syscall_ftruncate);
3025 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
3026 ftruncate if the system supports it. Then I discovered that
3027 you can have some filesystems that support ftruncate
3028 expansion and some that don't! On Linux fat can't do
3029 ftruncate extend but ext2 can. */
3031 result = ftruncate(fsp_get_io_fd(fsp), len);
3033 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
3034 extend a file with ftruncate. Provide alternate implementation
3037 /* Do an fstat to see if the file is longer than the requested
3038 size in which case the ftruncate above should have
3039 succeeded or shorter, in which case seek to len - 1 and
3040 write 1 byte of zero */
3041 status = vfs_stat_fsp(fsp);
3042 if (!NT_STATUS_IS_OK(status)) {
3046 /* We need to update the files_struct after successful ftruncate */
3051 pst = &fsp->fsp_name->st;
3054 if (S_ISFIFO(pst->st_ex_mode)) {
3060 if (pst->st_ex_size == len) {
3065 if (pst->st_ex_size > len) {
3066 /* the ftruncate should have worked */
3070 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3078 END_PROFILE(syscall_ftruncate);
3082 static int vfswrap_fallocate(vfs_handle_struct *handle,
3090 START_PROFILE(syscall_fallocate);
3092 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3094 * posix_fallocate returns 0 on success, errno on error
3095 * and doesn't set errno. Make it behave like fallocate()
3096 * which returns -1, and sets errno on failure.
3103 /* sys_fallocate handles filtering of unsupported mode flags */
3104 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3106 END_PROFILE(syscall_fallocate);
3110 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3114 START_PROFILE(syscall_fcntl_lock);
3116 if (fsp->fsp_flags.use_ofd_locks) {
3117 op = map_process_lock_to_ofd_lock(op);
3120 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3121 END_PROFILE(syscall_fcntl_lock);
3125 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3127 uint32_t share_access,
3128 uint32_t access_mask)
3134 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3138 va_list dup_cmd_arg;
3142 START_PROFILE(syscall_fcntl);
3144 va_copy(dup_cmd_arg, cmd_arg);
3150 #if defined(HAVE_OFD_LOCKS)
3155 #if defined(HAVE_F_OWNER_EX)
3159 #if defined(HAVE_RW_HINTS)
3162 case F_GET_FILE_RW_HINT:
3163 case F_SET_FILE_RW_HINT:
3165 argp = va_arg(dup_cmd_arg, void *);
3166 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3169 val = va_arg(dup_cmd_arg, int);
3170 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3173 va_end(dup_cmd_arg);
3175 END_PROFILE(syscall_fcntl);
3179 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3184 START_PROFILE(syscall_fcntl_getlock);
3186 if (fsp->fsp_flags.use_ofd_locks) {
3187 op = map_process_lock_to_ofd_lock(op);
3190 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3191 END_PROFILE(syscall_fcntl_getlock);
3195 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3200 START_PROFILE(syscall_linux_setlease);
3202 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3204 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3205 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3209 END_PROFILE(syscall_linux_setlease);
3213 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3214 const struct smb_filename *link_target,
3215 struct files_struct *dirfsp,
3216 const struct smb_filename *new_smb_fname)
3220 START_PROFILE(syscall_symlinkat);
3222 SMB_ASSERT(!is_named_stream(new_smb_fname));
3224 result = symlinkat(link_target->base_name,
3225 fsp_get_pathref_fd(dirfsp),
3226 new_smb_fname->base_name);
3227 END_PROFILE(syscall_symlinkat);
3231 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3232 const struct files_struct *dirfsp,
3233 const struct smb_filename *smb_fname,
3239 START_PROFILE(syscall_readlinkat);
3241 SMB_ASSERT(!is_named_stream(smb_fname));
3243 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3244 smb_fname->base_name,
3248 END_PROFILE(syscall_readlinkat);
3252 static int vfswrap_linkat(vfs_handle_struct *handle,
3253 files_struct *srcfsp,
3254 const struct smb_filename *old_smb_fname,
3255 files_struct *dstfsp,
3256 const struct smb_filename *new_smb_fname,
3261 START_PROFILE(syscall_linkat);
3263 SMB_ASSERT(!is_named_stream(old_smb_fname));
3264 SMB_ASSERT(!is_named_stream(new_smb_fname));
3266 result = linkat(fsp_get_pathref_fd(srcfsp),
3267 old_smb_fname->base_name,
3268 fsp_get_pathref_fd(dstfsp),
3269 new_smb_fname->base_name,
3272 END_PROFILE(syscall_linkat);
3276 static int vfswrap_mknodat(vfs_handle_struct *handle,
3277 files_struct *dirfsp,
3278 const struct smb_filename *smb_fname,
3284 START_PROFILE(syscall_mknodat);
3286 SMB_ASSERT(!is_named_stream(smb_fname));
3288 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3289 smb_fname->base_name,
3293 END_PROFILE(syscall_mknodat);
3297 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3299 const struct smb_filename *smb_fname)
3302 struct smb_filename *result_fname = NULL;
3304 START_PROFILE(syscall_realpath);
3305 result = sys_realpath(smb_fname->base_name);
3306 END_PROFILE(syscall_realpath);
3308 result_fname = synthetic_smb_fname(ctx,
3316 return result_fname;
3319 static int vfswrap_fchflags(vfs_handle_struct *handle,
3320 struct files_struct *fsp,
3323 #ifdef HAVE_FCHFLAGS
3324 int fd = fsp_get_pathref_fd(fsp);
3326 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3328 if (!fsp->fsp_flags.is_pathref) {
3329 return fchflags(fd, flags);
3332 if (fsp->fsp_flags.have_proc_fds) {
3333 const char *p = NULL;
3336 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3341 return chflags(p, flags);
3345 * This is no longer a handle based call.
3347 return chflags(fsp->fsp_name->base_name, flags);
3354 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3355 const SMB_STRUCT_STAT *sbuf)
3359 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3363 key.devid = sbuf->st_ex_dev;
3364 key.inode = sbuf->st_ex_ino;
3365 /* key.extid is unused by default. */
3370 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3371 const SMB_STRUCT_STAT *psbuf)
3375 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3376 return (uint64_t)psbuf->st_ex_ino;
3380 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3383 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3388 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3389 struct files_struct *fsp,
3390 TALLOC_CTX *mem_ctx,
3391 unsigned int *pnum_streams,
3392 struct stream_struct **pstreams)
3394 struct stream_struct *tmp_streams = NULL;
3395 unsigned int num_streams = *pnum_streams;
3396 struct stream_struct *streams = *pstreams;
3399 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3401 if (fsp->fsp_flags.is_directory) {
3403 * No default streams on directories
3407 status = vfs_stat_fsp(fsp);
3408 if (!NT_STATUS_IS_OK(status)) {
3412 if (num_streams + 1 < 1) {
3414 return NT_STATUS_INVALID_PARAMETER;
3417 tmp_streams = talloc_realloc(mem_ctx,
3419 struct stream_struct,
3421 if (tmp_streams == NULL) {
3422 return NT_STATUS_NO_MEMORY;
3424 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3425 if (tmp_streams[num_streams].name == NULL) {
3426 return NT_STATUS_NO_MEMORY;
3428 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3429 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3432 &fsp->fsp_name->st);
3435 *pnum_streams = num_streams;
3436 *pstreams = tmp_streams;
3438 return NT_STATUS_OK;
3441 static NTSTATUS vfswrap_get_real_filename_at(
3442 struct vfs_handle_struct *handle,
3443 struct files_struct *dirfsp,
3445 TALLOC_CTX *mem_ctx,
3449 * Don't fall back to get_real_filename so callers can differentiate
3450 * between a full directory scan and an actual case-insensitive stat.
3452 return NT_STATUS_NOT_SUPPORTED;
3455 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3456 const struct smb_filename *smb_fname)
3458 return handle->conn->connectpath;
3461 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3462 struct byte_range_lock *br_lck,
3463 struct lock_struct *plock)
3465 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3467 /* Note: blr is not used in the default implementation. */
3468 return brl_lock_windows_default(br_lck, plock);
3471 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3472 struct byte_range_lock *br_lck,
3473 const struct lock_struct *plock)
3475 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3477 return brl_unlock_windows_default(br_lck, plock);
3480 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3482 struct lock_struct *plock)
3484 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3485 plock->lock_type == WRITE_LOCK);
3487 return strict_lock_check_default(fsp, plock);
3490 /* NT ACL operations. */
3492 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3494 uint32_t security_info,
3495 TALLOC_CTX *mem_ctx,
3496 struct security_descriptor **ppdesc)
3500 START_PROFILE(fget_nt_acl);
3502 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3504 result = posix_fget_nt_acl(fsp, security_info,
3506 END_PROFILE(fget_nt_acl);
3510 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3514 START_PROFILE(fset_nt_acl);
3516 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3518 result = set_nt_acl(fsp, security_info_sent, psd);
3519 END_PROFILE(fset_nt_acl);
3523 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3524 struct smb_filename *file,
3525 struct security_acl *sacl,
3526 uint32_t access_requested,
3527 uint32_t access_denied)
3529 return NT_STATUS_OK; /* Nothing to do here ... */
3532 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3534 SMB_ACL_TYPE_T type,
3535 TALLOC_CTX *mem_ctx)
3537 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3539 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3542 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3544 SMB_ACL_TYPE_T type,
3547 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3549 return sys_acl_set_fd(handle, fsp, type, theacl);
3552 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3555 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3557 return sys_acl_delete_def_fd(handle, fsp);
3560 /****************************************************************
3561 Extended attribute operations.
3562 *****************************************************************/
3564 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3565 struct files_struct *fsp,
3570 int fd = fsp_get_pathref_fd(fsp);
3572 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3574 if (!fsp->fsp_flags.is_pathref) {
3575 return fgetxattr(fd, name, value, size);
3578 if (fsp->fsp_flags.have_proc_fds) {
3579 const char *p = NULL;
3582 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3587 return getxattr(p, name, value, size);
3591 * This is no longer a handle based call.
3593 return getxattr(fsp->fsp_name->base_name, name, value, size);
3596 struct vfswrap_getxattrat_state {
3597 struct tevent_context *ev;
3598 struct vfs_handle_struct *handle;
3599 files_struct *dir_fsp;
3600 const struct smb_filename *smb_fname;
3603 * The following variables are talloced off "state" which is protected
3604 * by a destructor and thus are guaranteed to be safe to be used in the
3605 * job function in the worker thread.
3608 const char *xattr_name;
3609 uint8_t *xattr_value;
3610 struct security_unix_token *token;
3613 struct vfs_aio_state vfs_aio_state;
3614 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3617 static int vfswrap_getxattrat_state_destructor(
3618 struct vfswrap_getxattrat_state *state)
3623 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3624 static void vfswrap_getxattrat_do_async(void *private_data);
3625 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3627 static struct tevent_req *vfswrap_getxattrat_send(
3628 TALLOC_CTX *mem_ctx,
3629 struct tevent_context *ev,
3630 struct vfs_handle_struct *handle,
3631 files_struct *dir_fsp,
3632 const struct smb_filename *smb_fname,
3633 const char *xattr_name,
3636 struct tevent_req *req = NULL;
3637 struct tevent_req *subreq = NULL;
3638 struct vfswrap_getxattrat_state *state = NULL;
3639 size_t max_threads = 0;
3640 bool have_per_thread_cwd = false;
3641 bool have_per_thread_creds = false;
3642 bool do_async = false;
3644 SMB_ASSERT(!is_named_stream(smb_fname));
3646 req = tevent_req_create(mem_ctx, &state,
3647 struct vfswrap_getxattrat_state);
3651 *state = (struct vfswrap_getxattrat_state) {
3655 .smb_fname = smb_fname,
3658 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3659 if (max_threads >= 1) {
3661 * We need a non sync threadpool!
3663 have_per_thread_cwd = per_thread_cwd_supported();
3665 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3666 have_per_thread_creds = true;
3668 if (have_per_thread_cwd && have_per_thread_creds) {
3672 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3673 state->profile_bytes, 0);
3675 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3676 DBG_ERR("Need a valid directory fd\n");
3677 tevent_req_error(req, EINVAL);
3678 return tevent_req_post(req, ev);
3681 if (alloc_hint > 0) {
3682 state->xattr_value = talloc_zero_array(state,
3685 if (tevent_req_nomem(state->xattr_value, req)) {
3686 return tevent_req_post(req, ev);
3691 vfswrap_getxattrat_do_sync(req);
3692 return tevent_req_post(req, ev);
3696 * Now allocate all parameters from a memory context that won't go away
3697 * no matter what. These paremeters will get used in threads and we
3698 * can't reliably cancel threads, so all buffers passed to the threads
3699 * must not be freed before all referencing threads terminate.
3702 state->name = talloc_strdup(state, smb_fname->base_name);
3703 if (tevent_req_nomem(state->name, req)) {
3704 return tevent_req_post(req, ev);
3707 state->xattr_name = talloc_strdup(state, xattr_name);
3708 if (tevent_req_nomem(state->xattr_name, req)) {
3709 return tevent_req_post(req, ev);
3713 * This is a hot codepath so at first glance one might think we should
3714 * somehow optimize away the token allocation and do a
3715 * talloc_reference() or similar black magic instead. But due to the
3716 * talloc_stackframe pool per SMB2 request this should be a simple copy
3717 * without a malloc in most cases.
3719 if (geteuid() == sec_initial_uid()) {
3720 state->token = root_unix_token(state);
3722 state->token = copy_unix_token(
3724 dir_fsp->conn->session_info->unix_token);
3726 if (tevent_req_nomem(state->token, req)) {
3727 return tevent_req_post(req, ev);
3730 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3732 subreq = pthreadpool_tevent_job_send(
3735 dir_fsp->conn->sconn->pool,
3736 vfswrap_getxattrat_do_async,
3738 if (tevent_req_nomem(subreq, req)) {
3739 return tevent_req_post(req, ev);
3741 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3743 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3748 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3750 struct vfswrap_getxattrat_state *state = tevent_req_data(
3751 req, struct vfswrap_getxattrat_state);
3753 state->xattr_size = vfswrap_fgetxattr(state->handle,
3754 state->smb_fname->fsp,
3757 talloc_array_length(state->xattr_value));
3758 if (state->xattr_size == -1) {
3759 tevent_req_error(req, errno);
3763 tevent_req_done(req);
3767 static void vfswrap_getxattrat_do_async(void *private_data)
3769 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3770 private_data, struct vfswrap_getxattrat_state);
3771 struct timespec start_time;
3772 struct timespec end_time;
3775 PROFILE_TIMESTAMP(&start_time);
3776 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3779 * Here we simulate a getxattrat()
3780 * call using fchdir();getxattr()
3783 per_thread_cwd_activate();
3785 /* Become the correct credential on this thread. */
3786 ret = set_thread_credentials(state->token->uid,
3788 (size_t)state->token->ngroups,
3789 state->token->groups);
3791 state->xattr_size = -1;
3792 state->vfs_aio_state.error = errno;
3796 state->xattr_size = vfswrap_fgetxattr(state->handle,
3797 state->smb_fname->fsp,
3800 talloc_array_length(state->xattr_value));
3801 if (state->xattr_size == -1) {
3802 state->vfs_aio_state.error = errno;
3806 PROFILE_TIMESTAMP(&end_time);
3807 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3808 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3811 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3813 struct tevent_req *req = tevent_req_callback_data(
3814 subreq, struct tevent_req);
3815 struct vfswrap_getxattrat_state *state = tevent_req_data(
3816 req, struct vfswrap_getxattrat_state);
3821 * Make sure we run as the user again
3823 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3826 ret = pthreadpool_tevent_job_recv(subreq);
3827 TALLOC_FREE(subreq);
3828 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3829 talloc_set_destructor(state, NULL);
3831 if (ret != EAGAIN) {
3832 tevent_req_error(req, ret);
3836 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3837 * means the lower level pthreadpool failed to create a new
3838 * thread. Fallback to sync processing in that case to allow
3839 * some progress for the client.
3841 vfswrap_getxattrat_do_sync(req);
3845 if (state->xattr_size == -1) {
3846 tevent_req_error(req, state->vfs_aio_state.error);
3850 if (state->xattr_value == NULL) {
3852 * The caller only wanted the size.
3854 tevent_req_done(req);
3859 * shrink the buffer to the returned size.
3860 * (can't fail). It means NULL if size is 0.
3862 state->xattr_value = talloc_realloc(state,
3867 tevent_req_done(req);
3870 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3871 struct vfs_aio_state *aio_state,
3872 TALLOC_CTX *mem_ctx,
3873 uint8_t **xattr_value)
3875 struct vfswrap_getxattrat_state *state = tevent_req_data(
3876 req, struct vfswrap_getxattrat_state);
3879 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3880 tevent_req_received(req);
3884 *aio_state = state->vfs_aio_state;
3885 xattr_size = state->xattr_size;
3886 if (xattr_value != NULL) {
3887 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3890 tevent_req_received(req);
3894 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3896 int fd = fsp_get_pathref_fd(fsp);
3898 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3900 if (!fsp->fsp_flags.is_pathref) {
3901 return flistxattr(fd, list, size);
3904 if (fsp->fsp_flags.have_proc_fds) {
3905 const char *p = NULL;
3908 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3913 return listxattr(p, list, size);
3917 * This is no longer a handle based call.
3919 return listxattr(fsp->fsp_name->base_name, list, size);
3922 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3924 int fd = fsp_get_pathref_fd(fsp);
3926 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3928 if (!fsp->fsp_flags.is_pathref) {
3929 return fremovexattr(fd, name);
3932 if (fsp->fsp_flags.have_proc_fds) {
3933 const char *p = NULL;
3936 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3941 return removexattr(p, name);
3945 * This is no longer a handle based call.
3947 return removexattr(fsp->fsp_name->base_name, name);
3950 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3952 int fd = fsp_get_pathref_fd(fsp);
3954 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3956 if (!fsp->fsp_flags.is_pathref) {
3957 return fsetxattr(fd, name, value, size, flags);
3960 if (fsp->fsp_flags.have_proc_fds) {
3961 const char *p = NULL;
3964 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3969 return setxattr(p, name, value, size, flags);
3973 * This is no longer a handle based call.
3975 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3978 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3983 static bool vfswrap_is_offline(struct connection_struct *conn,
3984 const struct smb_filename *fname)
3988 bool offline = false;
3990 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3994 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3995 #if defined(ENOTSUP)
4001 status = get_full_smb_filename(talloc_tos(), fname, &path);
4002 if (!NT_STATUS_IS_OK(status)) {
4003 errno = map_errno_from_nt_status(status);
4007 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
4014 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
4015 struct files_struct *fsp,
4016 TALLOC_CTX *mem_ctx,
4019 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
4022 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
4023 struct files_struct *fsp,
4024 const DATA_BLOB old_cookie,
4025 TALLOC_CTX *mem_ctx,
4026 DATA_BLOB *new_cookie)
4028 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
4032 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
4033 struct smb_request *smb1req,
4034 struct smbXsrv_open *op,
4035 const DATA_BLOB old_cookie,
4036 TALLOC_CTX *mem_ctx,
4037 struct files_struct **fsp,
4038 DATA_BLOB *new_cookie)
4040 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
4041 old_cookie, mem_ctx,
4045 static struct vfs_fn_pointers vfs_default_fns = {
4046 /* Disk operations */
4048 .connect_fn = vfswrap_connect,
4049 .disconnect_fn = vfswrap_disconnect,
4050 .disk_free_fn = vfswrap_disk_free,
4051 .get_quota_fn = vfswrap_get_quota,
4052 .set_quota_fn = vfswrap_set_quota,
4053 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
4054 .statvfs_fn = vfswrap_statvfs,
4055 .fs_capabilities_fn = vfswrap_fs_capabilities,
4056 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
4057 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
4058 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
4059 .snap_check_path_fn = vfswrap_snap_check_path,
4060 .snap_create_fn = vfswrap_snap_create,
4061 .snap_delete_fn = vfswrap_snap_delete,
4063 /* Directory operations */
4065 .fdopendir_fn = vfswrap_fdopendir,
4066 .readdir_fn = vfswrap_readdir,
4067 .freaddir_attr_fn = vfswrap_freaddir_attr,
4068 .seekdir_fn = vfswrap_seekdir,
4069 .telldir_fn = vfswrap_telldir,
4070 .rewind_dir_fn = vfswrap_rewinddir,
4071 .mkdirat_fn = vfswrap_mkdirat,
4072 .closedir_fn = vfswrap_closedir,
4074 /* File operations */
4076 .openat_fn = vfswrap_openat,
4077 .create_file_fn = vfswrap_create_file,
4078 .close_fn = vfswrap_close,
4079 .pread_fn = vfswrap_pread,
4080 .pread_send_fn = vfswrap_pread_send,
4081 .pread_recv_fn = vfswrap_pread_recv,
4082 .pwrite_fn = vfswrap_pwrite,
4083 .pwrite_send_fn = vfswrap_pwrite_send,
4084 .pwrite_recv_fn = vfswrap_pwrite_recv,
4085 .lseek_fn = vfswrap_lseek,
4086 .sendfile_fn = vfswrap_sendfile,
4087 .recvfile_fn = vfswrap_recvfile,
4088 .renameat_fn = vfswrap_renameat,
4089 .fsync_send_fn = vfswrap_fsync_send,
4090 .fsync_recv_fn = vfswrap_fsync_recv,
4091 .stat_fn = vfswrap_stat,
4092 .fstat_fn = vfswrap_fstat,
4093 .lstat_fn = vfswrap_lstat,
4094 .fstatat_fn = vfswrap_fstatat,
4095 .get_alloc_size_fn = vfswrap_get_alloc_size,
4096 .unlinkat_fn = vfswrap_unlinkat,
4097 .fchmod_fn = vfswrap_fchmod,
4098 .fchown_fn = vfswrap_fchown,
4099 .lchown_fn = vfswrap_lchown,
4100 .chdir_fn = vfswrap_chdir,
4101 .getwd_fn = vfswrap_getwd,
4102 .fntimes_fn = vfswrap_fntimes,
4103 .ftruncate_fn = vfswrap_ftruncate,
4104 .fallocate_fn = vfswrap_fallocate,
4105 .lock_fn = vfswrap_lock,
4106 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4107 .fcntl_fn = vfswrap_fcntl,
4108 .linux_setlease_fn = vfswrap_linux_setlease,
4109 .getlock_fn = vfswrap_getlock,
4110 .symlinkat_fn = vfswrap_symlinkat,
4111 .readlinkat_fn = vfswrap_readlinkat,
4112 .linkat_fn = vfswrap_linkat,
4113 .mknodat_fn = vfswrap_mknodat,
4114 .realpath_fn = vfswrap_realpath,
4115 .fchflags_fn = vfswrap_fchflags,
4116 .file_id_create_fn = vfswrap_file_id_create,
4117 .fs_file_id_fn = vfswrap_fs_file_id,
4118 .fstreaminfo_fn = vfswrap_fstreaminfo,
4119 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4120 .connectpath_fn = vfswrap_connectpath,
4121 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4122 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4123 .strict_lock_check_fn = vfswrap_strict_lock_check,
4124 .translate_name_fn = vfswrap_translate_name,
4125 .parent_pathname_fn = vfswrap_parent_pathname,
4126 .fsctl_fn = vfswrap_fsctl,
4127 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4128 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4129 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4130 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4131 .offload_read_send_fn = vfswrap_offload_read_send,
4132 .offload_read_recv_fn = vfswrap_offload_read_recv,
4133 .offload_write_send_fn = vfswrap_offload_write_send,
4134 .offload_write_recv_fn = vfswrap_offload_write_recv,
4135 .fget_compression_fn = vfswrap_fget_compression,
4136 .set_compression_fn = vfswrap_set_compression,
4138 /* NT ACL operations. */
4140 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4141 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4142 .audit_file_fn = vfswrap_audit_file,
4144 /* POSIX ACL operations. */
4146 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4147 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4148 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4149 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4151 /* EA operations. */
4152 .getxattrat_send_fn = vfswrap_getxattrat_send,
4153 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4154 .fgetxattr_fn = vfswrap_fgetxattr,
4155 .flistxattr_fn = vfswrap_flistxattr,
4156 .fremovexattr_fn = vfswrap_fremovexattr,
4157 .fsetxattr_fn = vfswrap_fsetxattr,
4159 /* aio operations */
4160 .aio_force_fn = vfswrap_aio_force,
4162 /* durable handle operations */
4163 .durable_cookie_fn = vfswrap_durable_cookie,
4164 .durable_disconnect_fn = vfswrap_durable_disconnect,
4165 .durable_reconnect_fn = vfswrap_durable_reconnect,
4169 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4172 * Here we need to implement every call!
4174 * As this is the end of the vfs module chain.
4176 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4177 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4178 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);