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();
55 #ifdef DISABLE_PROC_FDS
56 handle->conn->have_proc_fds = false;
60 * assume the kernel will support openat2(),
61 * it will be reset on the first ENOSYS.
63 * Note that libreplace will always provide openat2(),
64 * but return -1/errno = ENOSYS...
66 * The option is only there to test the fallback code.
68 bval = lp_parm_bool(SNUM(handle->conn),
70 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
73 handle->conn->open_how_resolve |=
74 VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
76 #ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
77 handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
80 return 0; /* Return >= 0 for success */
83 static void vfswrap_disconnect(vfs_handle_struct *handle)
89 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
90 const struct smb_filename *smb_fname,
95 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
103 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
104 const struct smb_filename *smb_fname,
105 enum SMB_QUOTA_TYPE qtype,
109 #ifdef HAVE_SYS_QUOTAS
112 START_PROFILE(syscall_get_quota);
113 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
114 END_PROFILE(syscall_get_quota);
122 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
124 #ifdef HAVE_SYS_QUOTAS
127 START_PROFILE(syscall_set_quota);
128 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
129 END_PROFILE(syscall_set_quota);
137 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
138 struct files_struct *fsp,
139 struct shadow_copy_data *shadow_copy_data,
143 return -1; /* Not implemented. */
146 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
147 const struct smb_filename *smb_fname,
148 struct vfs_statvfs_struct *statbuf)
150 return sys_statvfs(smb_fname->base_name, statbuf);
153 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
154 enum timestamp_set_resolution *p_ts_res)
156 const struct loadparm_substitution *lp_sub =
157 loadparm_s3_global_substitution();
158 connection_struct *conn = handle->conn;
159 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
160 struct smb_filename *smb_fname_cpath = NULL;
161 struct vfs_statvfs_struct statbuf;
164 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
170 if (smb_fname_cpath == NULL) {
174 ZERO_STRUCT(statbuf);
175 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
177 caps = statbuf.FsCapabilities;
180 *p_ts_res = TIMESTAMP_SET_SECONDS;
182 /* Work out what timestamp resolution we can
183 * use when setting a timestamp. */
185 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
187 TALLOC_FREE(smb_fname_cpath);
191 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
192 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
193 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
194 /* If any of the normal UNIX directory timestamps
195 * have a non-zero tv_nsec component assume
196 * we might be able to set sub-second timestamps.
197 * See what filetime set primitives we have.
199 #if defined(HAVE_UTIMENSAT)
200 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
201 #elif defined(HAVE_UTIMES)
202 /* utimes allows msec timestamps to be set. */
203 *p_ts_res = TIMESTAMP_SET_MSEC;
204 #elif defined(HAVE_UTIME)
205 /* utime only allows sec timestamps to be set. */
206 *p_ts_res = TIMESTAMP_SET_SECONDS;
209 DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
211 "available on share %s, directory %s\n",
212 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
213 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
216 TALLOC_FREE(smb_fname_cpath);
220 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
221 struct dfs_GetDFSReferral *r)
223 struct junction_map *junction = NULL;
224 size_t consumedcnt = 0;
225 bool self_referral = false;
226 char *pathnamep = NULL;
227 char *local_dfs_path = NULL;
230 uint16_t max_referral_level = r->in.req.max_referral_level;
232 if (DEBUGLVL(DBGLVL_DEBUG)) {
233 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
236 /* get the junction entry */
237 if (r->in.req.servername == NULL) {
238 return NT_STATUS_NOT_FOUND;
242 * Trim pathname sent by client so it begins with only one backslash.
243 * Two backslashes confuse some dfs clients
246 local_dfs_path = talloc_strdup(r, r->in.req.servername);
247 if (local_dfs_path == NULL) {
248 return NT_STATUS_NO_MEMORY;
250 pathnamep = local_dfs_path;
251 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
252 IS_DIRECTORY_SEP(pathnamep[1])) {
256 junction = talloc_zero(r, struct junction_map);
257 if (junction == NULL) {
258 return NT_STATUS_NO_MEMORY;
261 /* The following call can change cwd. */
262 status = get_referred_path(r,
263 handle->conn->session_info,
265 handle->conn->sconn->remote_address,
266 handle->conn->sconn->local_address,
267 junction, &consumedcnt, &self_referral);
268 if (!NT_STATUS_IS_OK(status)) {
269 struct smb_filename connectpath_fname = {
270 .base_name = handle->conn->connectpath
272 vfs_ChDir(handle->conn, &connectpath_fname);
276 struct smb_filename connectpath_fname = {
277 .base_name = handle->conn->connectpath
279 vfs_ChDir(handle->conn, &connectpath_fname);
282 if (!self_referral) {
283 pathnamep[consumedcnt] = '\0';
285 if (DEBUGLVL(DBGLVL_INFO)) {
286 dbgtext("Path %s to alternate path(s):",
288 for (i=0; i < junction->referral_count; i++) {
290 junction->referral_list[i].alternate_path);
296 if (r->in.req.max_referral_level <= 2) {
297 max_referral_level = 2;
299 if (r->in.req.max_referral_level >= 3) {
300 max_referral_level = 3;
303 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
304 if (r->out.resp == NULL) {
305 return NT_STATUS_NO_MEMORY;
308 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
309 r->out.resp->nb_referrals = junction->referral_count;
311 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
313 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
316 r->out.resp->referral_entries = talloc_zero_array(r,
317 struct dfs_referral_type,
318 r->out.resp->nb_referrals);
319 if (r->out.resp->referral_entries == NULL) {
320 return NT_STATUS_NO_MEMORY;
323 switch (max_referral_level) {
325 for(i=0; i < junction->referral_count; i++) {
326 struct referral *ref = &junction->referral_list[i];
327 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
328 struct dfs_referral_type *t =
329 &r->out.resp->referral_entries[i];
330 struct dfs_referral_v2 *v2 = &t->referral.v2;
333 v2->size = VERSION2_REFERRAL_SIZE;
335 v2->server_type = DFS_SERVER_ROOT;
337 v2->server_type = DFS_SERVER_NON_ROOT;
340 v2->proximity = ref->proximity;
342 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
343 if (v2->DFS_path == NULL) {
344 return NT_STATUS_NO_MEMORY;
346 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
347 if (v2->DFS_alt_path == NULL) {
348 return NT_STATUS_NO_MEMORY;
350 v2->netw_address = talloc_strdup(mem_ctx,
351 ref->alternate_path);
352 if (v2->netw_address == NULL) {
353 return NT_STATUS_NO_MEMORY;
359 for(i=0; i < junction->referral_count; i++) {
360 struct referral *ref = &junction->referral_list[i];
361 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
362 struct dfs_referral_type *t =
363 &r->out.resp->referral_entries[i];
364 struct dfs_referral_v3 *v3 = &t->referral.v3;
365 struct dfs_normal_referral *r1 = &v3->referrals.r1;
368 v3->size = VERSION3_REFERRAL_SIZE;
370 v3->server_type = DFS_SERVER_ROOT;
372 v3->server_type = DFS_SERVER_NON_ROOT;
376 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
377 if (r1->DFS_path == NULL) {
378 return NT_STATUS_NO_MEMORY;
380 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
381 if (r1->DFS_alt_path == NULL) {
382 return NT_STATUS_NO_MEMORY;
384 r1->netw_address = talloc_strdup(mem_ctx,
385 ref->alternate_path);
386 if (r1->netw_address == NULL) {
387 return NT_STATUS_NO_MEMORY;
392 DBG_ERR("Invalid dfs referral version: %d\n",
394 return NT_STATUS_INVALID_LEVEL;
397 if (DEBUGLVL(DBGLVL_DEBUG)) {
398 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
404 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
405 struct files_struct *dirfsp,
406 const struct smb_filename *smb_fname,
407 const struct referral *reflist,
408 size_t referral_count)
410 TALLOC_CTX *frame = talloc_stackframe();
411 NTSTATUS status = NT_STATUS_NO_MEMORY;
413 char *msdfs_link = NULL;
415 /* Form the msdfs_link contents */
416 msdfs_link = msdfs_link_string(frame,
419 if (msdfs_link == NULL) {
423 ret = symlinkat(msdfs_link,
424 fsp_get_pathref_fd(dirfsp),
425 smb_fname->base_name);
427 status = NT_STATUS_OK;
429 status = map_nt_error_from_unix(errno);
439 * Read and return the contents of a DFS redirect given a
440 * pathname. A caller can pass in NULL for ppreflist and
441 * preferral_count but still determine if this was a
442 * DFS redirect point by getting NT_STATUS_OK back
443 * without incurring the overhead of reading and parsing
444 * the referral contents.
447 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
449 struct files_struct *dirfsp,
450 struct smb_filename *smb_fname,
451 struct referral **ppreflist,
452 size_t *preferral_count)
454 NTSTATUS status = NT_STATUS_NO_MEMORY;
456 char *link_target = NULL;
459 #if defined(HAVE_BROKEN_READLINK)
460 char link_target_buf[PATH_MAX];
462 char link_target_buf[7];
466 if (is_named_stream(smb_fname)) {
467 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
471 if (ppreflist == NULL && preferral_count == NULL) {
473 * We're only checking if this is a DFS
474 * redirect. We don't need to return data.
476 bufsize = sizeof(link_target_buf);
477 link_target = link_target_buf;
480 link_target = talloc_array(mem_ctx, char, bufsize);
486 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
487 smb_fname->base_name,
490 if (referral_len == -1) {
491 if (errno == EINVAL) {
493 * If the path isn't a link, readlinkat
494 * returns EINVAL. Allow the caller to
497 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
498 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
500 status = map_nt_error_from_unix(errno);
501 if (errno == ENOENT) {
502 DBG_NOTICE("Error reading "
503 "msdfs link %s: %s\n",
504 smb_fname->base_name,
507 DBG_ERR("Error reading "
508 "msdfs link %s: %s\n",
509 smb_fname->base_name,
515 link_target[referral_len] = '\0';
517 DBG_INFO("%s -> %s\n",
518 smb_fname->base_name,
521 if (!strnequal(link_target, "msdfs:", 6)) {
522 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
526 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
527 smb_fname->base_name,
530 lp_fake_directory_create_times(SNUM(handle->conn)));
532 status = map_nt_error_from_unix(errno);
536 if (ppreflist == NULL && preferral_count == NULL) {
537 /* Early return for checking if this is a DFS link. */
541 ok = parse_msdfs_symlink(mem_ctx,
542 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
548 status = NT_STATUS_OK;
550 status = NT_STATUS_NO_MEMORY;
555 if (link_target != link_target_buf) {
556 TALLOC_FREE(link_target);
561 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
563 const char *service_path,
566 return NT_STATUS_NOT_SUPPORTED;
569 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
571 const char *base_volume,
577 return NT_STATUS_NOT_SUPPORTED;
580 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
585 return NT_STATUS_NOT_SUPPORTED;
588 /* Directory operations */
590 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
597 START_PROFILE(syscall_fdopendir);
598 result = sys_fdopendir(fsp_get_io_fd(fsp));
599 END_PROFILE(syscall_fdopendir);
603 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
604 struct files_struct *dirfsp,
607 struct dirent *result;
609 START_PROFILE(syscall_readdir);
611 result = readdir(dirp);
612 END_PROFILE(syscall_readdir);
617 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
618 struct files_struct *fsp,
620 struct readdir_attr_data **attr_data)
622 return NT_STATUS_NOT_SUPPORTED;
625 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
627 START_PROFILE(syscall_rewinddir);
629 END_PROFILE(syscall_rewinddir);
632 static int vfswrap_mkdirat(vfs_handle_struct *handle,
633 struct files_struct *dirfsp,
634 const struct smb_filename *smb_fname,
639 START_PROFILE(syscall_mkdirat);
641 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
643 END_PROFILE(syscall_mkdirat);
647 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
651 START_PROFILE(syscall_closedir);
652 result = closedir(dirp);
653 END_PROFILE(syscall_closedir);
657 /* File operations */
659 static int vfswrap_openat(vfs_handle_struct *handle,
660 const struct files_struct *dirfsp,
661 const struct smb_filename *smb_fname,
663 const struct vfs_open_how *how)
665 int flags = how->flags;
666 mode_t mode = how->mode;
667 bool have_opath = false;
668 bool became_root = false;
671 START_PROFILE(syscall_openat);
673 if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
674 VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
680 SMB_ASSERT(!is_named_stream(smb_fname));
684 if (fsp->fsp_flags.is_pathref) {
687 if (flags & O_PATH) {
689 * From "man 2 openat":
691 * When O_PATH is specified in flags, flag bits other than
692 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
694 * From "man 2 openat2":
696 * Whereas openat(2) ignores unknown bits in its flags
697 * argument, openat2() returns an error if unknown or
698 * conflicting flags are specified in how.flags.
700 * So we better clear ignored/invalid flags
701 * and only keep the expected ones.
703 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
707 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
708 struct open_how linux_how = {
711 .resolve = RESOLVE_NO_SYMLINKS,
714 result = openat2(fsp_get_pathref_fd(dirfsp),
715 smb_fname->base_name,
719 if (errno == ENOSYS) {
721 * The kernel doesn't support
722 * openat2(), so indicate to
724 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
725 * would just be a waste of time.
727 fsp->conn->open_how_resolve &=
728 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
736 if (fsp->fsp_flags.is_pathref && !have_opath) {
741 result = openat(fsp_get_pathref_fd(dirfsp),
742 smb_fname->base_name,
754 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
757 * "/proc/self/fd/-1" never exists. Indicate to upper
758 * layers that for this fsp a possible name-based
759 * fallback is the only way to go.
761 fsp->fsp_flags.have_proc_fds = false;
765 END_PROFILE(syscall_openat);
768 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
769 struct smb_request *req,
770 struct files_struct *dirfsp,
771 struct smb_filename *smb_fname,
772 uint32_t access_mask,
773 uint32_t share_access,
774 uint32_t create_disposition,
775 uint32_t create_options,
776 uint32_t file_attributes,
777 uint32_t oplock_request,
778 const struct smb2_lease *lease,
779 uint64_t allocation_size,
780 uint32_t private_flags,
781 struct security_descriptor *sd,
782 struct ea_list *ea_list,
783 files_struct **result,
785 const struct smb2_create_blobs *in_context_blobs,
786 struct smb2_create_blobs *out_context_blobs)
788 return create_file_default(handle->conn, req, dirfsp, smb_fname,
789 access_mask, share_access,
790 create_disposition, create_options,
791 file_attributes, oplock_request, lease,
792 allocation_size, private_flags,
794 pinfo, in_context_blobs, out_context_blobs);
797 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
801 START_PROFILE(syscall_close);
802 result = fd_close_posix(fsp);
803 END_PROFILE(syscall_close);
807 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
808 size_t n, off_t offset)
812 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
813 START_PROFILE_BYTES(syscall_pread, n);
814 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
815 END_PROFILE_BYTES(syscall_pread);
817 if (result == -1 && errno == ESPIPE) {
818 /* Maintain the fiction that pipes can be seeked (sought?) on. */
819 result = sys_read(fsp_get_io_fd(fsp), data, n);
820 fh_set_pos(fsp->fh, 0);
823 #else /* HAVE_PREAD */
826 #endif /* HAVE_PREAD */
831 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
832 size_t n, off_t offset)
836 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
837 START_PROFILE_BYTES(syscall_pwrite, n);
838 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
839 END_PROFILE_BYTES(syscall_pwrite);
841 if (result == -1 && errno == ESPIPE) {
842 /* Maintain the fiction that pipes can be sought on. */
843 result = sys_write(fsp_get_io_fd(fsp), data, n);
846 #else /* HAVE_PWRITE */
849 #endif /* HAVE_PWRITE */
854 struct vfswrap_pread_state {
861 struct vfs_aio_state vfs_aio_state;
862 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
865 static void vfs_pread_do(void *private_data);
866 static void vfs_pread_done(struct tevent_req *subreq);
867 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
869 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
871 struct tevent_context *ev,
872 struct files_struct *fsp,
874 size_t n, off_t offset)
876 struct tevent_req *req, *subreq;
877 struct vfswrap_pread_state *state;
879 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
885 state->fd = fsp_get_io_fd(fsp);
888 state->offset = offset;
890 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
891 state->profile_bytes, n);
892 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
894 subreq = pthreadpool_tevent_job_send(
895 state, ev, handle->conn->sconn->pool,
896 vfs_pread_do, state);
897 if (tevent_req_nomem(subreq, req)) {
898 return tevent_req_post(req, ev);
900 tevent_req_set_callback(subreq, vfs_pread_done, req);
902 talloc_set_destructor(state, vfs_pread_state_destructor);
907 static void vfs_pread_do(void *private_data)
909 struct vfswrap_pread_state *state = talloc_get_type_abort(
910 private_data, struct vfswrap_pread_state);
911 struct timespec start_time;
912 struct timespec end_time;
914 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
916 PROFILE_TIMESTAMP(&start_time);
918 state->ret = sys_pread_full(state->fd,
923 if (state->ret == -1) {
924 state->vfs_aio_state.error = errno;
927 PROFILE_TIMESTAMP(&end_time);
929 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
931 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
934 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
939 static void vfs_pread_done(struct tevent_req *subreq)
941 struct tevent_req *req = tevent_req_callback_data(
942 subreq, struct tevent_req);
943 struct vfswrap_pread_state *state = tevent_req_data(
944 req, struct vfswrap_pread_state);
947 ret = pthreadpool_tevent_job_recv(subreq);
949 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
950 talloc_set_destructor(state, NULL);
953 tevent_req_error(req, ret);
957 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
958 * means the lower level pthreadpool failed to create a new
959 * thread. Fallback to sync processing in that case to allow
960 * some progress for the client.
965 tevent_req_done(req);
968 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
969 struct vfs_aio_state *vfs_aio_state)
971 struct vfswrap_pread_state *state = tevent_req_data(
972 req, struct vfswrap_pread_state);
974 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
978 *vfs_aio_state = state->vfs_aio_state;
982 struct vfswrap_pwrite_state {
989 struct vfs_aio_state vfs_aio_state;
990 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
993 static void vfs_pwrite_do(void *private_data);
994 static void vfs_pwrite_done(struct tevent_req *subreq);
995 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
997 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
999 struct tevent_context *ev,
1000 struct files_struct *fsp,
1002 size_t n, off_t offset)
1004 struct tevent_req *req, *subreq;
1005 struct vfswrap_pwrite_state *state;
1007 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1013 state->fd = fsp_get_io_fd(fsp);
1016 state->offset = offset;
1018 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1019 state->profile_bytes, n);
1020 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1022 subreq = pthreadpool_tevent_job_send(
1023 state, ev, handle->conn->sconn->pool,
1024 vfs_pwrite_do, state);
1025 if (tevent_req_nomem(subreq, req)) {
1026 return tevent_req_post(req, ev);
1028 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1030 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1035 static void vfs_pwrite_do(void *private_data)
1037 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1038 private_data, struct vfswrap_pwrite_state);
1039 struct timespec start_time;
1040 struct timespec end_time;
1042 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1044 PROFILE_TIMESTAMP(&start_time);
1046 state->ret = sys_pwrite_full(state->fd,
1051 if (state->ret == -1) {
1052 state->vfs_aio_state.error = errno;
1055 PROFILE_TIMESTAMP(&end_time);
1057 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1059 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1062 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1067 static void vfs_pwrite_done(struct tevent_req *subreq)
1069 struct tevent_req *req = tevent_req_callback_data(
1070 subreq, struct tevent_req);
1071 struct vfswrap_pwrite_state *state = tevent_req_data(
1072 req, struct vfswrap_pwrite_state);
1075 ret = pthreadpool_tevent_job_recv(subreq);
1076 TALLOC_FREE(subreq);
1077 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1078 talloc_set_destructor(state, NULL);
1080 if (ret != EAGAIN) {
1081 tevent_req_error(req, ret);
1085 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1086 * means the lower level pthreadpool failed to create a new
1087 * thread. Fallback to sync processing in that case to allow
1088 * some progress for the client.
1090 vfs_pwrite_do(state);
1093 tevent_req_done(req);
1096 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1097 struct vfs_aio_state *vfs_aio_state)
1099 struct vfswrap_pwrite_state *state = tevent_req_data(
1100 req, struct vfswrap_pwrite_state);
1102 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1106 *vfs_aio_state = state->vfs_aio_state;
1110 struct vfswrap_fsync_state {
1114 struct vfs_aio_state vfs_aio_state;
1115 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1118 static void vfs_fsync_do(void *private_data);
1119 static void vfs_fsync_done(struct tevent_req *subreq);
1120 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1122 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1123 TALLOC_CTX *mem_ctx,
1124 struct tevent_context *ev,
1125 struct files_struct *fsp)
1127 struct tevent_req *req, *subreq;
1128 struct vfswrap_fsync_state *state;
1130 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1136 state->fd = fsp_get_io_fd(fsp);
1138 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1139 state->profile_bytes, 0);
1140 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1142 subreq = pthreadpool_tevent_job_send(
1143 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1144 if (tevent_req_nomem(subreq, req)) {
1145 return tevent_req_post(req, ev);
1147 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1149 talloc_set_destructor(state, vfs_fsync_state_destructor);
1154 static void vfs_fsync_do(void *private_data)
1156 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1157 private_data, struct vfswrap_fsync_state);
1158 struct timespec start_time;
1159 struct timespec end_time;
1161 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1163 PROFILE_TIMESTAMP(&start_time);
1166 state->ret = fsync(state->fd);
1167 } while ((state->ret == -1) && (errno == EINTR));
1169 if (state->ret == -1) {
1170 state->vfs_aio_state.error = errno;
1173 PROFILE_TIMESTAMP(&end_time);
1175 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1177 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1180 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1185 static void vfs_fsync_done(struct tevent_req *subreq)
1187 struct tevent_req *req = tevent_req_callback_data(
1188 subreq, struct tevent_req);
1189 struct vfswrap_fsync_state *state = tevent_req_data(
1190 req, struct vfswrap_fsync_state);
1193 ret = pthreadpool_tevent_job_recv(subreq);
1194 TALLOC_FREE(subreq);
1195 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1196 talloc_set_destructor(state, NULL);
1198 if (ret != EAGAIN) {
1199 tevent_req_error(req, ret);
1203 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1204 * means the lower level pthreadpool failed to create a new
1205 * thread. Fallback to sync processing in that case to allow
1206 * some progress for the client.
1208 vfs_fsync_do(state);
1211 tevent_req_done(req);
1214 static int vfswrap_fsync_recv(struct tevent_req *req,
1215 struct vfs_aio_state *vfs_aio_state)
1217 struct vfswrap_fsync_state *state = tevent_req_data(
1218 req, struct vfswrap_fsync_state);
1220 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1224 *vfs_aio_state = state->vfs_aio_state;
1228 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1232 START_PROFILE(syscall_lseek);
1234 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1236 * We want to maintain the fiction that we can seek
1237 * on a fifo for file system purposes. This allows
1238 * people to set up UNIX fifo's that feed data to Windows
1239 * applications. JRA.
1242 if((result == -1) && (errno == ESPIPE)) {
1247 END_PROFILE(syscall_lseek);
1251 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1252 off_t offset, size_t n)
1256 START_PROFILE_BYTES(syscall_sendfile, n);
1257 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1258 END_PROFILE_BYTES(syscall_sendfile);
1262 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1264 files_struct *tofsp,
1270 START_PROFILE_BYTES(syscall_recvfile, n);
1271 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1272 END_PROFILE_BYTES(syscall_recvfile);
1276 static int vfswrap_renameat(vfs_handle_struct *handle,
1277 files_struct *srcfsp,
1278 const struct smb_filename *smb_fname_src,
1279 files_struct *dstfsp,
1280 const struct smb_filename *smb_fname_dst)
1284 START_PROFILE(syscall_renameat);
1286 SMB_ASSERT(!is_named_stream(smb_fname_src));
1287 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1289 result = renameat(fsp_get_pathref_fd(srcfsp),
1290 smb_fname_src->base_name,
1291 fsp_get_pathref_fd(dstfsp),
1292 smb_fname_dst->base_name);
1294 END_PROFILE(syscall_renameat);
1298 static int vfswrap_stat(vfs_handle_struct *handle,
1299 struct smb_filename *smb_fname)
1303 START_PROFILE(syscall_stat);
1305 SMB_ASSERT(!is_named_stream(smb_fname));
1307 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1308 lp_fake_directory_create_times(SNUM(handle->conn)));
1310 END_PROFILE(syscall_stat);
1314 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1318 START_PROFILE(syscall_fstat);
1319 result = sys_fstat(fsp_get_pathref_fd(fsp),
1320 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1321 END_PROFILE(syscall_fstat);
1325 static int vfswrap_lstat(vfs_handle_struct *handle,
1326 struct smb_filename *smb_fname)
1330 START_PROFILE(syscall_lstat);
1332 SMB_ASSERT(!is_named_stream(smb_fname));
1334 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1335 lp_fake_directory_create_times(SNUM(handle->conn)));
1337 END_PROFILE(syscall_lstat);
1341 static int vfswrap_fstatat(
1342 struct vfs_handle_struct *handle,
1343 const struct files_struct *dirfsp,
1344 const struct smb_filename *smb_fname,
1345 SMB_STRUCT_STAT *sbuf,
1350 START_PROFILE(syscall_fstatat);
1352 SMB_ASSERT(!is_named_stream(smb_fname));
1354 result = sys_fstatat(
1355 fsp_get_pathref_fd(dirfsp),
1356 smb_fname->base_name,
1359 lp_fake_directory_create_times(SNUM(handle->conn)));
1361 END_PROFILE(syscall_fstatat);
1365 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1367 enum vfs_translate_direction direction,
1368 TALLOC_CTX *mem_ctx,
1371 return NT_STATUS_NONE_MAPPED;
1375 * Return allocated parent directory and basename of path
1377 * Note: if requesting atname, it is returned as talloc child of the
1378 * parent. Freeing the parent is thus sufficient to free both.
1380 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1381 TALLOC_CTX *mem_ctx,
1382 const struct smb_filename *smb_fname_in,
1383 struct smb_filename **parent_dir_out,
1384 struct smb_filename **atname_out)
1386 struct smb_filename *parent = NULL;
1387 struct smb_filename *name = NULL;
1390 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1391 if (parent == NULL) {
1392 return NT_STATUS_NO_MEMORY;
1394 SET_STAT_INVALID(parent->st);
1396 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1398 TALLOC_FREE(parent->base_name);
1399 parent->base_name = talloc_strdup(parent, ".");
1400 if (parent->base_name == NULL) {
1401 TALLOC_FREE(parent);
1402 return NT_STATUS_NO_MEMORY;
1404 p = smb_fname_in->base_name;
1410 if (atname_out == NULL) {
1411 *parent_dir_out = parent;
1412 return NT_STATUS_OK;
1415 name = synthetic_smb_fname(
1418 smb_fname_in->stream_name,
1421 smb_fname_in->flags);
1423 return NT_STATUS_NO_MEMORY;
1426 *parent_dir_out = parent;
1428 return NT_STATUS_OK;
1432 * Implement the default fsctl operation.
1434 static bool vfswrap_logged_ioctl_message = false;
1436 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1437 struct files_struct *fsp,
1440 uint16_t req_flags, /* Needed for UNICODE ... */
1441 const uint8_t *_in_data,
1443 uint8_t **_out_data,
1444 uint32_t max_out_len,
1447 const char *in_data = (const char *)_in_data;
1448 char **out_data = (char **)_out_data;
1452 * Currently all fsctls operate on the base
1453 * file if given an alternate data stream.
1454 * Revisit this if we implement fsctls later
1455 * that need access to the ADS handle.
1457 fsp = metadata_fsp(fsp);
1460 case FSCTL_SET_SPARSE:
1462 bool set_sparse = true;
1464 if (in_len >= 1 && in_data[0] == 0) {
1468 status = file_set_sparse(handle->conn, fsp, set_sparse);
1470 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1471 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1472 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1473 nt_errstr(status)));
1478 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1480 unsigned char objid[16];
1481 char *return_data = NULL;
1483 /* This should return the object-id on this file.
1484 * I think I'll make this be the inode+dev. JRA.
1487 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1490 *out_len = MIN(max_out_len, 64);
1492 /* Hmmm, will this cause problems if less data asked for? */
1493 return_data = talloc_array(ctx, char, 64);
1494 if (return_data == NULL) {
1495 return NT_STATUS_NO_MEMORY;
1498 /* For backwards compatibility only store the dev/inode. */
1499 push_file_id_16(return_data, &fsp->file_id);
1500 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1501 push_file_id_16(return_data+32, &fsp->file_id);
1502 memset(return_data+48, 0, 16);
1503 *out_data = return_data;
1504 return NT_STATUS_OK;
1507 case FSCTL_GET_REPARSE_POINT:
1509 status = fsctl_get_reparse_point(
1510 fsp, ctx, out_data, max_out_len, out_len);
1514 case FSCTL_SET_REPARSE_POINT:
1516 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1520 case FSCTL_DELETE_REPARSE_POINT:
1522 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1526 case FSCTL_GET_SHADOW_COPY_DATA:
1529 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1530 * and return their volume names. If max_data_count is 16, then it is just
1531 * asking for the number of volumes and length of the combined names.
1533 * pdata is the data allocated by our caller, but that uses
1534 * total_data_count (which is 0 in our case) rather than max_data_count.
1535 * Allocate the correct amount and return the pointer to let
1536 * it be deallocated when we return.
1538 struct shadow_copy_data *shadow_data = NULL;
1539 bool labels = False;
1540 uint32_t labels_data_count = 0;
1542 char *cur_pdata = NULL;
1544 if (max_out_len < 16) {
1545 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1547 return NT_STATUS_INVALID_PARAMETER;
1550 if (max_out_len > 16) {
1554 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1555 if (shadow_data == NULL) {
1556 DBG_ERR("TALLOC_ZERO() failed!\n");
1557 return NT_STATUS_NO_MEMORY;
1561 * Call the VFS routine to actually do the work.
1563 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1564 int log_lev = DBGLVL_ERR;
1566 /* broken module didn't set errno on error */
1567 status = NT_STATUS_UNSUCCESSFUL;
1569 status = map_nt_error_from_unix(errno);
1570 if (NT_STATUS_EQUAL(status,
1571 NT_STATUS_NOT_SUPPORTED)) {
1572 log_lev = DBGLVL_INFO;
1575 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1576 "connectpath %s, failed - %s.\n",
1577 fsp->conn->connectpath,
1578 nt_errstr(status)));
1579 TALLOC_FREE(shadow_data);
1583 labels_data_count = (shadow_data->num_volumes * 2 *
1584 sizeof(SHADOW_COPY_LABEL)) + 2;
1589 *out_len = 12 + labels_data_count;
1592 if (max_out_len < *out_len) {
1593 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1594 max_out_len, *out_len);
1595 TALLOC_FREE(shadow_data);
1596 return NT_STATUS_BUFFER_TOO_SMALL;
1599 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1600 if (cur_pdata == NULL) {
1601 TALLOC_FREE(shadow_data);
1602 return NT_STATUS_NO_MEMORY;
1605 *out_data = cur_pdata;
1607 /* num_volumes 4 bytes */
1608 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1611 /* num_labels 4 bytes */
1612 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1615 /* needed_data_count 4 bytes */
1616 SIVAL(cur_pdata, 8, labels_data_count);
1620 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1621 shadow_data->num_volumes, fsp_str_dbg(fsp));
1622 if (labels && shadow_data->labels) {
1623 for (i=0; i<shadow_data->num_volumes; i++) {
1625 status = srvstr_push(cur_pdata, req_flags,
1626 cur_pdata, shadow_data->labels[i],
1627 2 * sizeof(SHADOW_COPY_LABEL),
1628 STR_UNICODE|STR_TERMINATE, &len);
1629 if (!NT_STATUS_IS_OK(status)) {
1630 TALLOC_FREE(*out_data);
1631 TALLOC_FREE(shadow_data);
1634 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1635 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1639 TALLOC_FREE(shadow_data);
1641 return NT_STATUS_OK;
1644 case FSCTL_FIND_FILES_BY_SID:
1646 /* pretend this succeeded -
1648 * we have to send back a list with all files owned by this SID
1650 * but I have to check that --metze
1654 struct dom_sid_buf buf;
1658 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1662 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1663 return NT_STATUS_INVALID_PARAMETER;
1666 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1668 /* unknown 4 bytes: this is not the length of the sid :-( */
1669 /*unknown = IVAL(pdata,0);*/
1671 ret = sid_parse(_in_data + 4, sid_len, &sid);
1673 return NT_STATUS_INVALID_PARAMETER;
1675 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1676 dom_sid_str_buf(&sid, &buf)));
1678 if (!sid_to_uid(&sid, &uid)) {
1679 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1680 dom_sid_str_buf(&sid, &buf),
1681 (unsigned long)sid_len);
1685 /* we can take a look at the find source :-)
1687 * find ./ -uid $uid -name '*' is what we need here
1690 * and send 4bytes len and then NULL terminated unicode strings
1693 * but I don't know how to deal with the paged results
1694 * (maybe we can hang the result anywhere in the fsp struct)
1696 * but I don't know how to deal with the paged results
1697 * (maybe we can hang the result anywhere in the fsp struct)
1699 * we don't send all files at once
1700 * and at the next we should *not* start from the beginning,
1701 * so we have to cache the result
1706 /* this works for now... */
1707 return NT_STATUS_OK;
1710 case FSCTL_QUERY_ALLOCATED_RANGES:
1712 /* FIXME: This is just a dummy reply, telling that all of the
1713 * file is allocated. MKS cp needs that.
1714 * Adding the real allocated ranges via FIEMAP on Linux
1715 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1716 * this FSCTL correct for sparse files.
1718 uint64_t offset, length;
1719 char *out_data_tmp = NULL;
1722 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1724 return NT_STATUS_INVALID_PARAMETER;
1727 if (max_out_len < 16) {
1728 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1730 return NT_STATUS_INVALID_PARAMETER;
1733 offset = BVAL(in_data,0);
1734 length = BVAL(in_data,8);
1736 if (offset + length < offset) {
1737 /* No 64-bit integer wrap. */
1738 return NT_STATUS_INVALID_PARAMETER;
1741 /* Shouldn't this be SMB_VFS_STAT ... ? */
1742 status = vfs_stat_fsp(fsp);
1743 if (!NT_STATUS_IS_OK(status)) {
1748 out_data_tmp = talloc_array(ctx, char, *out_len);
1749 if (out_data_tmp == NULL) {
1750 DBG_DEBUG("unable to allocate memory for response\n");
1751 return NT_STATUS_NO_MEMORY;
1754 if (offset > fsp->fsp_name->st.st_ex_size ||
1755 fsp->fsp_name->st.st_ex_size == 0 ||
1757 memset(out_data_tmp, 0, *out_len);
1759 uint64_t end = offset + length;
1760 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1761 SBVAL(out_data_tmp, 0, 0);
1762 SBVAL(out_data_tmp, 8, end);
1765 *out_data = out_data_tmp;
1767 return NT_STATUS_OK;
1770 case FSCTL_IS_VOLUME_DIRTY:
1772 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1773 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1775 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1776 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1778 return NT_STATUS_INVALID_PARAMETER;
1783 * Only print once ... unfortunately there could be lots of
1784 * different FSCTLs that are called.
1786 if (!vfswrap_logged_ioctl_message) {
1787 vfswrap_logged_ioctl_message = true;
1788 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1789 __func__, function);
1793 return NT_STATUS_NOT_SUPPORTED;
1796 static bool vfswrap_is_offline(struct connection_struct *conn,
1797 const struct smb_filename *fname);
1799 struct vfswrap_get_dos_attributes_state {
1800 struct vfs_aio_state aio_state;
1801 connection_struct *conn;
1802 TALLOC_CTX *mem_ctx;
1803 struct tevent_context *ev;
1804 files_struct *dir_fsp;
1805 struct smb_filename *smb_fname;
1810 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1812 static struct tevent_req *vfswrap_get_dos_attributes_send(
1813 TALLOC_CTX *mem_ctx,
1814 struct tevent_context *ev,
1815 struct vfs_handle_struct *handle,
1816 files_struct *dir_fsp,
1817 struct smb_filename *smb_fname)
1819 struct tevent_req *req = NULL;
1820 struct tevent_req *subreq = NULL;
1821 struct vfswrap_get_dos_attributes_state *state = NULL;
1823 SMB_ASSERT(!is_named_stream(smb_fname));
1825 req = tevent_req_create(mem_ctx, &state,
1826 struct vfswrap_get_dos_attributes_state);
1831 *state = (struct vfswrap_get_dos_attributes_state) {
1832 .conn = dir_fsp->conn,
1836 .smb_fname = smb_fname,
1839 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1840 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1841 "\"store dos attributes\" is disabled\n",
1842 dir_fsp->conn->connectpath);
1843 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1844 return tevent_req_post(req, ev);
1847 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1851 SAMBA_XATTR_DOS_ATTRIB,
1853 if (tevent_req_nomem(subreq, req)) {
1854 return tevent_req_post(req, ev);
1856 tevent_req_set_callback(subreq,
1857 vfswrap_get_dos_attributes_getxattr_done,
1863 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1865 struct tevent_req *req =
1866 tevent_req_callback_data(subreq,
1868 struct vfswrap_get_dos_attributes_state *state =
1869 tevent_req_data(req,
1870 struct vfswrap_get_dos_attributes_state);
1872 DATA_BLOB blob = {0};
1874 char *tofree = NULL;
1875 char pathbuf[PATH_MAX+1];
1877 struct smb_filename smb_fname;
1881 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1885 TALLOC_FREE(subreq);
1886 if (xattr_size == -1) {
1887 status = map_nt_error_from_unix(state->aio_state.error);
1889 if (state->as_root) {
1890 tevent_req_nterror(req, status);
1893 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1894 tevent_req_nterror(req, status);
1898 state->as_root = true;
1901 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1905 SAMBA_XATTR_DOS_ATTRIB,
1908 if (tevent_req_nomem(subreq, req)) {
1911 tevent_req_set_callback(subreq,
1912 vfswrap_get_dos_attributes_getxattr_done,
1917 blob.length = xattr_size;
1919 status = parse_dos_attribute_blob(state->smb_fname,
1922 if (!NT_STATUS_IS_OK(status)) {
1923 tevent_req_nterror(req, status);
1927 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1928 state->smb_fname->base_name,
1933 if (pathlen == -1) {
1934 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1938 smb_fname = (struct smb_filename) {
1940 .st = state->smb_fname->st,
1941 .flags = state->smb_fname->flags,
1942 .twrp = state->smb_fname->twrp,
1945 offline = vfswrap_is_offline(state->conn, &smb_fname);
1947 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1949 TALLOC_FREE(tofree);
1951 tevent_req_done(req);
1955 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1956 struct vfs_aio_state *aio_state,
1959 struct vfswrap_get_dos_attributes_state *state =
1960 tevent_req_data(req,
1961 struct vfswrap_get_dos_attributes_state);
1964 if (tevent_req_is_nterror(req, &status)) {
1965 tevent_req_received(req);
1969 *aio_state = state->aio_state;
1970 *dosmode = state->dosmode;
1971 tevent_req_received(req);
1972 return NT_STATUS_OK;
1975 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1976 struct files_struct *fsp,
1981 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1983 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1985 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1988 return fget_ea_dos_attribute(fsp, dosmode);
1991 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1992 struct files_struct *fsp,
1995 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1997 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2000 static struct vfs_offload_ctx *vfswrap_offload_ctx;
2002 struct vfswrap_offload_read_state {
2006 static struct tevent_req *vfswrap_offload_read_send(
2007 TALLOC_CTX *mem_ctx,
2008 struct tevent_context *ev,
2009 struct vfs_handle_struct *handle,
2010 struct files_struct *fsp,
2016 struct tevent_req *req = NULL;
2017 struct vfswrap_offload_read_state *state = NULL;
2020 req = tevent_req_create(mem_ctx, &state,
2021 struct vfswrap_offload_read_state);
2026 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2027 &vfswrap_offload_ctx);
2028 if (tevent_req_nterror(req, status)) {
2029 return tevent_req_post(req, ev);
2032 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2033 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2034 return tevent_req_post(req, ev);
2037 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2039 if (tevent_req_nterror(req, status)) {
2040 return tevent_req_post(req, ev);
2043 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2045 if (tevent_req_nterror(req, status)) {
2046 return tevent_req_post(req, ev);
2049 tevent_req_done(req);
2050 return tevent_req_post(req, ev);
2053 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2054 struct vfs_handle_struct *handle,
2055 TALLOC_CTX *mem_ctx,
2060 struct vfswrap_offload_read_state *state = tevent_req_data(
2061 req, struct vfswrap_offload_read_state);
2064 if (tevent_req_is_nterror(req, &status)) {
2065 tevent_req_received(req);
2071 token->length = state->token.length;
2072 token->data = talloc_move(mem_ctx, &state->token.data);
2074 tevent_req_received(req);
2075 return NT_STATUS_OK;
2078 struct vfswrap_offload_write_state {
2080 bool read_lck_locked;
2081 bool write_lck_locked;
2083 struct tevent_context *src_ev;
2084 struct files_struct *src_fsp;
2086 struct tevent_context *dst_ev;
2087 struct files_struct *dst_fsp;
2092 size_t next_io_size;
2095 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2096 enum tevent_req_state req_state)
2098 struct vfswrap_offload_write_state *state = tevent_req_data(
2099 req, struct vfswrap_offload_write_state);
2102 if (state->dst_fsp == NULL) {
2106 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2108 state->dst_fsp = NULL;
2111 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2112 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2114 static struct tevent_req *vfswrap_offload_write_send(
2115 struct vfs_handle_struct *handle,
2116 TALLOC_CTX *mem_ctx,
2117 struct tevent_context *ev,
2120 off_t transfer_offset,
2121 struct files_struct *dest_fsp,
2125 struct tevent_req *req;
2126 struct vfswrap_offload_write_state *state = NULL;
2127 /* off_t is signed! */
2128 off_t max_offset = INT64_MAX - to_copy;
2129 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2130 files_struct *src_fsp = NULL;
2134 req = tevent_req_create(mem_ctx, &state,
2135 struct vfswrap_offload_write_state);
2140 *state = (struct vfswrap_offload_write_state) {
2142 .src_off = transfer_offset,
2144 .dst_fsp = dest_fsp,
2145 .dst_off = dest_off,
2147 .remaining = to_copy,
2150 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2153 case FSCTL_SRV_COPYCHUNK:
2154 case FSCTL_SRV_COPYCHUNK_WRITE:
2157 case FSCTL_OFFLOAD_WRITE:
2158 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2159 return tevent_req_post(req, ev);
2161 case FSCTL_DUP_EXTENTS_TO_FILE:
2162 DBG_DEBUG("COW clones not supported by vfs_default\n");
2163 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2164 return tevent_req_post(req, ev);
2167 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2168 return tevent_req_post(req, ev);
2172 * From here on we assume a copy-chunk fsctl
2176 tevent_req_done(req);
2177 return tevent_req_post(req, ev);
2180 if (state->src_off > max_offset) {
2182 * Protect integer checks below.
2184 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2185 return tevent_req_post(req, ev);
2187 if (state->src_off < 0) {
2189 * Protect integer checks below.
2191 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2192 return tevent_req_post(req, ev);
2194 if (state->dst_off > max_offset) {
2196 * Protect integer checks below.
2198 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2199 return tevent_req_post(req, ev);
2201 if (state->dst_off < 0) {
2203 * Protect integer checks below.
2205 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2206 return tevent_req_post(req, ev);
2209 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2211 if (tevent_req_nterror(req, status)) {
2212 return tevent_req_post(req, ev);
2215 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2217 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2218 if (!NT_STATUS_IS_OK(status)) {
2219 tevent_req_nterror(req, status);
2220 return tevent_req_post(req, ev);
2223 ok = change_to_user_and_service_by_fsp(src_fsp);
2225 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2226 return tevent_req_post(req, ev);
2229 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2230 state->src_fsp = src_fsp;
2232 status = vfs_stat_fsp(src_fsp);
2233 if (tevent_req_nterror(req, status)) {
2234 return tevent_req_post(req, ev);
2237 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2239 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2240 * If the SourceOffset or SourceOffset + Length extends beyond
2241 * the end of file, the server SHOULD<240> treat this as a
2242 * STATUS_END_OF_FILE error.
2244 * <240> Section 3.3.5.15.6: Windows servers will return
2245 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2247 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2248 return tevent_req_post(req, ev);
2251 status = vfswrap_offload_copy_file_range(req);
2252 if (NT_STATUS_IS_OK(status)) {
2253 tevent_req_done(req);
2254 return tevent_req_post(req, ev);
2256 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2257 tevent_req_nterror(req, status);
2258 return tevent_req_post(req, ev);
2261 state->buf = talloc_array(state, uint8_t, num);
2262 if (tevent_req_nomem(state->buf, req)) {
2263 return tevent_req_post(req, ev);
2266 status = vfswrap_offload_write_loop(req);
2267 if (!NT_STATUS_IS_OK(status)) {
2268 tevent_req_nterror(req, status);
2269 return tevent_req_post(req, ev);
2275 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2277 struct vfswrap_offload_write_state *state = tevent_req_data(
2278 req, struct vfswrap_offload_write_state);
2279 struct lock_struct lck;
2284 static bool try_copy_file_range = true;
2286 if (!try_copy_file_range) {
2287 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2290 same_file = file_id_equal(&state->src_fsp->file_id,
2291 &state->dst_fsp->file_id);
2293 sys_io_ranges_overlap(state->remaining,
2298 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2301 if (fsp_is_alternate_stream(state->src_fsp) ||
2302 fsp_is_alternate_stream(state->dst_fsp))
2304 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2307 init_strict_lock_struct(state->src_fsp,
2308 state->src_fsp->op->global->open_persistent_id,
2312 lp_posix_cifsu_locktype(state->src_fsp),
2315 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2319 return NT_STATUS_FILE_LOCK_CONFLICT;
2322 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2324 return NT_STATUS_INTERNAL_ERROR;
2327 init_strict_lock_struct(state->dst_fsp,
2328 state->dst_fsp->op->global->open_persistent_id,
2332 lp_posix_cifsu_locktype(state->dst_fsp),
2335 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2339 return NT_STATUS_FILE_LOCK_CONFLICT;
2342 while (state->remaining > 0) {
2343 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2345 fsp_get_io_fd(state->dst_fsp),
2349 if (nwritten == -1) {
2350 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2351 "n [%jd] failed: %s\n",
2352 fsp_str_dbg(state->src_fsp),
2353 (intmax_t)state->src_off,
2354 fsp_str_dbg(state->dst_fsp),
2355 (intmax_t)state->dst_off,
2356 (intmax_t)state->remaining,
2361 try_copy_file_range = false;
2362 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2365 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2368 status = map_nt_error_from_unix(errno);
2369 if (NT_STATUS_EQUAL(
2371 NT_STATUS_MORE_PROCESSING_REQUIRED))
2373 /* Avoid triggering the fallback */
2374 status = NT_STATUS_INTERNAL_ERROR;
2381 if (state->remaining < nwritten) {
2382 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2383 "n [%jd] remaining [%jd]\n",
2384 fsp_str_dbg(state->src_fsp),
2385 fsp_str_dbg(state->dst_fsp),
2387 (intmax_t)state->remaining);
2388 return NT_STATUS_INTERNAL_ERROR;
2391 if (nwritten == 0) {
2394 state->copied += nwritten;
2395 state->remaining -= nwritten;
2399 * Tell the req cleanup function there's no need to call
2400 * change_to_user_and_service_by_fsp() on the dst handle.
2402 state->dst_fsp = NULL;
2403 return NT_STATUS_OK;
2406 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2408 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2410 struct vfswrap_offload_write_state *state = tevent_req_data(
2411 req, struct vfswrap_offload_write_state);
2412 struct tevent_req *subreq = NULL;
2413 struct lock_struct read_lck;
2417 * This is called under the context of state->src_fsp.
2420 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2422 init_strict_lock_struct(state->src_fsp,
2423 state->src_fsp->op->global->open_persistent_id,
2425 state->next_io_size,
2427 lp_posix_cifsu_locktype(state->src_fsp),
2430 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2434 return NT_STATUS_FILE_LOCK_CONFLICT;
2437 subreq = SMB_VFS_PREAD_SEND(state,
2441 state->next_io_size,
2443 if (subreq == NULL) {
2444 return NT_STATUS_NO_MEMORY;
2446 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2448 return NT_STATUS_OK;
2451 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2453 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2455 struct tevent_req *req = tevent_req_callback_data(
2456 subreq, struct tevent_req);
2457 struct vfswrap_offload_write_state *state = tevent_req_data(
2458 req, struct vfswrap_offload_write_state);
2459 struct vfs_aio_state aio_state;
2460 struct lock_struct write_lck;
2464 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2465 TALLOC_FREE(subreq);
2467 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2468 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2471 if (nread != state->next_io_size) {
2472 DBG_ERR("Short read, only %zd of %zu\n",
2473 nread, state->next_io_size);
2474 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2478 state->src_off += nread;
2480 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2482 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2486 init_strict_lock_struct(state->dst_fsp,
2487 state->dst_fsp->op->global->open_persistent_id,
2489 state->next_io_size,
2491 lp_posix_cifsu_locktype(state->dst_fsp),
2494 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2498 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2502 subreq = SMB_VFS_PWRITE_SEND(state,
2506 state->next_io_size,
2508 if (subreq == NULL) {
2509 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2512 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2515 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2517 struct tevent_req *req = tevent_req_callback_data(
2518 subreq, struct tevent_req);
2519 struct vfswrap_offload_write_state *state = tevent_req_data(
2520 req, struct vfswrap_offload_write_state);
2521 struct vfs_aio_state aio_state;
2526 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2527 TALLOC_FREE(subreq);
2528 if (nwritten == -1) {
2529 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2530 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2533 if (nwritten != state->next_io_size) {
2534 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2535 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2539 state->dst_off += nwritten;
2541 if (state->remaining < nwritten) {
2542 /* Paranoia check */
2543 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2546 state->copied += nwritten;
2547 state->remaining -= nwritten;
2548 if (state->remaining == 0) {
2549 tevent_req_done(req);
2553 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2555 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2559 status = vfswrap_offload_write_loop(req);
2560 if (!NT_STATUS_IS_OK(status)) {
2561 tevent_req_nterror(req, status);
2568 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2569 struct tevent_req *req,
2572 struct vfswrap_offload_write_state *state = tevent_req_data(
2573 req, struct vfswrap_offload_write_state);
2576 if (tevent_req_is_nterror(req, &status)) {
2577 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2579 tevent_req_received(req);
2583 *copied = state->copied;
2584 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2585 tevent_req_received(req);
2587 return NT_STATUS_OK;
2590 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2591 TALLOC_CTX *mem_ctx,
2592 struct files_struct *fsp,
2593 uint16_t *_compression_fmt)
2595 return NT_STATUS_INVALID_DEVICE_REQUEST;
2598 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2599 TALLOC_CTX *mem_ctx,
2600 struct files_struct *fsp,
2601 uint16_t compression_fmt)
2603 return NT_STATUS_INVALID_DEVICE_REQUEST;
2606 /********************************************************************
2607 Given a stat buffer return the allocated size on disk, taking into
2608 account sparse files.
2609 ********************************************************************/
2610 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2611 struct files_struct *fsp,
2612 const SMB_STRUCT_STAT *sbuf)
2616 START_PROFILE(syscall_get_alloc_size);
2618 if(S_ISDIR(sbuf->st_ex_mode)) {
2623 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2624 /* The type of st_blocksize is blkcnt_t which *MUST* be
2625 signed (according to POSIX) and can be less than 64-bits.
2626 Ensure when we're converting to 64 bits wide we don't
2628 #if defined(SIZEOF_BLKCNT_T_8)
2629 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2630 #elif defined(SIZEOF_BLKCNT_T_4)
2632 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2633 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2636 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2640 * Some file systems do not allocate a block for very
2641 * small files. But for non-empty file should report a
2645 uint64_t filesize = get_file_size_stat(sbuf);
2647 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2651 result = get_file_size_stat(sbuf);
2654 if (fsp && fsp->initial_allocation_size)
2655 result = MAX(result,fsp->initial_allocation_size);
2657 result = smb_roundup(handle->conn, result);
2660 END_PROFILE(syscall_get_alloc_size);
2664 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2665 struct files_struct *dirfsp,
2666 const struct smb_filename *smb_fname,
2671 START_PROFILE(syscall_unlinkat);
2673 SMB_ASSERT(!is_named_stream(smb_fname));
2675 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2676 smb_fname->base_name,
2679 END_PROFILE(syscall_unlinkat);
2683 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2687 START_PROFILE(syscall_fchmod);
2689 if (!fsp->fsp_flags.is_pathref) {
2690 result = fchmod(fsp_get_io_fd(fsp), mode);
2691 END_PROFILE(syscall_fchmod);
2695 if (fsp->fsp_flags.have_proc_fds) {
2696 int fd = fsp_get_pathref_fd(fsp);
2697 struct sys_proc_fd_path_buf buf;
2699 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2701 END_PROFILE(syscall_fchmod);
2706 * This is no longer a handle based call.
2708 result = chmod(fsp->fsp_name->base_name, mode);
2710 END_PROFILE(syscall_fchmod);
2714 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2719 START_PROFILE(syscall_fchown);
2720 if (!fsp->fsp_flags.is_pathref) {
2721 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2722 END_PROFILE(syscall_fchown);
2726 if (fsp->fsp_flags.have_proc_fds) {
2727 int fd = fsp_get_pathref_fd(fsp);
2728 struct sys_proc_fd_path_buf buf;
2730 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2732 END_PROFILE(syscall_fchown);
2737 * This is no longer a handle based call.
2739 result = chown(fsp->fsp_name->base_name, uid, gid);
2740 END_PROFILE(syscall_fchown);
2748 static int vfswrap_lchown(vfs_handle_struct *handle,
2749 const struct smb_filename *smb_fname,
2755 START_PROFILE(syscall_lchown);
2756 result = lchown(smb_fname->base_name, uid, gid);
2757 END_PROFILE(syscall_lchown);
2761 static int vfswrap_chdir(vfs_handle_struct *handle,
2762 const struct smb_filename *smb_fname)
2766 START_PROFILE(syscall_chdir);
2767 result = chdir(smb_fname->base_name);
2768 END_PROFILE(syscall_chdir);
2772 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2776 struct smb_filename *smb_fname = NULL;
2778 START_PROFILE(syscall_getwd);
2779 result = sys_getwd();
2780 END_PROFILE(syscall_getwd);
2782 if (result == NULL) {
2785 smb_fname = synthetic_smb_fname(ctx,
2792 * sys_getwd() *always* returns malloced memory.
2793 * We must free here to avoid leaks:
2794 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2800 /*********************************************************************
2801 nsec timestamp resolution call. Convert down to whatever the underlying
2802 system will support.
2803 **********************************************************************/
2805 static int vfswrap_fntimes(vfs_handle_struct *handle,
2807 struct smb_file_time *ft)
2810 struct timespec ts[2];
2811 struct timespec *times = NULL;
2813 START_PROFILE(syscall_fntimes);
2815 if (fsp_is_alternate_stream(fsp)) {
2821 if (is_omit_timespec(&ft->atime)) {
2822 ft->atime = fsp->fsp_name->st.st_ex_atime;
2825 if (is_omit_timespec(&ft->mtime)) {
2826 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2829 if (!is_omit_timespec(&ft->create_time)) {
2830 set_create_timespec_ea(fsp,
2834 if ((timespec_compare(&ft->atime,
2835 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2836 (timespec_compare(&ft->mtime,
2837 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2849 if (!fsp->fsp_flags.is_pathref) {
2850 result = futimens(fsp_get_io_fd(fsp), times);
2854 if (fsp->fsp_flags.have_proc_fds) {
2855 int fd = fsp_get_pathref_fd(fsp);
2856 struct sys_proc_fd_path_buf buf;
2858 result = utimensat(AT_FDCWD,
2859 sys_proc_fd_path(fd, &buf),
2867 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2868 * path translation mechanism. Fallback to path based call.
2870 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2873 END_PROFILE(syscall_fntimes);
2879 /*********************************************************************
2880 A version of ftruncate that will write the space on disk if strict
2882 **********************************************************************/
2884 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2886 off_t space_to_write;
2887 uint64_t space_avail;
2888 uint64_t bsize,dfree,dsize;
2891 SMB_STRUCT_STAT *pst;
2894 ok = vfs_valid_pwrite_range(len, 0);
2900 status = vfs_stat_fsp(fsp);
2901 if (!NT_STATUS_IS_OK(status)) {
2904 pst = &fsp->fsp_name->st;
2907 if (S_ISFIFO(pst->st_ex_mode))
2911 if (pst->st_ex_size == len)
2914 /* Shrink - just ftruncate. */
2915 if (pst->st_ex_size > len)
2916 return ftruncate(fsp_get_io_fd(fsp), len);
2918 space_to_write = len - pst->st_ex_size;
2920 /* for allocation try fallocate first. This can fail on some
2921 platforms e.g. when the filesystem doesn't support it and no
2922 emulation is being done by the libc (like on AIX with JFS1). In that
2923 case we do our own emulation. fallocate implementations can
2924 return ENOTSUP or EINVAL in cases like that. */
2925 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2926 if (ret == -1 && errno == ENOSPC) {
2932 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2933 "error %d. Falling back to slow manual allocation\n", errno);
2935 /* available disk space is enough or not? */
2937 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2938 /* space_avail is 1k blocks */
2939 if (space_avail == (uint64_t)-1 ||
2940 ((uint64_t)space_to_write/1024 > space_avail) ) {
2945 /* Write out the real space on disk. */
2946 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2954 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2957 SMB_STRUCT_STAT *pst;
2961 START_PROFILE(syscall_ftruncate);
2963 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2964 result = strict_allocate_ftruncate(handle, fsp, len);
2965 END_PROFILE(syscall_ftruncate);
2969 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2970 ftruncate if the system supports it. Then I discovered that
2971 you can have some filesystems that support ftruncate
2972 expansion and some that don't! On Linux fat can't do
2973 ftruncate extend but ext2 can. */
2975 result = ftruncate(fsp_get_io_fd(fsp), len);
2977 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2978 extend a file with ftruncate. Provide alternate implementation
2981 /* Do an fstat to see if the file is longer than the requested
2982 size in which case the ftruncate above should have
2983 succeeded or shorter, in which case seek to len - 1 and
2984 write 1 byte of zero */
2985 status = vfs_stat_fsp(fsp);
2986 if (!NT_STATUS_IS_OK(status)) {
2990 /* We need to update the files_struct after successful ftruncate */
2995 pst = &fsp->fsp_name->st;
2998 if (S_ISFIFO(pst->st_ex_mode)) {
3004 if (pst->st_ex_size == len) {
3009 if (pst->st_ex_size > len) {
3010 /* the ftruncate should have worked */
3014 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3022 END_PROFILE(syscall_ftruncate);
3026 static int vfswrap_fallocate(vfs_handle_struct *handle,
3034 START_PROFILE(syscall_fallocate);
3036 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3038 * posix_fallocate returns 0 on success, errno on error
3039 * and doesn't set errno. Make it behave like fallocate()
3040 * which returns -1, and sets errno on failure.
3047 /* sys_fallocate handles filtering of unsupported mode flags */
3048 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3050 END_PROFILE(syscall_fallocate);
3054 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3058 START_PROFILE(syscall_fcntl_lock);
3060 if (fsp->fsp_flags.use_ofd_locks) {
3061 op = map_process_lock_to_ofd_lock(op);
3064 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3065 END_PROFILE(syscall_fcntl_lock);
3069 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3071 uint32_t share_access,
3072 uint32_t access_mask)
3078 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3082 va_list dup_cmd_arg;
3086 START_PROFILE(syscall_fcntl);
3088 va_copy(dup_cmd_arg, cmd_arg);
3094 #if defined(HAVE_OFD_LOCKS)
3099 #if defined(HAVE_F_OWNER_EX)
3103 #if defined(HAVE_RW_HINTS)
3106 case F_GET_FILE_RW_HINT:
3107 case F_SET_FILE_RW_HINT:
3109 argp = va_arg(dup_cmd_arg, void *);
3110 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3113 val = va_arg(dup_cmd_arg, int);
3114 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3117 va_end(dup_cmd_arg);
3119 END_PROFILE(syscall_fcntl);
3123 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3128 START_PROFILE(syscall_fcntl_getlock);
3130 if (fsp->fsp_flags.use_ofd_locks) {
3131 op = map_process_lock_to_ofd_lock(op);
3134 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3135 END_PROFILE(syscall_fcntl_getlock);
3139 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3144 START_PROFILE(syscall_linux_setlease);
3146 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3148 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3149 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3153 END_PROFILE(syscall_linux_setlease);
3157 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3158 const struct smb_filename *link_target,
3159 struct files_struct *dirfsp,
3160 const struct smb_filename *new_smb_fname)
3164 START_PROFILE(syscall_symlinkat);
3166 SMB_ASSERT(!is_named_stream(new_smb_fname));
3168 result = symlinkat(link_target->base_name,
3169 fsp_get_pathref_fd(dirfsp),
3170 new_smb_fname->base_name);
3171 END_PROFILE(syscall_symlinkat);
3175 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3176 const struct files_struct *dirfsp,
3177 const struct smb_filename *smb_fname,
3183 START_PROFILE(syscall_readlinkat);
3185 SMB_ASSERT(!is_named_stream(smb_fname));
3187 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3188 smb_fname->base_name,
3192 END_PROFILE(syscall_readlinkat);
3196 static int vfswrap_linkat(vfs_handle_struct *handle,
3197 files_struct *srcfsp,
3198 const struct smb_filename *old_smb_fname,
3199 files_struct *dstfsp,
3200 const struct smb_filename *new_smb_fname,
3205 START_PROFILE(syscall_linkat);
3207 SMB_ASSERT(!is_named_stream(old_smb_fname));
3208 SMB_ASSERT(!is_named_stream(new_smb_fname));
3210 result = linkat(fsp_get_pathref_fd(srcfsp),
3211 old_smb_fname->base_name,
3212 fsp_get_pathref_fd(dstfsp),
3213 new_smb_fname->base_name,
3216 END_PROFILE(syscall_linkat);
3220 static int vfswrap_mknodat(vfs_handle_struct *handle,
3221 files_struct *dirfsp,
3222 const struct smb_filename *smb_fname,
3228 START_PROFILE(syscall_mknodat);
3230 SMB_ASSERT(!is_named_stream(smb_fname));
3232 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3233 smb_fname->base_name,
3237 END_PROFILE(syscall_mknodat);
3241 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3243 const struct smb_filename *smb_fname)
3246 struct smb_filename *result_fname = NULL;
3248 START_PROFILE(syscall_realpath);
3249 result = sys_realpath(smb_fname->base_name);
3250 END_PROFILE(syscall_realpath);
3252 result_fname = synthetic_smb_fname(ctx,
3260 return result_fname;
3263 static int vfswrap_fchflags(vfs_handle_struct *handle,
3264 struct files_struct *fsp,
3267 #ifdef HAVE_FCHFLAGS
3268 int fd = fsp_get_pathref_fd(fsp);
3270 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3272 if (!fsp->fsp_flags.is_pathref) {
3273 return fchflags(fd, flags);
3276 if (fsp->fsp_flags.have_proc_fds) {
3277 struct sys_proc_fd_path_buf buf;
3279 return chflags(sys_proc_fd_path(fd, &buf), flags);
3283 * This is no longer a handle based call.
3285 return chflags(fsp->fsp_name->base_name, flags);
3292 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3293 const SMB_STRUCT_STAT *sbuf)
3297 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3301 key.devid = sbuf->st_ex_dev;
3302 key.inode = sbuf->st_ex_ino;
3303 /* key.extid is unused by default. */
3308 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3309 const SMB_STRUCT_STAT *psbuf)
3313 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3314 return (uint64_t)psbuf->st_ex_ino;
3318 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3321 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3326 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3327 struct files_struct *fsp,
3328 TALLOC_CTX *mem_ctx,
3329 unsigned int *pnum_streams,
3330 struct stream_struct **pstreams)
3332 struct stream_struct *tmp_streams = NULL;
3333 unsigned int num_streams = *pnum_streams;
3334 struct stream_struct *streams = *pstreams;
3337 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3339 if (fsp->fsp_flags.is_directory) {
3341 * No default streams on directories
3345 status = vfs_stat_fsp(fsp);
3346 if (!NT_STATUS_IS_OK(status)) {
3350 if (num_streams + 1 < 1) {
3352 return NT_STATUS_INVALID_PARAMETER;
3355 tmp_streams = talloc_realloc(mem_ctx,
3357 struct stream_struct,
3359 if (tmp_streams == NULL) {
3360 return NT_STATUS_NO_MEMORY;
3362 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3363 if (tmp_streams[num_streams].name == NULL) {
3364 return NT_STATUS_NO_MEMORY;
3366 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3367 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3370 &fsp->fsp_name->st);
3373 *pnum_streams = num_streams;
3374 *pstreams = tmp_streams;
3376 return NT_STATUS_OK;
3379 static NTSTATUS vfswrap_get_real_filename_at(
3380 struct vfs_handle_struct *handle,
3381 struct files_struct *dirfsp,
3383 TALLOC_CTX *mem_ctx,
3387 * Don't fall back to get_real_filename so callers can differentiate
3388 * between a full directory scan and an actual case-insensitive stat.
3390 return NT_STATUS_NOT_SUPPORTED;
3393 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3394 const struct files_struct *dirfsp,
3395 const struct smb_filename *smb_fname)
3397 return handle->conn->connectpath;
3400 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3401 struct byte_range_lock *br_lck,
3402 struct lock_struct *plock)
3404 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3406 /* Note: blr is not used in the default implementation. */
3407 return brl_lock_windows_default(br_lck, plock);
3410 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3411 struct byte_range_lock *br_lck,
3412 const struct lock_struct *plock)
3414 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3416 return brl_unlock_windows_default(br_lck, plock);
3419 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3421 struct lock_struct *plock)
3423 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3424 plock->lock_type == WRITE_LOCK);
3426 return strict_lock_check_default(fsp, plock);
3429 /* NT ACL operations. */
3431 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3433 uint32_t security_info,
3434 TALLOC_CTX *mem_ctx,
3435 struct security_descriptor **ppdesc)
3439 START_PROFILE(fget_nt_acl);
3441 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3443 result = posix_fget_nt_acl(fsp, security_info,
3445 END_PROFILE(fget_nt_acl);
3449 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3453 START_PROFILE(fset_nt_acl);
3455 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3457 result = set_nt_acl(fsp, security_info_sent, psd);
3458 END_PROFILE(fset_nt_acl);
3462 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3463 struct smb_filename *file,
3464 struct security_acl *sacl,
3465 uint32_t access_requested,
3466 uint32_t access_denied)
3468 return NT_STATUS_OK; /* Nothing to do here ... */
3471 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3473 SMB_ACL_TYPE_T type,
3474 TALLOC_CTX *mem_ctx)
3476 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3478 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3481 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3483 SMB_ACL_TYPE_T type,
3486 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3488 return sys_acl_set_fd(handle, fsp, type, theacl);
3491 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3494 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3496 return sys_acl_delete_def_fd(handle, fsp);
3499 /****************************************************************
3500 Extended attribute operations.
3501 *****************************************************************/
3503 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3504 struct files_struct *fsp,
3509 int fd = fsp_get_pathref_fd(fsp);
3511 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3513 if (!fsp->fsp_flags.is_pathref) {
3514 return fgetxattr(fd, name, value, size);
3517 if (fsp->fsp_flags.have_proc_fds) {
3518 struct sys_proc_fd_path_buf buf;
3520 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3524 * This is no longer a handle based call.
3526 return getxattr(fsp->fsp_name->base_name, name, value, size);
3529 struct vfswrap_getxattrat_state {
3530 struct tevent_context *ev;
3531 struct vfs_handle_struct *handle;
3532 files_struct *dir_fsp;
3533 const struct smb_filename *smb_fname;
3536 * The following variables are talloced off "state" which is protected
3537 * by a destructor and thus are guaranteed to be safe to be used in the
3538 * job function in the worker thread.
3541 const char *xattr_name;
3542 uint8_t *xattr_value;
3543 struct security_unix_token *token;
3546 struct vfs_aio_state vfs_aio_state;
3547 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3550 static int vfswrap_getxattrat_state_destructor(
3551 struct vfswrap_getxattrat_state *state)
3556 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3557 static void vfswrap_getxattrat_do_async(void *private_data);
3558 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3560 static struct tevent_req *vfswrap_getxattrat_send(
3561 TALLOC_CTX *mem_ctx,
3562 struct tevent_context *ev,
3563 struct vfs_handle_struct *handle,
3564 files_struct *dir_fsp,
3565 const struct smb_filename *smb_fname,
3566 const char *xattr_name,
3569 struct tevent_req *req = NULL;
3570 struct tevent_req *subreq = NULL;
3571 struct vfswrap_getxattrat_state *state = NULL;
3572 size_t max_threads = 0;
3573 bool have_per_thread_cwd = false;
3574 bool have_per_thread_creds = false;
3575 bool do_async = false;
3577 SMB_ASSERT(!is_named_stream(smb_fname));
3579 req = tevent_req_create(mem_ctx, &state,
3580 struct vfswrap_getxattrat_state);
3584 *state = (struct vfswrap_getxattrat_state) {
3588 .smb_fname = smb_fname,
3591 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3592 if (max_threads >= 1) {
3594 * We need a non sync threadpool!
3596 have_per_thread_cwd = per_thread_cwd_supported();
3598 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3599 have_per_thread_creds = true;
3601 if (have_per_thread_cwd && have_per_thread_creds) {
3605 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3606 state->profile_bytes, 0);
3608 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3609 DBG_ERR("Need a valid directory fd\n");
3610 tevent_req_error(req, EINVAL);
3611 return tevent_req_post(req, ev);
3614 if (alloc_hint > 0) {
3615 state->xattr_value = talloc_zero_array(state,
3618 if (tevent_req_nomem(state->xattr_value, req)) {
3619 return tevent_req_post(req, ev);
3624 vfswrap_getxattrat_do_sync(req);
3625 return tevent_req_post(req, ev);
3629 * Now allocate all parameters from a memory context that won't go away
3630 * no matter what. These parameters will get used in threads and we
3631 * can't reliably cancel threads, so all buffers passed to the threads
3632 * must not be freed before all referencing threads terminate.
3635 state->name = talloc_strdup(state, smb_fname->base_name);
3636 if (tevent_req_nomem(state->name, req)) {
3637 return tevent_req_post(req, ev);
3640 state->xattr_name = talloc_strdup(state, xattr_name);
3641 if (tevent_req_nomem(state->xattr_name, req)) {
3642 return tevent_req_post(req, ev);
3646 * This is a hot codepath so at first glance one might think we should
3647 * somehow optimize away the token allocation and do a
3648 * talloc_reference() or similar black magic instead. But due to the
3649 * talloc_stackframe pool per SMB2 request this should be a simple copy
3650 * without a malloc in most cases.
3652 if (geteuid() == sec_initial_uid()) {
3653 state->token = root_unix_token(state);
3655 state->token = copy_unix_token(
3657 dir_fsp->conn->session_info->unix_token);
3659 if (tevent_req_nomem(state->token, req)) {
3660 return tevent_req_post(req, ev);
3663 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3665 subreq = pthreadpool_tevent_job_send(
3668 dir_fsp->conn->sconn->pool,
3669 vfswrap_getxattrat_do_async,
3671 if (tevent_req_nomem(subreq, req)) {
3672 return tevent_req_post(req, ev);
3674 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3676 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3681 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3683 struct vfswrap_getxattrat_state *state = tevent_req_data(
3684 req, struct vfswrap_getxattrat_state);
3686 state->xattr_size = vfswrap_fgetxattr(state->handle,
3687 state->smb_fname->fsp,
3690 talloc_array_length(state->xattr_value));
3691 if (state->xattr_size == -1) {
3692 tevent_req_error(req, errno);
3696 tevent_req_done(req);
3700 static void vfswrap_getxattrat_do_async(void *private_data)
3702 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3703 private_data, struct vfswrap_getxattrat_state);
3704 struct timespec start_time;
3705 struct timespec end_time;
3708 PROFILE_TIMESTAMP(&start_time);
3709 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3712 * Here we simulate a getxattrat()
3713 * call using fchdir();getxattr()
3716 per_thread_cwd_activate();
3718 /* Become the correct credential on this thread. */
3719 ret = set_thread_credentials(state->token->uid,
3721 (size_t)state->token->ngroups,
3722 state->token->groups);
3724 state->xattr_size = -1;
3725 state->vfs_aio_state.error = errno;
3729 state->xattr_size = vfswrap_fgetxattr(state->handle,
3730 state->smb_fname->fsp,
3733 talloc_array_length(state->xattr_value));
3734 if (state->xattr_size == -1) {
3735 state->vfs_aio_state.error = errno;
3739 PROFILE_TIMESTAMP(&end_time);
3740 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3741 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3744 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3746 struct tevent_req *req = tevent_req_callback_data(
3747 subreq, struct tevent_req);
3748 struct vfswrap_getxattrat_state *state = tevent_req_data(
3749 req, struct vfswrap_getxattrat_state);
3754 * Make sure we run as the user again
3756 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3759 ret = pthreadpool_tevent_job_recv(subreq);
3760 TALLOC_FREE(subreq);
3761 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3762 talloc_set_destructor(state, NULL);
3764 if (ret != EAGAIN) {
3765 tevent_req_error(req, ret);
3769 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3770 * means the lower level pthreadpool failed to create a new
3771 * thread. Fallback to sync processing in that case to allow
3772 * some progress for the client.
3774 vfswrap_getxattrat_do_sync(req);
3778 if (state->xattr_size == -1) {
3779 tevent_req_error(req, state->vfs_aio_state.error);
3783 if (state->xattr_value == NULL) {
3785 * The caller only wanted the size.
3787 tevent_req_done(req);
3792 * shrink the buffer to the returned size.
3793 * (can't fail). It means NULL if size is 0.
3795 state->xattr_value = talloc_realloc(state,
3800 tevent_req_done(req);
3803 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3804 struct vfs_aio_state *aio_state,
3805 TALLOC_CTX *mem_ctx,
3806 uint8_t **xattr_value)
3808 struct vfswrap_getxattrat_state *state = tevent_req_data(
3809 req, struct vfswrap_getxattrat_state);
3812 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3813 tevent_req_received(req);
3817 *aio_state = state->vfs_aio_state;
3818 xattr_size = state->xattr_size;
3819 if (xattr_value != NULL) {
3820 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3823 tevent_req_received(req);
3827 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3829 int fd = fsp_get_pathref_fd(fsp);
3831 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3833 if (!fsp->fsp_flags.is_pathref) {
3834 return flistxattr(fd, list, size);
3837 if (fsp->fsp_flags.have_proc_fds) {
3838 struct sys_proc_fd_path_buf buf;
3840 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3844 * This is no longer a handle based call.
3846 return listxattr(fsp->fsp_name->base_name, list, size);
3849 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3851 int fd = fsp_get_pathref_fd(fsp);
3853 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3855 if (!fsp->fsp_flags.is_pathref) {
3856 return fremovexattr(fd, name);
3859 if (fsp->fsp_flags.have_proc_fds) {
3860 struct sys_proc_fd_path_buf buf;
3862 return removexattr(sys_proc_fd_path(fd, &buf), name);
3866 * This is no longer a handle based call.
3868 return removexattr(fsp->fsp_name->base_name, name);
3871 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3873 int fd = fsp_get_pathref_fd(fsp);
3875 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3877 if (!fsp->fsp_flags.is_pathref) {
3878 return fsetxattr(fd, name, value, size, flags);
3881 if (fsp->fsp_flags.have_proc_fds) {
3882 struct sys_proc_fd_path_buf buf;
3884 return setxattr(sys_proc_fd_path(fd, &buf),
3892 * This is no longer a handle based call.
3894 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3897 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3902 static bool vfswrap_is_offline(struct connection_struct *conn,
3903 const struct smb_filename *fname)
3907 bool offline = false;
3909 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3913 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3914 #if defined(ENOTSUP)
3920 status = get_full_smb_filename(talloc_tos(), fname, &path);
3921 if (!NT_STATUS_IS_OK(status)) {
3922 errno = map_errno_from_nt_status(status);
3926 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3933 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3934 struct files_struct *fsp,
3935 TALLOC_CTX *mem_ctx,
3938 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3941 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3942 struct files_struct *fsp,
3943 const DATA_BLOB old_cookie,
3944 TALLOC_CTX *mem_ctx,
3945 DATA_BLOB *new_cookie)
3947 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3951 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3952 struct smb_request *smb1req,
3953 struct smbXsrv_open *op,
3954 const DATA_BLOB old_cookie,
3955 TALLOC_CTX *mem_ctx,
3956 struct files_struct **fsp,
3957 DATA_BLOB *new_cookie)
3959 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3960 old_cookie, mem_ctx,
3964 static struct vfs_fn_pointers vfs_default_fns = {
3965 /* Disk operations */
3967 .connect_fn = vfswrap_connect,
3968 .disconnect_fn = vfswrap_disconnect,
3969 .disk_free_fn = vfswrap_disk_free,
3970 .get_quota_fn = vfswrap_get_quota,
3971 .set_quota_fn = vfswrap_set_quota,
3972 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3973 .statvfs_fn = vfswrap_statvfs,
3974 .fs_capabilities_fn = vfswrap_fs_capabilities,
3975 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3976 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3977 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3978 .snap_check_path_fn = vfswrap_snap_check_path,
3979 .snap_create_fn = vfswrap_snap_create,
3980 .snap_delete_fn = vfswrap_snap_delete,
3982 /* Directory operations */
3984 .fdopendir_fn = vfswrap_fdopendir,
3985 .readdir_fn = vfswrap_readdir,
3986 .freaddir_attr_fn = vfswrap_freaddir_attr,
3987 .rewind_dir_fn = vfswrap_rewinddir,
3988 .mkdirat_fn = vfswrap_mkdirat,
3989 .closedir_fn = vfswrap_closedir,
3991 /* File operations */
3993 .openat_fn = vfswrap_openat,
3994 .create_file_fn = vfswrap_create_file,
3995 .close_fn = vfswrap_close,
3996 .pread_fn = vfswrap_pread,
3997 .pread_send_fn = vfswrap_pread_send,
3998 .pread_recv_fn = vfswrap_pread_recv,
3999 .pwrite_fn = vfswrap_pwrite,
4000 .pwrite_send_fn = vfswrap_pwrite_send,
4001 .pwrite_recv_fn = vfswrap_pwrite_recv,
4002 .lseek_fn = vfswrap_lseek,
4003 .sendfile_fn = vfswrap_sendfile,
4004 .recvfile_fn = vfswrap_recvfile,
4005 .renameat_fn = vfswrap_renameat,
4006 .fsync_send_fn = vfswrap_fsync_send,
4007 .fsync_recv_fn = vfswrap_fsync_recv,
4008 .stat_fn = vfswrap_stat,
4009 .fstat_fn = vfswrap_fstat,
4010 .lstat_fn = vfswrap_lstat,
4011 .fstatat_fn = vfswrap_fstatat,
4012 .get_alloc_size_fn = vfswrap_get_alloc_size,
4013 .unlinkat_fn = vfswrap_unlinkat,
4014 .fchmod_fn = vfswrap_fchmod,
4015 .fchown_fn = vfswrap_fchown,
4016 .lchown_fn = vfswrap_lchown,
4017 .chdir_fn = vfswrap_chdir,
4018 .getwd_fn = vfswrap_getwd,
4019 .fntimes_fn = vfswrap_fntimes,
4020 .ftruncate_fn = vfswrap_ftruncate,
4021 .fallocate_fn = vfswrap_fallocate,
4022 .lock_fn = vfswrap_lock,
4023 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4024 .fcntl_fn = vfswrap_fcntl,
4025 .linux_setlease_fn = vfswrap_linux_setlease,
4026 .getlock_fn = vfswrap_getlock,
4027 .symlinkat_fn = vfswrap_symlinkat,
4028 .readlinkat_fn = vfswrap_readlinkat,
4029 .linkat_fn = vfswrap_linkat,
4030 .mknodat_fn = vfswrap_mknodat,
4031 .realpath_fn = vfswrap_realpath,
4032 .fchflags_fn = vfswrap_fchflags,
4033 .file_id_create_fn = vfswrap_file_id_create,
4034 .fs_file_id_fn = vfswrap_fs_file_id,
4035 .fstreaminfo_fn = vfswrap_fstreaminfo,
4036 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4037 .connectpath_fn = vfswrap_connectpath,
4038 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4039 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4040 .strict_lock_check_fn = vfswrap_strict_lock_check,
4041 .translate_name_fn = vfswrap_translate_name,
4042 .parent_pathname_fn = vfswrap_parent_pathname,
4043 .fsctl_fn = vfswrap_fsctl,
4044 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4045 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4046 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4047 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4048 .offload_read_send_fn = vfswrap_offload_read_send,
4049 .offload_read_recv_fn = vfswrap_offload_read_recv,
4050 .offload_write_send_fn = vfswrap_offload_write_send,
4051 .offload_write_recv_fn = vfswrap_offload_write_recv,
4052 .fget_compression_fn = vfswrap_fget_compression,
4053 .set_compression_fn = vfswrap_set_compression,
4055 /* NT ACL operations. */
4057 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4058 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4059 .audit_file_fn = vfswrap_audit_file,
4061 /* POSIX ACL operations. */
4063 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4064 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4065 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4066 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4068 /* EA operations. */
4069 .getxattrat_send_fn = vfswrap_getxattrat_send,
4070 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4071 .fgetxattr_fn = vfswrap_fgetxattr,
4072 .flistxattr_fn = vfswrap_flistxattr,
4073 .fremovexattr_fn = vfswrap_fremovexattr,
4074 .fsetxattr_fn = vfswrap_fsetxattr,
4076 /* aio operations */
4077 .aio_force_fn = vfswrap_aio_force,
4079 /* durable handle operations */
4080 .durable_cookie_fn = vfswrap_durable_cookie,
4081 .durable_disconnect_fn = vfswrap_durable_disconnect,
4082 .durable_reconnect_fn = vfswrap_durable_reconnect,
4086 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4089 * Here we need to implement every call!
4091 * As this is the end of the vfs module chain.
4093 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4094 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4095 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);