vfs_ceph_new: handle case of readlinkat with empty name string
[Samba.git] / source3 / modules / vfs_default.c
blob5922aba3e8a50d9dea2ad46ef4643e044baf69ee
1 /*
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/>.
21 #include "includes.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "ntioctl.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"
41 #undef DBGC_CLASS
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
48 this possibility. */
50 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
52 bool bval;
54 handle->conn->have_proc_fds = sys_have_proc_fds();
55 #ifdef DISABLE_PROC_FDS
56 handle->conn->have_proc_fds = false;
57 #endif
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),
69 "vfs_default",
70 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
71 true);
72 if (bval) {
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;
78 #endif
80 return 0; /* Return >= 0 for success */
83 static void vfswrap_disconnect(vfs_handle_struct *handle)
87 /* Disk operations */
89 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
90 const struct smb_filename *smb_fname,
91 uint64_t *bsize,
92 uint64_t *dfree,
93 uint64_t *dsize)
95 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
96 return (uint64_t)-1;
99 *bsize = 512;
100 return *dfree / 2;
103 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
104 const struct smb_filename *smb_fname,
105 enum SMB_QUOTA_TYPE qtype,
106 unid_t id,
107 SMB_DISK_QUOTA *qt)
109 #ifdef HAVE_SYS_QUOTAS
110 int result;
112 START_PROFILE(syscall_get_quota);
113 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
114 END_PROFILE(syscall_get_quota);
115 return result;
116 #else
117 errno = ENOSYS;
118 return -1;
119 #endif
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
125 int result;
127 START_PROFILE(syscall_set_quota);
128 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
129 END_PROFILE(syscall_set_quota);
130 return result;
131 #else
132 errno = ENOSYS;
133 return -1;
134 #endif
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,
140 bool labels)
142 errno = ENOSYS;
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;
162 int ret;
164 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
165 conn->connectpath,
166 NULL,
167 NULL,
170 if (smb_fname_cpath == NULL) {
171 return caps;
174 ZERO_STRUCT(statbuf);
175 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
176 if (ret == 0) {
177 caps = statbuf.FsCapabilities;
180 #if defined(HAVE_SYS_QUOTAS)
181 caps |= FILE_VOLUME_QUOTAS;
182 #endif
184 if (lp_nt_acl_support(SNUM(conn))) {
185 caps |= FILE_PERSISTENT_ACLS;
188 caps |= lp_parm_int(SNUM(conn), "share", "fake_fscaps", 0);
190 *p_ts_res = TIMESTAMP_SET_SECONDS;
192 /* Work out what timestamp resolution we can
193 * use when setting a timestamp. */
195 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
196 if (ret == -1) {
197 TALLOC_FREE(smb_fname_cpath);
198 return caps;
201 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
202 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
203 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
204 /* If any of the normal UNIX directory timestamps
205 * have a non-zero tv_nsec component assume
206 * we might be able to set sub-second timestamps.
207 * See what filetime set primitives we have.
209 #if defined(HAVE_UTIMENSAT)
210 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
211 #elif defined(HAVE_UTIMES)
212 /* utimes allows msec timestamps to be set. */
213 *p_ts_res = TIMESTAMP_SET_MSEC;
214 #elif defined(HAVE_UTIME)
215 /* utime only allows sec timestamps to be set. */
216 *p_ts_res = TIMESTAMP_SET_SECONDS;
217 #endif
219 DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
220 "resolution of %s "
221 "available on share %s, directory %s\n",
222 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
223 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
224 conn->connectpath );
226 TALLOC_FREE(smb_fname_cpath);
227 return caps;
230 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
231 struct dfs_GetDFSReferral *r)
233 struct junction_map *junction = NULL;
234 size_t consumedcnt = 0;
235 bool self_referral = false;
236 char *pathnamep = NULL;
237 char *local_dfs_path = NULL;
238 NTSTATUS status;
239 size_t i;
240 uint16_t max_referral_level = r->in.req.max_referral_level;
242 if (DEBUGLVL(DBGLVL_DEBUG)) {
243 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
246 /* get the junction entry */
247 if (r->in.req.servername == NULL) {
248 return NT_STATUS_NOT_FOUND;
252 * Trim pathname sent by client so it begins with only one backslash.
253 * Two backslashes confuse some dfs clients
256 local_dfs_path = talloc_strdup(r, r->in.req.servername);
257 if (local_dfs_path == NULL) {
258 return NT_STATUS_NO_MEMORY;
260 pathnamep = local_dfs_path;
261 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
262 IS_DIRECTORY_SEP(pathnamep[1])) {
263 pathnamep++;
266 junction = talloc_zero(r, struct junction_map);
267 if (junction == NULL) {
268 return NT_STATUS_NO_MEMORY;
271 /* The following call can change cwd. */
272 status = get_referred_path(r,
273 handle->conn->session_info,
274 pathnamep,
275 handle->conn->sconn->remote_address,
276 handle->conn->sconn->local_address,
277 junction, &consumedcnt, &self_referral);
278 if (!NT_STATUS_IS_OK(status)) {
279 struct smb_filename connectpath_fname = {
280 .base_name = handle->conn->connectpath
282 vfs_ChDir(handle->conn, &connectpath_fname);
283 return status;
286 struct smb_filename connectpath_fname = {
287 .base_name = handle->conn->connectpath
289 vfs_ChDir(handle->conn, &connectpath_fname);
292 if (!self_referral) {
293 pathnamep[consumedcnt] = '\0';
295 if (DEBUGLVL(DBGLVL_INFO)) {
296 dbgtext("Path %s to alternate path(s):",
297 pathnamep);
298 for (i=0; i < junction->referral_count; i++) {
299 dbgtext(" %s",
300 junction->referral_list[i].alternate_path);
302 dbgtext(".\n");
306 if (r->in.req.max_referral_level <= 2) {
307 max_referral_level = 2;
309 if (r->in.req.max_referral_level >= 3) {
310 max_referral_level = 3;
313 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
314 if (r->out.resp == NULL) {
315 return NT_STATUS_NO_MEMORY;
318 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
319 r->out.resp->nb_referrals = junction->referral_count;
321 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
322 if (self_referral) {
323 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
326 r->out.resp->referral_entries = talloc_zero_array(r,
327 struct dfs_referral_type,
328 r->out.resp->nb_referrals);
329 if (r->out.resp->referral_entries == NULL) {
330 return NT_STATUS_NO_MEMORY;
333 switch (max_referral_level) {
334 case 2:
335 for(i=0; i < junction->referral_count; i++) {
336 struct referral *ref = &junction->referral_list[i];
337 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
338 struct dfs_referral_type *t =
339 &r->out.resp->referral_entries[i];
340 struct dfs_referral_v2 *v2 = &t->referral.v2;
342 t->version = 2;
343 v2->size = VERSION2_REFERRAL_SIZE;
344 if (self_referral) {
345 v2->server_type = DFS_SERVER_ROOT;
346 } else {
347 v2->server_type = DFS_SERVER_NON_ROOT;
349 v2->entry_flags = 0;
350 v2->proximity = ref->proximity;
351 v2->ttl = ref->ttl;
352 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
353 if (v2->DFS_path == NULL) {
354 return NT_STATUS_NO_MEMORY;
356 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
357 if (v2->DFS_alt_path == NULL) {
358 return NT_STATUS_NO_MEMORY;
360 v2->netw_address = talloc_strdup(mem_ctx,
361 ref->alternate_path);
362 if (v2->netw_address == NULL) {
363 return NT_STATUS_NO_MEMORY;
367 break;
368 case 3:
369 for(i=0; i < junction->referral_count; i++) {
370 struct referral *ref = &junction->referral_list[i];
371 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
372 struct dfs_referral_type *t =
373 &r->out.resp->referral_entries[i];
374 struct dfs_referral_v3 *v3 = &t->referral.v3;
375 struct dfs_normal_referral *r1 = &v3->referrals.r1;
377 t->version = 3;
378 v3->size = VERSION3_REFERRAL_SIZE;
379 if (self_referral) {
380 v3->server_type = DFS_SERVER_ROOT;
381 } else {
382 v3->server_type = DFS_SERVER_NON_ROOT;
384 v3->entry_flags = 0;
385 v3->ttl = ref->ttl;
386 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
387 if (r1->DFS_path == NULL) {
388 return NT_STATUS_NO_MEMORY;
390 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
391 if (r1->DFS_alt_path == NULL) {
392 return NT_STATUS_NO_MEMORY;
394 r1->netw_address = talloc_strdup(mem_ctx,
395 ref->alternate_path);
396 if (r1->netw_address == NULL) {
397 return NT_STATUS_NO_MEMORY;
400 break;
401 default:
402 DBG_ERR("Invalid dfs referral version: %d\n",
403 max_referral_level);
404 return NT_STATUS_INVALID_LEVEL;
407 if (DEBUGLVL(DBGLVL_DEBUG)) {
408 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
411 return NT_STATUS_OK;
414 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
415 struct files_struct *dirfsp,
416 const struct smb_filename *smb_fname,
417 const struct referral *reflist,
418 size_t referral_count)
420 TALLOC_CTX *frame = talloc_stackframe();
421 NTSTATUS status = NT_STATUS_NO_MEMORY;
422 int ret;
423 char *msdfs_link = NULL;
425 /* Form the msdfs_link contents */
426 msdfs_link = msdfs_link_string(frame,
427 reflist,
428 referral_count);
429 if (msdfs_link == NULL) {
430 goto out;
433 ret = symlinkat(msdfs_link,
434 fsp_get_pathref_fd(dirfsp),
435 smb_fname->base_name);
436 if (ret == 0) {
437 status = NT_STATUS_OK;
438 } else {
439 status = map_nt_error_from_unix(errno);
442 out:
444 TALLOC_FREE(frame);
445 return status;
449 * Read and return the contents of a DFS redirect given a
450 * pathname. A caller can pass in NULL for ppreflist and
451 * preferral_count but still determine if this was a
452 * DFS redirect point by getting NT_STATUS_OK back
453 * without incurring the overhead of reading and parsing
454 * the referral contents.
457 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
458 TALLOC_CTX *mem_ctx,
459 struct files_struct *dirfsp,
460 struct smb_filename *smb_fname,
461 struct referral **ppreflist,
462 size_t *preferral_count)
464 NTSTATUS status = NT_STATUS_NO_MEMORY;
465 size_t bufsize;
466 char *link_target = NULL;
467 int referral_len;
468 bool ok;
469 #if defined(HAVE_BROKEN_READLINK)
470 char link_target_buf[PATH_MAX];
471 #else
472 char link_target_buf[7];
473 #endif
474 int ret;
476 if (is_named_stream(smb_fname)) {
477 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
478 goto err;
481 if (ppreflist == NULL && preferral_count == NULL) {
483 * We're only checking if this is a DFS
484 * redirect. We don't need to return data.
486 bufsize = sizeof(link_target_buf);
487 link_target = link_target_buf;
488 } else {
489 bufsize = PATH_MAX;
490 link_target = talloc_array(mem_ctx, char, bufsize);
491 if (!link_target) {
492 goto err;
496 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
497 smb_fname->base_name,
498 link_target,
499 bufsize - 1);
500 if (referral_len == -1) {
501 if (errno == EINVAL) {
503 * If the path isn't a link, readlinkat
504 * returns EINVAL. Allow the caller to
505 * detect this.
507 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
508 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
509 } else {
510 status = map_nt_error_from_unix(errno);
511 if (errno == ENOENT) {
512 DBG_NOTICE("Error reading "
513 "msdfs link %s: %s\n",
514 smb_fname->base_name,
515 strerror(errno));
516 } else {
517 DBG_ERR("Error reading "
518 "msdfs link %s: %s\n",
519 smb_fname->base_name,
520 strerror(errno));
523 goto err;
525 link_target[referral_len] = '\0';
527 DBG_INFO("%s -> %s\n",
528 smb_fname->base_name,
529 link_target);
531 if (!strnequal(link_target, "msdfs:", 6)) {
532 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
533 goto err;
536 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
537 smb_fname->base_name,
538 &smb_fname->st,
539 AT_SYMLINK_NOFOLLOW,
540 lp_fake_directory_create_times(SNUM(handle->conn)));
541 if (ret < 0) {
542 status = map_nt_error_from_unix(errno);
543 goto err;
546 if (ppreflist == NULL && preferral_count == NULL) {
547 /* Early return for checking if this is a DFS link. */
548 return NT_STATUS_OK;
551 ok = parse_msdfs_symlink(mem_ctx,
552 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
553 link_target,
554 ppreflist,
555 preferral_count);
557 if (ok) {
558 status = NT_STATUS_OK;
559 } else {
560 status = NT_STATUS_NO_MEMORY;
563 err:
565 if (link_target != link_target_buf) {
566 TALLOC_FREE(link_target);
568 return status;
571 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
572 TALLOC_CTX *mem_ctx,
573 const char *service_path,
574 char **base_volume)
576 return NT_STATUS_NOT_SUPPORTED;
579 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
580 TALLOC_CTX *mem_ctx,
581 const char *base_volume,
582 time_t *tstamp,
583 bool rw,
584 char **base_path,
585 char **snap_path)
587 return NT_STATUS_NOT_SUPPORTED;
590 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
591 TALLOC_CTX *mem_ctx,
592 char *base_path,
593 char *snap_path)
595 return NT_STATUS_NOT_SUPPORTED;
598 /* Directory operations */
600 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
601 files_struct *fsp,
602 const char *mask,
603 uint32_t attr)
605 DIR *result;
607 START_PROFILE(syscall_fdopendir);
608 result = sys_fdopendir(fsp_get_io_fd(fsp));
609 END_PROFILE(syscall_fdopendir);
610 return result;
613 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
614 struct files_struct *dirfsp,
615 DIR *dirp)
617 struct dirent *result;
619 START_PROFILE(syscall_readdir);
621 result = readdir(dirp);
622 END_PROFILE(syscall_readdir);
624 return result;
627 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
628 struct files_struct *fsp,
629 TALLOC_CTX *mem_ctx,
630 struct readdir_attr_data **attr_data)
632 return NT_STATUS_NOT_SUPPORTED;
635 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
637 START_PROFILE(syscall_rewinddir);
638 rewinddir(dirp);
639 END_PROFILE(syscall_rewinddir);
642 static int vfswrap_mkdirat(vfs_handle_struct *handle,
643 struct files_struct *dirfsp,
644 const struct smb_filename *smb_fname,
645 mode_t mode)
647 int result;
649 START_PROFILE(syscall_mkdirat);
651 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
653 END_PROFILE(syscall_mkdirat);
654 return result;
657 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
659 int result;
661 START_PROFILE(syscall_closedir);
662 result = closedir(dirp);
663 END_PROFILE(syscall_closedir);
664 return result;
667 /* File operations */
669 static int vfswrap_openat(vfs_handle_struct *handle,
670 const struct files_struct *dirfsp,
671 const struct smb_filename *smb_fname,
672 files_struct *fsp,
673 const struct vfs_open_how *how)
675 int flags = how->flags;
676 mode_t mode = how->mode;
677 bool have_opath = false;
678 bool became_root = false;
679 int result;
681 START_PROFILE(syscall_openat);
683 if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
684 VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
685 errno = ENOSYS;
686 result = -1;
687 goto out;
690 SMB_ASSERT(!is_named_stream(smb_fname));
692 #ifdef O_PATH
693 have_opath = true;
694 if (fsp->fsp_flags.is_pathref) {
695 flags |= O_PATH;
697 if (flags & O_PATH) {
699 * From "man 2 openat":
701 * When O_PATH is specified in flags, flag bits other than
702 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
704 * From "man 2 openat2":
706 * Whereas openat(2) ignores unknown bits in its flags
707 * argument, openat2() returns an error if unknown or
708 * conflicting flags are specified in how.flags.
710 * So we better clear ignored/invalid flags
711 * and only keep the expected ones.
713 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
715 #endif
717 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
718 struct open_how linux_how = {
719 .flags = flags,
720 .mode = mode,
721 .resolve = RESOLVE_NO_SYMLINKS,
724 result = openat2(fsp_get_pathref_fd(dirfsp),
725 smb_fname->base_name,
726 &linux_how,
727 sizeof(linux_how));
728 if (result == -1) {
729 if (errno == ENOSYS) {
731 * The kernel doesn't support
732 * openat2(), so indicate to
733 * the callers that
734 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
735 * would just be a waste of time.
737 fsp->conn->open_how_resolve &=
738 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
740 goto out;
743 goto done;
746 if (fsp->fsp_flags.is_pathref && !have_opath) {
747 become_root();
748 became_root = true;
751 result = openat(fsp_get_pathref_fd(dirfsp),
752 smb_fname->base_name,
753 flags,
754 mode);
756 if (became_root) {
757 int err = errno;
758 unbecome_root();
759 errno = err;
762 done:
763 if (result >= 0) {
764 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
765 } else {
767 * "/proc/self/fd/-1" never exists. Indicate to upper
768 * layers that for this fsp a possible name-based
769 * fallback is the only way to go.
771 fsp->fsp_flags.have_proc_fds = false;
774 out:
775 END_PROFILE(syscall_openat);
776 return result;
778 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
779 struct smb_request *req,
780 struct files_struct *dirfsp,
781 struct smb_filename *smb_fname,
782 uint32_t access_mask,
783 uint32_t share_access,
784 uint32_t create_disposition,
785 uint32_t create_options,
786 uint32_t file_attributes,
787 uint32_t oplock_request,
788 const struct smb2_lease *lease,
789 uint64_t allocation_size,
790 uint32_t private_flags,
791 struct security_descriptor *sd,
792 struct ea_list *ea_list,
793 files_struct **result,
794 int *pinfo,
795 const struct smb2_create_blobs *in_context_blobs,
796 struct smb2_create_blobs *out_context_blobs)
798 return create_file_default(handle->conn, req, dirfsp, smb_fname,
799 access_mask, share_access,
800 create_disposition, create_options,
801 file_attributes, oplock_request, lease,
802 allocation_size, private_flags,
803 sd, ea_list, result,
804 pinfo, in_context_blobs, out_context_blobs);
807 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
809 int result;
811 START_PROFILE(syscall_close);
812 result = fd_close_posix(fsp);
813 END_PROFILE(syscall_close);
814 return result;
817 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
818 size_t n, off_t offset)
820 ssize_t result;
822 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
823 START_PROFILE_BYTES(syscall_pread, n);
824 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
825 END_PROFILE_BYTES(syscall_pread);
827 if (result == -1 && errno == ESPIPE) {
828 /* Maintain the fiction that pipes can be seeked (sought?) on. */
829 result = sys_read(fsp_get_io_fd(fsp), data, n);
830 fh_set_pos(fsp->fh, 0);
833 #else /* HAVE_PREAD */
834 errno = ENOSYS;
835 result = -1;
836 #endif /* HAVE_PREAD */
838 return result;
841 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
842 size_t n, off_t offset)
844 ssize_t result;
846 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
847 START_PROFILE_BYTES(syscall_pwrite, n);
848 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
849 END_PROFILE_BYTES(syscall_pwrite);
851 if (result == -1 && errno == ESPIPE) {
852 /* Maintain the fiction that pipes can be sought on. */
853 result = sys_write(fsp_get_io_fd(fsp), data, n);
856 #else /* HAVE_PWRITE */
857 errno = ENOSYS;
858 result = -1;
859 #endif /* HAVE_PWRITE */
861 return result;
864 struct vfswrap_pread_state {
865 ssize_t ret;
866 int fd;
867 void *buf;
868 size_t count;
869 off_t offset;
871 struct vfs_aio_state vfs_aio_state;
872 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
875 static void vfs_pread_do(void *private_data);
876 static void vfs_pread_done(struct tevent_req *subreq);
877 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
879 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
880 TALLOC_CTX *mem_ctx,
881 struct tevent_context *ev,
882 struct files_struct *fsp,
883 void *data,
884 size_t n, off_t offset)
886 struct tevent_req *req, *subreq;
887 struct vfswrap_pread_state *state;
889 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
890 if (req == NULL) {
891 return NULL;
894 state->ret = -1;
895 state->fd = fsp_get_io_fd(fsp);
896 state->buf = data;
897 state->count = n;
898 state->offset = offset;
900 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
901 state->profile_bytes, n);
902 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
904 subreq = pthreadpool_tevent_job_send(
905 state, ev, handle->conn->sconn->pool,
906 vfs_pread_do, state);
907 if (tevent_req_nomem(subreq, req)) {
908 return tevent_req_post(req, ev);
910 tevent_req_set_callback(subreq, vfs_pread_done, req);
912 talloc_set_destructor(state, vfs_pread_state_destructor);
914 return req;
917 static void vfs_pread_do(void *private_data)
919 struct vfswrap_pread_state *state = talloc_get_type_abort(
920 private_data, struct vfswrap_pread_state);
921 struct timespec start_time;
922 struct timespec end_time;
924 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
926 PROFILE_TIMESTAMP(&start_time);
928 state->ret = sys_pread_full(state->fd,
929 state->buf,
930 state->count,
931 state->offset);
933 if (state->ret == -1) {
934 state->vfs_aio_state.error = errno;
937 PROFILE_TIMESTAMP(&end_time);
939 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
941 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
944 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
946 return -1;
949 static void vfs_pread_done(struct tevent_req *subreq)
951 struct tevent_req *req = tevent_req_callback_data(
952 subreq, struct tevent_req);
953 struct vfswrap_pread_state *state = tevent_req_data(
954 req, struct vfswrap_pread_state);
955 int ret;
957 ret = pthreadpool_tevent_job_recv(subreq);
958 TALLOC_FREE(subreq);
959 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
960 talloc_set_destructor(state, NULL);
961 if (ret != 0) {
962 if (ret != EAGAIN) {
963 tevent_req_error(req, ret);
964 return;
967 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
968 * means the lower level pthreadpool failed to create a new
969 * thread. Fallback to sync processing in that case to allow
970 * some progress for the client.
972 vfs_pread_do(state);
975 tevent_req_done(req);
978 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
979 struct vfs_aio_state *vfs_aio_state)
981 struct vfswrap_pread_state *state = tevent_req_data(
982 req, struct vfswrap_pread_state);
984 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
985 return -1;
988 *vfs_aio_state = state->vfs_aio_state;
989 return state->ret;
992 struct vfswrap_pwrite_state {
993 ssize_t ret;
994 int fd;
995 const void *buf;
996 size_t count;
997 off_t offset;
999 struct vfs_aio_state vfs_aio_state;
1000 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1003 static void vfs_pwrite_do(void *private_data);
1004 static void vfs_pwrite_done(struct tevent_req *subreq);
1005 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
1007 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
1008 TALLOC_CTX *mem_ctx,
1009 struct tevent_context *ev,
1010 struct files_struct *fsp,
1011 const void *data,
1012 size_t n, off_t offset)
1014 struct tevent_req *req, *subreq;
1015 struct vfswrap_pwrite_state *state;
1017 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1018 if (req == NULL) {
1019 return NULL;
1022 state->ret = -1;
1023 state->fd = fsp_get_io_fd(fsp);
1024 state->buf = data;
1025 state->count = n;
1026 state->offset = offset;
1028 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1029 state->profile_bytes, n);
1030 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1032 subreq = pthreadpool_tevent_job_send(
1033 state, ev, handle->conn->sconn->pool,
1034 vfs_pwrite_do, state);
1035 if (tevent_req_nomem(subreq, req)) {
1036 return tevent_req_post(req, ev);
1038 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1040 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1042 return req;
1045 static void vfs_pwrite_do(void *private_data)
1047 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1048 private_data, struct vfswrap_pwrite_state);
1049 struct timespec start_time;
1050 struct timespec end_time;
1052 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1054 PROFILE_TIMESTAMP(&start_time);
1056 state->ret = sys_pwrite_full(state->fd,
1057 state->buf,
1058 state->count,
1059 state->offset);
1061 if (state->ret == -1) {
1062 state->vfs_aio_state.error = errno;
1065 PROFILE_TIMESTAMP(&end_time);
1067 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1069 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1072 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1074 return -1;
1077 static void vfs_pwrite_done(struct tevent_req *subreq)
1079 struct tevent_req *req = tevent_req_callback_data(
1080 subreq, struct tevent_req);
1081 struct vfswrap_pwrite_state *state = tevent_req_data(
1082 req, struct vfswrap_pwrite_state);
1083 int ret;
1085 ret = pthreadpool_tevent_job_recv(subreq);
1086 TALLOC_FREE(subreq);
1087 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1088 talloc_set_destructor(state, NULL);
1089 if (ret != 0) {
1090 if (ret != EAGAIN) {
1091 tevent_req_error(req, ret);
1092 return;
1095 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1096 * means the lower level pthreadpool failed to create a new
1097 * thread. Fallback to sync processing in that case to allow
1098 * some progress for the client.
1100 vfs_pwrite_do(state);
1103 tevent_req_done(req);
1106 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1107 struct vfs_aio_state *vfs_aio_state)
1109 struct vfswrap_pwrite_state *state = tevent_req_data(
1110 req, struct vfswrap_pwrite_state);
1112 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1113 return -1;
1116 *vfs_aio_state = state->vfs_aio_state;
1117 return state->ret;
1120 struct vfswrap_fsync_state {
1121 ssize_t ret;
1122 int fd;
1124 struct vfs_aio_state vfs_aio_state;
1125 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1128 static void vfs_fsync_do(void *private_data);
1129 static void vfs_fsync_done(struct tevent_req *subreq);
1130 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1132 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1133 TALLOC_CTX *mem_ctx,
1134 struct tevent_context *ev,
1135 struct files_struct *fsp)
1137 struct tevent_req *req, *subreq;
1138 struct vfswrap_fsync_state *state;
1140 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1141 if (req == NULL) {
1142 return NULL;
1145 state->ret = -1;
1146 state->fd = fsp_get_io_fd(fsp);
1148 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1149 state->profile_bytes, 0);
1150 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1152 subreq = pthreadpool_tevent_job_send(
1153 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1154 if (tevent_req_nomem(subreq, req)) {
1155 return tevent_req_post(req, ev);
1157 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1159 talloc_set_destructor(state, vfs_fsync_state_destructor);
1161 return req;
1164 static void vfs_fsync_do(void *private_data)
1166 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1167 private_data, struct vfswrap_fsync_state);
1168 struct timespec start_time;
1169 struct timespec end_time;
1171 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1173 PROFILE_TIMESTAMP(&start_time);
1175 do {
1176 state->ret = fsync(state->fd);
1177 } while ((state->ret == -1) && (errno == EINTR));
1179 if (state->ret == -1) {
1180 state->vfs_aio_state.error = errno;
1183 PROFILE_TIMESTAMP(&end_time);
1185 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1187 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1190 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1192 return -1;
1195 static void vfs_fsync_done(struct tevent_req *subreq)
1197 struct tevent_req *req = tevent_req_callback_data(
1198 subreq, struct tevent_req);
1199 struct vfswrap_fsync_state *state = tevent_req_data(
1200 req, struct vfswrap_fsync_state);
1201 int ret;
1203 ret = pthreadpool_tevent_job_recv(subreq);
1204 TALLOC_FREE(subreq);
1205 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1206 talloc_set_destructor(state, NULL);
1207 if (ret != 0) {
1208 if (ret != EAGAIN) {
1209 tevent_req_error(req, ret);
1210 return;
1213 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1214 * means the lower level pthreadpool failed to create a new
1215 * thread. Fallback to sync processing in that case to allow
1216 * some progress for the client.
1218 vfs_fsync_do(state);
1221 tevent_req_done(req);
1224 static int vfswrap_fsync_recv(struct tevent_req *req,
1225 struct vfs_aio_state *vfs_aio_state)
1227 struct vfswrap_fsync_state *state = tevent_req_data(
1228 req, struct vfswrap_fsync_state);
1230 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1231 return -1;
1234 *vfs_aio_state = state->vfs_aio_state;
1235 return state->ret;
1238 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1240 off_t result = 0;
1242 START_PROFILE(syscall_lseek);
1244 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1246 * We want to maintain the fiction that we can seek
1247 * on a fifo for file system purposes. This allows
1248 * people to set up UNIX fifo's that feed data to Windows
1249 * applications. JRA.
1252 if((result == -1) && (errno == ESPIPE)) {
1253 result = 0;
1254 errno = 0;
1257 END_PROFILE(syscall_lseek);
1258 return result;
1261 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1262 off_t offset, size_t n)
1264 ssize_t result;
1266 START_PROFILE_BYTES(syscall_sendfile, n);
1267 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1268 END_PROFILE_BYTES(syscall_sendfile);
1269 return result;
1272 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1273 int fromfd,
1274 files_struct *tofsp,
1275 off_t offset,
1276 size_t n)
1278 ssize_t result;
1280 START_PROFILE_BYTES(syscall_recvfile, n);
1281 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1282 END_PROFILE_BYTES(syscall_recvfile);
1283 return result;
1286 static int vfswrap_renameat(vfs_handle_struct *handle,
1287 files_struct *srcfsp,
1288 const struct smb_filename *smb_fname_src,
1289 files_struct *dstfsp,
1290 const struct smb_filename *smb_fname_dst,
1291 const struct vfs_rename_how *how)
1293 int result = -1;
1294 int flags = 0;
1296 START_PROFILE(syscall_renameat);
1298 SMB_ASSERT(!is_named_stream(smb_fname_src));
1299 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1301 if (how->flags & ~VFS_RENAME_HOW_NO_REPLACE) {
1302 END_PROFILE(syscall_renameat);
1303 errno = EINVAL;
1304 return -1;
1307 if (how->flags & VFS_RENAME_HOW_NO_REPLACE) {
1308 flags |= RENAME_NOREPLACE;
1311 result = renameat2(fsp_get_pathref_fd(srcfsp),
1312 smb_fname_src->base_name,
1313 fsp_get_pathref_fd(dstfsp),
1314 smb_fname_dst->base_name,
1315 flags);
1317 END_PROFILE(syscall_renameat);
1318 return result;
1321 static int vfswrap_stat(vfs_handle_struct *handle,
1322 struct smb_filename *smb_fname)
1324 int result = -1;
1326 START_PROFILE(syscall_stat);
1328 SMB_ASSERT(!is_named_stream(smb_fname));
1330 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1331 lp_fake_directory_create_times(SNUM(handle->conn)));
1333 END_PROFILE(syscall_stat);
1334 return result;
1337 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1339 int result;
1341 START_PROFILE(syscall_fstat);
1342 result = sys_fstat(fsp_get_pathref_fd(fsp),
1343 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1344 END_PROFILE(syscall_fstat);
1345 return result;
1348 static int vfswrap_lstat(vfs_handle_struct *handle,
1349 struct smb_filename *smb_fname)
1351 int result = -1;
1353 START_PROFILE(syscall_lstat);
1355 SMB_ASSERT(!is_named_stream(smb_fname));
1357 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1358 lp_fake_directory_create_times(SNUM(handle->conn)));
1360 END_PROFILE(syscall_lstat);
1361 return result;
1364 static int vfswrap_fstatat(
1365 struct vfs_handle_struct *handle,
1366 const struct files_struct *dirfsp,
1367 const struct smb_filename *smb_fname,
1368 SMB_STRUCT_STAT *sbuf,
1369 int flags)
1371 int result = -1;
1373 START_PROFILE(syscall_fstatat);
1375 SMB_ASSERT(!is_named_stream(smb_fname));
1377 result = sys_fstatat(
1378 fsp_get_pathref_fd(dirfsp),
1379 smb_fname->base_name,
1380 sbuf,
1381 flags,
1382 lp_fake_directory_create_times(SNUM(handle->conn)));
1384 END_PROFILE(syscall_fstatat);
1385 return result;
1388 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1389 const char *name,
1390 enum vfs_translate_direction direction,
1391 TALLOC_CTX *mem_ctx,
1392 char **mapped_name)
1394 return NT_STATUS_NONE_MAPPED;
1398 * Return allocated parent directory and basename of path
1400 * Note: if requesting atname, it is returned as talloc child of the
1401 * parent. Freeing the parent is thus sufficient to free both.
1403 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1404 TALLOC_CTX *mem_ctx,
1405 const struct smb_filename *smb_fname_in,
1406 struct smb_filename **parent_dir_out,
1407 struct smb_filename **atname_out)
1409 struct smb_filename *parent = NULL;
1410 struct smb_filename *name = NULL;
1411 char *p = NULL;
1413 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1414 if (parent == NULL) {
1415 return NT_STATUS_NO_MEMORY;
1417 SET_STAT_INVALID(parent->st);
1419 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1420 if (p == NULL) {
1421 TALLOC_FREE(parent->base_name);
1422 parent->base_name = talloc_strdup(parent, ".");
1423 if (parent->base_name == NULL) {
1424 TALLOC_FREE(parent);
1425 return NT_STATUS_NO_MEMORY;
1427 p = smb_fname_in->base_name;
1428 } else {
1429 *p = '\0';
1430 p++;
1433 if (atname_out == NULL) {
1434 *parent_dir_out = parent;
1435 return NT_STATUS_OK;
1438 name = synthetic_smb_fname(
1439 parent,
1441 smb_fname_in->stream_name,
1442 &smb_fname_in->st,
1443 smb_fname_in->twrp,
1444 smb_fname_in->flags);
1445 if (name == NULL) {
1446 return NT_STATUS_NO_MEMORY;
1449 *parent_dir_out = parent;
1450 *atname_out = name;
1451 return NT_STATUS_OK;
1455 * Implement the default fsctl operation.
1457 static bool vfswrap_logged_ioctl_message = false;
1459 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1460 struct files_struct *fsp,
1461 TALLOC_CTX *ctx,
1462 uint32_t function,
1463 uint16_t req_flags, /* Needed for UNICODE ... */
1464 const uint8_t *_in_data,
1465 uint32_t in_len,
1466 uint8_t **_out_data,
1467 uint32_t max_out_len,
1468 uint32_t *out_len)
1470 const char *in_data = (const char *)_in_data;
1471 char **out_data = (char **)_out_data;
1472 NTSTATUS status;
1475 * Currently all fsctls operate on the base
1476 * file if given an alternate data stream.
1477 * Revisit this if we implement fsctls later
1478 * that need access to the ADS handle.
1480 fsp = metadata_fsp(fsp);
1482 switch (function) {
1483 case FSCTL_SET_SPARSE:
1485 bool set_sparse = true;
1487 if (in_len >= 1 && in_data[0] == 0) {
1488 set_sparse = false;
1491 status = file_set_sparse(handle->conn, fsp, set_sparse);
1493 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1494 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1495 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1496 nt_errstr(status)));
1498 return status;
1501 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1503 unsigned char objid[16];
1504 uint8_t *return_data = NULL;
1506 /* This should return the object-id on this file.
1507 * I think I'll make this be the inode+dev. JRA.
1510 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1511 fsp_fnum_dbg(fsp));
1513 *out_len = MIN(max_out_len, 64);
1515 /* Hmmm, will this cause problems if less data asked for? */
1516 return_data = talloc_array(ctx, uint8_t, 64);
1517 if (return_data == NULL) {
1518 return NT_STATUS_NO_MEMORY;
1521 /* For backwards compatibility only store the dev/inode. */
1522 push_file_id_16(return_data, &fsp->file_id);
1523 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1524 push_file_id_16(return_data + 32, &fsp->file_id);
1525 memset(return_data+48, 0, 16);
1526 *_out_data = return_data;
1527 return NT_STATUS_OK;
1530 case FSCTL_GET_REPARSE_POINT:
1532 uint32_t tag;
1533 status = fsctl_get_reparse_point(
1534 fsp, ctx, &tag, _out_data, max_out_len, out_len);
1535 return status;
1538 case FSCTL_SET_REPARSE_POINT:
1540 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1541 return status;
1544 case FSCTL_DELETE_REPARSE_POINT:
1546 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1547 return status;
1550 case FSCTL_GET_SHADOW_COPY_DATA:
1553 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1554 * and return their volume names. If max_data_count is 16, then it is just
1555 * asking for the number of volumes and length of the combined names.
1557 * pdata is the data allocated by our caller, but that uses
1558 * total_data_count (which is 0 in our case) rather than max_data_count.
1559 * Allocate the correct amount and return the pointer to let
1560 * it be deallocated when we return.
1562 struct shadow_copy_data *shadow_data = NULL;
1563 bool labels = False;
1564 uint32_t labels_data_count = 0;
1565 uint32_t i;
1566 char *cur_pdata = NULL;
1568 if (max_out_len < 16) {
1569 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1570 max_out_len);
1571 return NT_STATUS_INVALID_PARAMETER;
1574 if (max_out_len > 16) {
1575 labels = True;
1578 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1579 if (shadow_data == NULL) {
1580 DBG_ERR("TALLOC_ZERO() failed!\n");
1581 return NT_STATUS_NO_MEMORY;
1585 * Call the VFS routine to actually do the work.
1587 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1588 int log_lev = DBGLVL_ERR;
1589 if (errno == 0) {
1590 /* broken module didn't set errno on error */
1591 status = NT_STATUS_UNSUCCESSFUL;
1592 } else {
1593 status = map_nt_error_from_unix(errno);
1594 if (NT_STATUS_EQUAL(status,
1595 NT_STATUS_NOT_SUPPORTED)) {
1596 log_lev = DBGLVL_INFO;
1599 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1600 "connectpath %s, failed - %s.\n",
1601 fsp->conn->connectpath,
1602 nt_errstr(status)));
1603 TALLOC_FREE(shadow_data);
1604 return status;
1607 labels_data_count = (shadow_data->num_volumes * 2 *
1608 sizeof(SHADOW_COPY_LABEL)) + 2;
1610 if (!labels) {
1611 *out_len = 16;
1612 } else {
1613 *out_len = 12 + labels_data_count;
1616 if (max_out_len < *out_len) {
1617 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1618 max_out_len, *out_len);
1619 TALLOC_FREE(shadow_data);
1620 return NT_STATUS_BUFFER_TOO_SMALL;
1623 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1624 if (cur_pdata == NULL) {
1625 TALLOC_FREE(shadow_data);
1626 return NT_STATUS_NO_MEMORY;
1629 *out_data = cur_pdata;
1631 /* num_volumes 4 bytes */
1632 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1634 if (labels) {
1635 /* num_labels 4 bytes */
1636 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1639 /* needed_data_count 4 bytes */
1640 SIVAL(cur_pdata, 8, labels_data_count);
1642 cur_pdata += 12;
1644 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1645 shadow_data->num_volumes, fsp_str_dbg(fsp));
1646 if (labels && shadow_data->labels) {
1647 for (i=0; i<shadow_data->num_volumes; i++) {
1648 size_t len = 0;
1649 status = srvstr_push(cur_pdata, req_flags,
1650 cur_pdata, shadow_data->labels[i],
1651 2 * sizeof(SHADOW_COPY_LABEL),
1652 STR_UNICODE|STR_TERMINATE, &len);
1653 if (!NT_STATUS_IS_OK(status)) {
1654 TALLOC_FREE(*out_data);
1655 TALLOC_FREE(shadow_data);
1656 return status;
1658 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1659 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1663 TALLOC_FREE(shadow_data);
1665 return NT_STATUS_OK;
1668 case FSCTL_FIND_FILES_BY_SID:
1670 /* pretend this succeeded -
1672 * we have to send back a list with all files owned by this SID
1674 * but I have to check that --metze
1676 ssize_t ret;
1677 struct dom_sid sid;
1678 struct dom_sid_buf buf;
1679 uid_t uid;
1680 size_t sid_len;
1682 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1683 fsp_fnum_dbg(fsp));
1685 if (in_len < 8) {
1686 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1687 return NT_STATUS_INVALID_PARAMETER;
1690 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1692 /* unknown 4 bytes: this is not the length of the sid :-( */
1693 /*unknown = IVAL(pdata,0);*/
1695 ret = sid_parse(_in_data + 4, sid_len, &sid);
1696 if (ret == -1) {
1697 return NT_STATUS_INVALID_PARAMETER;
1699 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1700 dom_sid_str_buf(&sid, &buf)));
1702 if (!sid_to_uid(&sid, &uid)) {
1703 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1704 dom_sid_str_buf(&sid, &buf),
1705 (unsigned long)sid_len);
1706 uid = (-1);
1709 /* we can take a look at the find source :-)
1711 * find ./ -uid $uid -name '*' is what we need here
1714 * and send 4bytes len and then NULL terminated unicode strings
1715 * for each file
1717 * but I don't know how to deal with the paged results
1718 * (maybe we can hang the result anywhere in the fsp struct)
1720 * but I don't know how to deal with the paged results
1721 * (maybe we can hang the result anywhere in the fsp struct)
1723 * we don't send all files at once
1724 * and at the next we should *not* start from the beginning,
1725 * so we have to cache the result
1727 * --metze
1730 /* this works for now... */
1731 return NT_STATUS_OK;
1734 case FSCTL_QUERY_ALLOCATED_RANGES:
1736 /* FIXME: This is just a dummy reply, telling that all of the
1737 * file is allocated. MKS cp needs that.
1738 * Adding the real allocated ranges via FIEMAP on Linux
1739 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1740 * this FSCTL correct for sparse files.
1742 uint64_t offset, length;
1743 char *out_data_tmp = NULL;
1745 if (in_len != 16) {
1746 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1747 in_len);
1748 return NT_STATUS_INVALID_PARAMETER;
1751 if (max_out_len < 16) {
1752 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1753 max_out_len);
1754 return NT_STATUS_INVALID_PARAMETER;
1757 offset = BVAL(in_data,0);
1758 length = BVAL(in_data,8);
1760 if (offset + length < offset) {
1761 /* No 64-bit integer wrap. */
1762 return NT_STATUS_INVALID_PARAMETER;
1765 /* Shouldn't this be SMB_VFS_STAT ... ? */
1766 status = vfs_stat_fsp(fsp);
1767 if (!NT_STATUS_IS_OK(status)) {
1768 return status;
1771 *out_len = 16;
1772 out_data_tmp = talloc_array(ctx, char, *out_len);
1773 if (out_data_tmp == NULL) {
1774 DBG_DEBUG("unable to allocate memory for response\n");
1775 return NT_STATUS_NO_MEMORY;
1778 if (offset > fsp->fsp_name->st.st_ex_size ||
1779 fsp->fsp_name->st.st_ex_size == 0 ||
1780 length == 0) {
1781 memset(out_data_tmp, 0, *out_len);
1782 } else {
1783 uint64_t end = offset + length;
1784 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1785 SBVAL(out_data_tmp, 0, 0);
1786 SBVAL(out_data_tmp, 8, end);
1789 *out_data = out_data_tmp;
1791 return NT_STATUS_OK;
1794 case FSCTL_IS_VOLUME_DIRTY:
1796 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1797 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1799 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1800 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1802 return NT_STATUS_INVALID_PARAMETER;
1805 default:
1807 * Only print once ... unfortunately there could be lots of
1808 * different FSCTLs that are called.
1810 if (!vfswrap_logged_ioctl_message) {
1811 vfswrap_logged_ioctl_message = true;
1812 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1813 __func__, function);
1817 return NT_STATUS_NOT_SUPPORTED;
1820 static bool vfswrap_is_offline(struct connection_struct *conn,
1821 const struct smb_filename *fname);
1823 struct vfswrap_get_dos_attributes_state {
1824 struct vfs_aio_state aio_state;
1825 connection_struct *conn;
1826 TALLOC_CTX *mem_ctx;
1827 struct tevent_context *ev;
1828 files_struct *dir_fsp;
1829 struct smb_filename *smb_fname;
1830 uint32_t dosmode;
1831 bool as_root;
1834 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1836 static struct tevent_req *vfswrap_get_dos_attributes_send(
1837 TALLOC_CTX *mem_ctx,
1838 struct tevent_context *ev,
1839 struct vfs_handle_struct *handle,
1840 files_struct *dir_fsp,
1841 struct smb_filename *smb_fname)
1843 struct tevent_req *req = NULL;
1844 struct tevent_req *subreq = NULL;
1845 struct vfswrap_get_dos_attributes_state *state = NULL;
1847 SMB_ASSERT(!is_named_stream(smb_fname));
1849 req = tevent_req_create(mem_ctx, &state,
1850 struct vfswrap_get_dos_attributes_state);
1851 if (req == NULL) {
1852 return NULL;
1855 *state = (struct vfswrap_get_dos_attributes_state) {
1856 .conn = dir_fsp->conn,
1857 .mem_ctx = mem_ctx,
1858 .ev = ev,
1859 .dir_fsp = dir_fsp,
1860 .smb_fname = smb_fname,
1863 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1864 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1865 "\"store dos attributes\" is disabled\n",
1866 dir_fsp->conn->connectpath);
1867 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1868 return tevent_req_post(req, ev);
1871 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1873 dir_fsp,
1874 smb_fname,
1875 SAMBA_XATTR_DOS_ATTRIB,
1876 sizeof(fstring));
1877 if (tevent_req_nomem(subreq, req)) {
1878 return tevent_req_post(req, ev);
1880 tevent_req_set_callback(subreq,
1881 vfswrap_get_dos_attributes_getxattr_done,
1882 req);
1884 return req;
1887 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1889 struct tevent_req *req =
1890 tevent_req_callback_data(subreq,
1891 struct tevent_req);
1892 struct vfswrap_get_dos_attributes_state *state =
1893 tevent_req_data(req,
1894 struct vfswrap_get_dos_attributes_state);
1895 ssize_t xattr_size;
1896 DATA_BLOB blob = {0};
1897 char *path = NULL;
1898 char *tofree = NULL;
1899 char pathbuf[PATH_MAX+1];
1900 ssize_t pathlen;
1901 struct smb_filename smb_fname;
1902 bool offline;
1903 NTSTATUS status;
1905 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1906 &state->aio_state,
1907 state,
1908 &blob.data);
1909 TALLOC_FREE(subreq);
1910 if (xattr_size == -1) {
1911 status = map_nt_error_from_unix(state->aio_state.error);
1913 if (state->as_root) {
1914 tevent_req_nterror(req, status);
1915 return;
1917 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1918 tevent_req_nterror(req, status);
1919 return;
1922 state->as_root = true;
1924 become_root();
1925 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1926 state->ev,
1927 state->dir_fsp,
1928 state->smb_fname,
1929 SAMBA_XATTR_DOS_ATTRIB,
1930 sizeof(fstring));
1931 unbecome_root();
1932 if (tevent_req_nomem(subreq, req)) {
1933 return;
1935 tevent_req_set_callback(subreq,
1936 vfswrap_get_dos_attributes_getxattr_done,
1937 req);
1938 return;
1941 blob.length = xattr_size;
1943 status = parse_dos_attribute_blob(state->smb_fname,
1944 blob,
1945 &state->dosmode);
1946 if (!NT_STATUS_IS_OK(status)) {
1947 tevent_req_nterror(req, status);
1948 return;
1951 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1952 state->smb_fname->base_name,
1953 pathbuf,
1954 sizeof(pathbuf),
1955 &path,
1956 &tofree);
1957 if (pathlen == -1) {
1958 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1959 return;
1962 smb_fname = (struct smb_filename) {
1963 .base_name = path,
1964 .st = state->smb_fname->st,
1965 .flags = state->smb_fname->flags,
1966 .twrp = state->smb_fname->twrp,
1969 offline = vfswrap_is_offline(state->conn, &smb_fname);
1970 if (offline) {
1971 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1973 TALLOC_FREE(tofree);
1975 tevent_req_done(req);
1976 return;
1979 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1980 struct vfs_aio_state *aio_state,
1981 uint32_t *dosmode)
1983 struct vfswrap_get_dos_attributes_state *state =
1984 tevent_req_data(req,
1985 struct vfswrap_get_dos_attributes_state);
1986 NTSTATUS status;
1988 if (tevent_req_is_nterror(req, &status)) {
1989 tevent_req_received(req);
1990 return status;
1993 *aio_state = state->aio_state;
1994 *dosmode = state->dosmode;
1995 tevent_req_received(req);
1996 return NT_STATUS_OK;
1999 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
2000 struct files_struct *fsp,
2001 uint32_t *dosmode)
2003 bool offline;
2005 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2007 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
2008 if (offline) {
2009 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
2012 return fget_ea_dos_attribute(fsp, dosmode);
2015 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
2016 struct files_struct *fsp,
2017 uint32_t dosmode)
2019 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2021 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2024 static struct vfs_offload_ctx *vfswrap_offload_ctx;
2026 struct vfswrap_offload_read_state {
2027 DATA_BLOB token;
2030 static struct tevent_req *vfswrap_offload_read_send(
2031 TALLOC_CTX *mem_ctx,
2032 struct tevent_context *ev,
2033 struct vfs_handle_struct *handle,
2034 struct files_struct *fsp,
2035 uint32_t fsctl,
2036 uint32_t ttl,
2037 off_t offset,
2038 size_t to_copy)
2040 struct tevent_req *req = NULL;
2041 struct vfswrap_offload_read_state *state = NULL;
2042 NTSTATUS status;
2044 req = tevent_req_create(mem_ctx, &state,
2045 struct vfswrap_offload_read_state);
2046 if (req == NULL) {
2047 return NULL;
2050 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2051 &vfswrap_offload_ctx);
2052 if (tevent_req_nterror(req, status)) {
2053 return tevent_req_post(req, ev);
2056 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY &&
2057 fsctl != FSCTL_DUP_EXTENTS_TO_FILE)
2059 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2060 return tevent_req_post(req, ev);
2063 if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE &&
2064 !(fsp->conn->fs_capabilities & FILE_SUPPORTS_BLOCK_REFCOUNTING))
2066 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2067 return tevent_req_post(req, ev);
2070 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2071 &state->token);
2072 if (tevent_req_nterror(req, status)) {
2073 return tevent_req_post(req, ev);
2076 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2077 &state->token);
2078 if (tevent_req_nterror(req, status)) {
2079 return tevent_req_post(req, ev);
2082 tevent_req_done(req);
2083 return tevent_req_post(req, ev);
2086 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2087 struct vfs_handle_struct *handle,
2088 TALLOC_CTX *mem_ctx,
2089 uint32_t *flags,
2090 uint64_t *xferlen,
2091 DATA_BLOB *token)
2093 struct vfswrap_offload_read_state *state = tevent_req_data(
2094 req, struct vfswrap_offload_read_state);
2095 NTSTATUS status;
2097 if (tevent_req_is_nterror(req, &status)) {
2098 tevent_req_received(req);
2099 return status;
2102 *flags = 0;
2103 *xferlen = 0;
2104 token->length = state->token.length;
2105 token->data = talloc_move(mem_ctx, &state->token.data);
2107 tevent_req_received(req);
2108 return NT_STATUS_OK;
2111 struct vfswrap_offload_write_state {
2112 uint8_t *buf;
2113 bool read_lck_locked;
2114 bool write_lck_locked;
2115 DATA_BLOB *token;
2116 struct tevent_context *src_ev;
2117 struct files_struct *src_fsp;
2118 off_t src_off;
2119 struct tevent_context *dst_ev;
2120 struct files_struct *dst_fsp;
2121 off_t dst_off;
2122 off_t to_copy;
2123 off_t remaining;
2124 off_t copied;
2125 size_t next_io_size;
2128 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2129 enum tevent_req_state req_state)
2131 struct vfswrap_offload_write_state *state = tevent_req_data(
2132 req, struct vfswrap_offload_write_state);
2133 bool ok;
2135 if (state->dst_fsp == NULL) {
2136 return;
2139 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2140 SMB_ASSERT(ok);
2141 state->dst_fsp = NULL;
2144 static NTSTATUS vfswrap_offload_fast_copy(struct tevent_req *req, int fsctl);
2145 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2147 static struct tevent_req *vfswrap_offload_write_send(
2148 struct vfs_handle_struct *handle,
2149 TALLOC_CTX *mem_ctx,
2150 struct tevent_context *ev,
2151 uint32_t fsctl,
2152 DATA_BLOB *token,
2153 off_t transfer_offset,
2154 struct files_struct *dest_fsp,
2155 off_t dest_off,
2156 off_t to_copy)
2158 struct tevent_req *req;
2159 struct vfswrap_offload_write_state *state = NULL;
2160 /* off_t is signed! */
2161 off_t max_offset = INT64_MAX - to_copy;
2162 off_t num = to_copy;
2163 files_struct *src_fsp = NULL;
2164 NTSTATUS status;
2165 bool ok;
2167 req = tevent_req_create(mem_ctx, &state,
2168 struct vfswrap_offload_write_state);
2169 if (req == NULL) {
2170 return NULL;
2173 *state = (struct vfswrap_offload_write_state) {
2174 .token = token,
2175 .src_off = transfer_offset,
2176 .dst_ev = ev,
2177 .dst_fsp = dest_fsp,
2178 .dst_off = dest_off,
2179 .to_copy = to_copy,
2180 .remaining = to_copy,
2183 status = vfs_offload_token_ctx_init(handle->conn->sconn->client,
2184 &vfswrap_offload_ctx);
2185 if (tevent_req_nterror(req, status)) {
2186 return tevent_req_post(req, ev);
2189 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2191 switch (fsctl) {
2192 case FSCTL_DUP_EXTENTS_TO_FILE:
2193 break;
2195 case FSCTL_SRV_COPYCHUNK:
2196 case FSCTL_SRV_COPYCHUNK_WRITE:
2197 num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2198 break;
2200 case FSCTL_OFFLOAD_WRITE:
2201 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2202 return tevent_req_post(req, ev);
2204 default:
2205 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2206 return tevent_req_post(req, ev);
2209 if (to_copy == 0) {
2210 tevent_req_done(req);
2211 return tevent_req_post(req, ev);
2214 if (state->src_off > max_offset) {
2216 * Protect integer checks below.
2218 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2219 return tevent_req_post(req, ev);
2221 if (state->src_off < 0) {
2223 * Protect integer checks below.
2225 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2226 return tevent_req_post(req, ev);
2228 if (state->dst_off > max_offset) {
2230 * Protect integer checks below.
2232 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2233 return tevent_req_post(req, ev);
2235 if (state->dst_off < 0) {
2237 * Protect integer checks below.
2239 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2240 return tevent_req_post(req, ev);
2243 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2244 token, &src_fsp);
2245 if (tevent_req_nterror(req, status)) {
2246 return tevent_req_post(req, ev);
2249 DBG_DEBUG("server side copy (%s) of length %" PRIu64 "\n",
2250 fsctl == FSCTL_DUP_EXTENTS_TO_FILE ? "reflink" : "chunk",
2251 to_copy);
2253 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2254 if (!NT_STATUS_IS_OK(status)) {
2255 tevent_req_nterror(req, status);
2256 return tevent_req_post(req, ev);
2259 ok = change_to_user_and_service_by_fsp(src_fsp);
2260 if (!ok) {
2261 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2262 return tevent_req_post(req, ev);
2265 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2266 state->src_fsp = src_fsp;
2268 status = vfs_stat_fsp(src_fsp);
2269 if (tevent_req_nterror(req, status)) {
2270 return tevent_req_post(req, ev);
2273 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2275 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2276 * If the SourceOffset or SourceOffset + Length extends beyond
2277 * the end of file, the server SHOULD<240> treat this as a
2278 * STATUS_END_OF_FILE error.
2279 * ...
2280 * <240> Section 3.3.5.15.6: Windows servers will return
2281 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2283 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2284 return tevent_req_post(req, ev);
2287 status = vfswrap_offload_fast_copy(req, fsctl);
2288 if (NT_STATUS_IS_OK(status)) {
2289 tevent_req_done(req);
2290 return tevent_req_post(req, ev);
2292 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2293 tevent_req_nterror(req, status);
2294 return tevent_req_post(req, ev);
2297 state->buf = talloc_array(state, uint8_t, num);
2298 if (tevent_req_nomem(state->buf, req)) {
2299 return tevent_req_post(req, ev);
2302 status = vfswrap_offload_write_loop(req);
2303 if (!NT_STATUS_IS_OK(status)) {
2304 tevent_req_nterror(req, status);
2305 return tevent_req_post(req, ev);
2308 return req;
2311 static NTSTATUS vfswrap_offload_fast_copy(struct tevent_req *req, int fsctl)
2313 struct vfswrap_offload_write_state *state = tevent_req_data(
2314 req, struct vfswrap_offload_write_state);
2315 struct lock_struct lck;
2316 ssize_t nwritten;
2317 NTSTATUS status;
2318 bool same_file;
2319 bool ok;
2320 static bool try_copy_file_range = true;
2322 same_file = file_id_equal(&state->src_fsp->file_id,
2323 &state->dst_fsp->file_id);
2324 if (same_file &&
2325 sys_io_ranges_overlap(state->remaining,
2326 state->src_off,
2327 state->remaining,
2328 state->dst_off))
2330 if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
2331 return NT_STATUS_INVALID_PARAMETER;
2333 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2336 if (fsp_is_alternate_stream(state->src_fsp) ||
2337 fsp_is_alternate_stream(state->dst_fsp))
2339 if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
2340 return NT_STATUS_NOT_SUPPORTED;
2342 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2345 if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
2346 int ret;
2348 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2349 if (!ok) {
2350 return NT_STATUS_INTERNAL_ERROR;
2353 ret = copy_reflink(fsp_get_io_fd(state->src_fsp),
2354 state->src_off,
2355 fsp_get_io_fd(state->dst_fsp),
2356 state->dst_off,
2357 state->to_copy);
2358 if (ret == -1) {
2359 DBG_INFO("copy_reflink() failed: %s\n", strerror(errno));
2360 return map_nt_error_from_unix(errno);
2363 state->copied = state->to_copy;
2364 goto done;
2367 if (!try_copy_file_range) {
2368 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2371 init_strict_lock_struct(state->src_fsp,
2372 state->src_fsp->op->global->open_persistent_id,
2373 state->src_off,
2374 state->remaining,
2375 READ_LOCK,
2376 lp_posix_cifsu_locktype(state->src_fsp),
2377 &lck);
2379 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2380 state->src_fsp,
2381 &lck);
2382 if (!ok) {
2383 return NT_STATUS_FILE_LOCK_CONFLICT;
2386 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2387 if (!ok) {
2388 return NT_STATUS_INTERNAL_ERROR;
2391 init_strict_lock_struct(state->dst_fsp,
2392 state->dst_fsp->op->global->open_persistent_id,
2393 state->dst_off,
2394 state->remaining,
2395 WRITE_LOCK,
2396 lp_posix_cifsu_locktype(state->dst_fsp),
2397 &lck);
2399 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2400 state->dst_fsp,
2401 &lck);
2402 if (!ok) {
2403 return NT_STATUS_FILE_LOCK_CONFLICT;
2406 while (state->remaining > 0) {
2407 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2408 &state->src_off,
2409 fsp_get_io_fd(state->dst_fsp),
2410 &state->dst_off,
2411 state->remaining,
2413 if (nwritten == -1) {
2414 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2415 "n [%jd] failed: %s\n",
2416 fsp_str_dbg(state->src_fsp),
2417 (intmax_t)state->src_off,
2418 fsp_str_dbg(state->dst_fsp),
2419 (intmax_t)state->dst_off,
2420 (intmax_t)state->remaining,
2421 strerror(errno));
2422 switch (errno) {
2423 case EOPNOTSUPP:
2424 case ENOSYS:
2425 try_copy_file_range = false;
2426 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2427 break;
2428 case EXDEV:
2429 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2430 break;
2431 default:
2432 status = map_nt_error_from_unix(errno);
2433 if (NT_STATUS_EQUAL(
2434 status,
2435 NT_STATUS_MORE_PROCESSING_REQUIRED))
2437 /* Avoid triggering the fallback */
2438 status = NT_STATUS_INTERNAL_ERROR;
2440 break;
2442 return status;
2445 if (state->remaining < nwritten) {
2446 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2447 "n [%jd] remaining [%jd]\n",
2448 fsp_str_dbg(state->src_fsp),
2449 fsp_str_dbg(state->dst_fsp),
2450 (intmax_t)nwritten,
2451 (intmax_t)state->remaining);
2452 return NT_STATUS_INTERNAL_ERROR;
2455 if (nwritten == 0) {
2456 break;
2458 state->copied += nwritten;
2459 state->remaining -= nwritten;
2462 done:
2464 * Tell the req cleanup function there's no need to call
2465 * change_to_user_and_service_by_fsp() on the dst handle.
2467 state->dst_fsp = NULL;
2468 return NT_STATUS_OK;
2471 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2473 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2475 struct vfswrap_offload_write_state *state = tevent_req_data(
2476 req, struct vfswrap_offload_write_state);
2477 struct tevent_req *subreq = NULL;
2478 struct lock_struct read_lck;
2479 bool ok;
2482 * This is called under the context of state->src_fsp.
2485 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2487 init_strict_lock_struct(state->src_fsp,
2488 state->src_fsp->op->global->open_persistent_id,
2489 state->src_off,
2490 state->next_io_size,
2491 READ_LOCK,
2492 lp_posix_cifsu_locktype(state->src_fsp),
2493 &read_lck);
2495 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2496 state->src_fsp,
2497 &read_lck);
2498 if (!ok) {
2499 return NT_STATUS_FILE_LOCK_CONFLICT;
2502 subreq = SMB_VFS_PREAD_SEND(state,
2503 state->src_ev,
2504 state->src_fsp,
2505 state->buf,
2506 state->next_io_size,
2507 state->src_off);
2508 if (subreq == NULL) {
2509 return NT_STATUS_NO_MEMORY;
2511 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2513 return NT_STATUS_OK;
2516 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2518 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2520 struct tevent_req *req = tevent_req_callback_data(
2521 subreq, struct tevent_req);
2522 struct vfswrap_offload_write_state *state = tevent_req_data(
2523 req, struct vfswrap_offload_write_state);
2524 struct vfs_aio_state aio_state;
2525 struct lock_struct write_lck;
2526 ssize_t nread;
2527 bool ok;
2529 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2530 TALLOC_FREE(subreq);
2531 if (nread == -1) {
2532 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2533 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2534 return;
2536 if (nread != state->next_io_size) {
2537 DBG_ERR("Short read, only %zd of %zu\n",
2538 nread, state->next_io_size);
2539 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2540 return;
2543 state->src_off += nread;
2545 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2546 if (!ok) {
2547 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2548 return;
2551 init_strict_lock_struct(state->dst_fsp,
2552 state->dst_fsp->op->global->open_persistent_id,
2553 state->dst_off,
2554 state->next_io_size,
2555 WRITE_LOCK,
2556 lp_posix_cifsu_locktype(state->dst_fsp),
2557 &write_lck);
2559 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2560 state->dst_fsp,
2561 &write_lck);
2562 if (!ok) {
2563 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2564 return;
2567 subreq = SMB_VFS_PWRITE_SEND(state,
2568 state->dst_ev,
2569 state->dst_fsp,
2570 state->buf,
2571 state->next_io_size,
2572 state->dst_off);
2573 if (subreq == NULL) {
2574 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2575 return;
2577 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2580 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2582 struct tevent_req *req = tevent_req_callback_data(
2583 subreq, struct tevent_req);
2584 struct vfswrap_offload_write_state *state = tevent_req_data(
2585 req, struct vfswrap_offload_write_state);
2586 struct vfs_aio_state aio_state;
2587 ssize_t nwritten;
2588 NTSTATUS status;
2589 bool ok;
2591 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2592 TALLOC_FREE(subreq);
2593 if (nwritten == -1) {
2594 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2595 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2596 return;
2598 if (nwritten != state->next_io_size) {
2599 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2600 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2601 return;
2604 state->dst_off += nwritten;
2606 if (state->remaining < nwritten) {
2607 /* Paranoia check */
2608 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2609 return;
2611 state->copied += nwritten;
2612 state->remaining -= nwritten;
2613 if (state->remaining == 0) {
2614 tevent_req_done(req);
2615 return;
2618 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2619 if (!ok) {
2620 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2621 return;
2624 status = vfswrap_offload_write_loop(req);
2625 if (!NT_STATUS_IS_OK(status)) {
2626 tevent_req_nterror(req, status);
2627 return;
2630 return;
2633 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2634 struct tevent_req *req,
2635 off_t *copied)
2637 struct vfswrap_offload_write_state *state = tevent_req_data(
2638 req, struct vfswrap_offload_write_state);
2639 NTSTATUS status;
2641 if (tevent_req_is_nterror(req, &status)) {
2642 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2643 *copied = 0;
2644 tevent_req_received(req);
2645 return status;
2648 *copied = state->copied;
2649 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2650 tevent_req_received(req);
2652 return NT_STATUS_OK;
2655 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2656 TALLOC_CTX *mem_ctx,
2657 struct files_struct *fsp,
2658 uint16_t *_compression_fmt)
2660 return NT_STATUS_INVALID_DEVICE_REQUEST;
2663 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2664 TALLOC_CTX *mem_ctx,
2665 struct files_struct *fsp,
2666 uint16_t compression_fmt)
2668 return NT_STATUS_INVALID_DEVICE_REQUEST;
2671 /********************************************************************
2672 Given a stat buffer return the allocated size on disk, taking into
2673 account sparse files.
2674 ********************************************************************/
2675 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2676 struct files_struct *fsp,
2677 const SMB_STRUCT_STAT *sbuf)
2679 uint64_t result;
2681 START_PROFILE(syscall_get_alloc_size);
2683 if(S_ISDIR(sbuf->st_ex_mode)) {
2684 result = 0;
2685 goto out;
2688 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2689 /* The type of st_blocksize is blkcnt_t which *MUST* be
2690 signed (according to POSIX) and can be less than 64-bits.
2691 Ensure when we're converting to 64 bits wide we don't
2692 sign extend. */
2693 #if defined(SIZEOF_BLKCNT_T_8)
2694 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2695 #elif defined(SIZEOF_BLKCNT_T_4)
2697 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2698 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2700 #else
2701 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2702 #endif
2703 if (result == 0) {
2705 * Some file systems do not allocate a block for very
2706 * small files. But for non-empty file should report a
2707 * positive size.
2710 uint64_t filesize = get_file_size_stat(sbuf);
2711 if (filesize > 0) {
2712 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2715 #else
2716 result = get_file_size_stat(sbuf);
2717 #endif
2719 if (fsp && fsp->initial_allocation_size)
2720 result = MAX(result,fsp->initial_allocation_size);
2722 result = smb_roundup(handle->conn, result);
2724 out:
2725 END_PROFILE(syscall_get_alloc_size);
2726 return result;
2729 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2730 struct files_struct *dirfsp,
2731 const struct smb_filename *smb_fname,
2732 int flags)
2734 int result = -1;
2736 START_PROFILE(syscall_unlinkat);
2738 SMB_ASSERT(!is_named_stream(smb_fname));
2740 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2741 smb_fname->base_name,
2742 flags);
2744 END_PROFILE(syscall_unlinkat);
2745 return result;
2748 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2750 int result;
2752 START_PROFILE(syscall_fchmod);
2754 if (!fsp->fsp_flags.is_pathref) {
2755 result = fchmod(fsp_get_io_fd(fsp), mode);
2756 END_PROFILE(syscall_fchmod);
2757 return result;
2760 if (fsp->fsp_flags.have_proc_fds) {
2761 int fd = fsp_get_pathref_fd(fsp);
2762 struct sys_proc_fd_path_buf buf;
2764 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2766 END_PROFILE(syscall_fchmod);
2767 return result;
2771 * This is no longer a handle based call.
2773 result = chmod(fsp->fsp_name->base_name, mode);
2775 END_PROFILE(syscall_fchmod);
2776 return result;
2779 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2781 #ifdef HAVE_FCHOWN
2782 int result;
2784 START_PROFILE(syscall_fchown);
2785 if (!fsp->fsp_flags.is_pathref) {
2786 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2787 END_PROFILE(syscall_fchown);
2788 return result;
2791 if (fsp->fsp_flags.have_proc_fds) {
2792 int fd = fsp_get_pathref_fd(fsp);
2793 struct sys_proc_fd_path_buf buf;
2795 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2797 END_PROFILE(syscall_fchown);
2798 return result;
2802 * This is no longer a handle based call.
2804 result = chown(fsp->fsp_name->base_name, uid, gid);
2805 END_PROFILE(syscall_fchown);
2806 return result;
2807 #else
2808 errno = ENOSYS;
2809 return -1;
2810 #endif
2813 static int vfswrap_lchown(vfs_handle_struct *handle,
2814 const struct smb_filename *smb_fname,
2815 uid_t uid,
2816 gid_t gid)
2818 int result;
2820 START_PROFILE(syscall_lchown);
2821 result = lchown(smb_fname->base_name, uid, gid);
2822 END_PROFILE(syscall_lchown);
2823 return result;
2826 static int vfswrap_chdir(vfs_handle_struct *handle,
2827 const struct smb_filename *smb_fname)
2829 int result;
2831 START_PROFILE(syscall_chdir);
2832 result = chdir(smb_fname->base_name);
2833 END_PROFILE(syscall_chdir);
2834 return result;
2837 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2838 TALLOC_CTX *ctx)
2840 char *result;
2841 struct smb_filename *smb_fname = NULL;
2843 START_PROFILE(syscall_getwd);
2844 result = sys_getwd();
2845 END_PROFILE(syscall_getwd);
2847 if (result == NULL) {
2848 return NULL;
2850 smb_fname = synthetic_smb_fname(ctx,
2851 result,
2852 NULL,
2853 NULL,
2857 * sys_getwd() *always* returns malloced memory.
2858 * We must free here to avoid leaks:
2859 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2861 SAFE_FREE(result);
2862 return smb_fname;
2865 /*********************************************************************
2866 nsec timestamp resolution call. Convert down to whatever the underlying
2867 system will support.
2868 **********************************************************************/
2870 static int vfswrap_fntimes(vfs_handle_struct *handle,
2871 files_struct *fsp,
2872 struct smb_file_time *ft)
2874 int result = -1;
2875 struct timespec ts[2];
2876 struct timespec *times = NULL;
2878 START_PROFILE(syscall_fntimes);
2880 if (fsp_is_alternate_stream(fsp)) {
2881 errno = ENOENT;
2882 goto out;
2885 if (ft != NULL) {
2886 if (is_omit_timespec(&ft->atime)) {
2887 ft->atime = fsp->fsp_name->st.st_ex_atime;
2890 if (is_omit_timespec(&ft->mtime)) {
2891 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2894 if (!is_omit_timespec(&ft->create_time)) {
2895 set_create_timespec_ea(fsp,
2896 ft->create_time);
2899 if ((timespec_compare(&ft->atime,
2900 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2901 (timespec_compare(&ft->mtime,
2902 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2903 result = 0;
2904 goto out;
2907 ts[0] = ft->atime;
2908 ts[1] = ft->mtime;
2909 times = ts;
2910 } else {
2911 times = NULL;
2914 if (!fsp->fsp_flags.is_pathref) {
2915 result = futimens(fsp_get_io_fd(fsp), times);
2916 goto out;
2919 if (fsp->fsp_flags.have_proc_fds) {
2920 int fd = fsp_get_pathref_fd(fsp);
2921 struct sys_proc_fd_path_buf buf;
2923 result = utimensat(AT_FDCWD,
2924 sys_proc_fd_path(fd, &buf),
2925 times,
2928 goto out;
2932 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2933 * path translation mechanism. Fallback to path based call.
2935 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2937 out:
2938 END_PROFILE(syscall_fntimes);
2940 return result;
2944 /*********************************************************************
2945 A version of ftruncate that will write the space on disk if strict
2946 allocate is set.
2947 **********************************************************************/
2949 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2951 off_t space_to_write;
2952 uint64_t space_avail;
2953 uint64_t bsize,dfree,dsize;
2954 int ret;
2955 NTSTATUS status;
2956 SMB_STRUCT_STAT *pst;
2957 bool ok;
2959 ok = vfs_valid_pwrite_range(len, 0);
2960 if (!ok) {
2961 errno = EINVAL;
2962 return -1;
2965 status = vfs_stat_fsp(fsp);
2966 if (!NT_STATUS_IS_OK(status)) {
2967 return -1;
2969 pst = &fsp->fsp_name->st;
2971 #ifdef S_ISFIFO
2972 if (S_ISFIFO(pst->st_ex_mode))
2973 return 0;
2974 #endif
2976 if (pst->st_ex_size == len)
2977 return 0;
2979 /* Shrink - just ftruncate. */
2980 if (pst->st_ex_size > len)
2981 return ftruncate(fsp_get_io_fd(fsp), len);
2983 space_to_write = len - pst->st_ex_size;
2985 /* for allocation try fallocate first. This can fail on some
2986 platforms e.g. when the filesystem doesn't support it and no
2987 emulation is being done by the libc (like on AIX with JFS1). In that
2988 case we do our own emulation. fallocate implementations can
2989 return ENOTSUP or EINVAL in cases like that. */
2990 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2991 if (ret == -1 && errno == ENOSPC) {
2992 return -1;
2994 if (ret == 0) {
2995 return 0;
2997 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2998 "error %d. Falling back to slow manual allocation\n", errno);
3000 /* available disk space is enough or not? */
3001 space_avail =
3002 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
3003 /* space_avail is 1k blocks */
3004 if (space_avail == (uint64_t)-1 ||
3005 ((uint64_t)space_to_write/1024 > space_avail) ) {
3006 errno = ENOSPC;
3007 return -1;
3010 /* Write out the real space on disk. */
3011 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
3012 if (ret != 0) {
3013 return -1;
3016 return 0;
3019 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
3021 int result = -1;
3022 SMB_STRUCT_STAT *pst;
3023 NTSTATUS status;
3024 char c = 0;
3026 START_PROFILE(syscall_ftruncate);
3028 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
3029 result = strict_allocate_ftruncate(handle, fsp, len);
3030 END_PROFILE(syscall_ftruncate);
3031 return result;
3034 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
3035 ftruncate if the system supports it. Then I discovered that
3036 you can have some filesystems that support ftruncate
3037 expansion and some that don't! On Linux fat can't do
3038 ftruncate extend but ext2 can. */
3040 result = ftruncate(fsp_get_io_fd(fsp), len);
3042 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
3043 extend a file with ftruncate. Provide alternate implementation
3044 for this */
3046 /* Do an fstat to see if the file is longer than the requested
3047 size in which case the ftruncate above should have
3048 succeeded or shorter, in which case seek to len - 1 and
3049 write 1 byte of zero */
3050 status = vfs_stat_fsp(fsp);
3051 if (!NT_STATUS_IS_OK(status)) {
3052 goto done;
3055 /* We need to update the files_struct after successful ftruncate */
3056 if (result == 0) {
3057 goto done;
3060 pst = &fsp->fsp_name->st;
3062 #ifdef S_ISFIFO
3063 if (S_ISFIFO(pst->st_ex_mode)) {
3064 result = 0;
3065 goto done;
3067 #endif
3069 if (pst->st_ex_size == len) {
3070 result = 0;
3071 goto done;
3074 if (pst->st_ex_size > len) {
3075 /* the ftruncate should have worked */
3076 goto done;
3079 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3080 goto done;
3083 result = 0;
3085 done:
3087 END_PROFILE(syscall_ftruncate);
3088 return result;
3091 static int vfswrap_fallocate(vfs_handle_struct *handle,
3092 files_struct *fsp,
3093 uint32_t mode,
3094 off_t offset,
3095 off_t len)
3097 int result;
3099 START_PROFILE(syscall_fallocate);
3100 if (mode == 0) {
3101 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3103 * posix_fallocate returns 0 on success, errno on error
3104 * and doesn't set errno. Make it behave like fallocate()
3105 * which returns -1, and sets errno on failure.
3107 if (result != 0) {
3108 errno = result;
3109 result = -1;
3111 } else {
3112 /* sys_fallocate handles filtering of unsupported mode flags */
3113 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3115 END_PROFILE(syscall_fallocate);
3116 return result;
3119 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3121 bool result;
3123 START_PROFILE(syscall_fcntl_lock);
3125 if (fsp->fsp_flags.use_ofd_locks) {
3126 op = map_process_lock_to_ofd_lock(op);
3129 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3130 END_PROFILE(syscall_fcntl_lock);
3131 return result;
3134 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3135 files_struct *fsp,
3136 uint32_t share_access,
3137 uint32_t access_mask)
3139 errno = ENOTSUP;
3140 return -1;
3143 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3144 va_list cmd_arg)
3146 void *argp;
3147 va_list dup_cmd_arg;
3148 int result;
3149 int val;
3151 START_PROFILE(syscall_fcntl);
3153 va_copy(dup_cmd_arg, cmd_arg);
3155 switch(cmd) {
3156 case F_SETLK:
3157 case F_SETLKW:
3158 case F_GETLK:
3159 #if defined(HAVE_OFD_LOCKS)
3160 case F_OFD_SETLK:
3161 case F_OFD_SETLKW:
3162 case F_OFD_GETLK:
3163 #endif
3164 #if defined(HAVE_F_OWNER_EX)
3165 case F_GETOWN_EX:
3166 case F_SETOWN_EX:
3167 #endif
3168 #if defined(HAVE_RW_HINTS)
3169 case F_GET_RW_HINT:
3170 case F_SET_RW_HINT:
3171 case F_GET_FILE_RW_HINT:
3172 case F_SET_FILE_RW_HINT:
3173 #endif
3174 argp = va_arg(dup_cmd_arg, void *);
3175 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3176 break;
3177 default:
3178 val = va_arg(dup_cmd_arg, int);
3179 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3182 va_end(dup_cmd_arg);
3184 END_PROFILE(syscall_fcntl);
3185 return result;
3188 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3190 bool result;
3191 int op = F_GETLK;
3193 START_PROFILE(syscall_fcntl_getlock);
3195 if (fsp->fsp_flags.use_ofd_locks) {
3196 op = map_process_lock_to_ofd_lock(op);
3199 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3200 END_PROFILE(syscall_fcntl_getlock);
3201 return result;
3204 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3205 int leasetype)
3207 int result = -1;
3209 START_PROFILE(syscall_linux_setlease);
3211 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3213 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3214 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3215 #else
3216 errno = ENOSYS;
3217 #endif
3218 END_PROFILE(syscall_linux_setlease);
3219 return result;
3222 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3223 const struct smb_filename *link_target,
3224 struct files_struct *dirfsp,
3225 const struct smb_filename *new_smb_fname)
3227 int result;
3229 START_PROFILE(syscall_symlinkat);
3231 SMB_ASSERT(!is_named_stream(new_smb_fname));
3233 result = symlinkat(link_target->base_name,
3234 fsp_get_pathref_fd(dirfsp),
3235 new_smb_fname->base_name);
3236 END_PROFILE(syscall_symlinkat);
3237 return result;
3240 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3241 const struct files_struct *dirfsp,
3242 const struct smb_filename *smb_fname,
3243 char *buf,
3244 size_t bufsiz)
3246 int result;
3248 START_PROFILE(syscall_readlinkat);
3250 SMB_ASSERT(!is_named_stream(smb_fname));
3252 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3253 smb_fname->base_name,
3254 buf,
3255 bufsiz);
3257 END_PROFILE(syscall_readlinkat);
3258 return result;
3261 static int vfswrap_linkat(vfs_handle_struct *handle,
3262 files_struct *srcfsp,
3263 const struct smb_filename *old_smb_fname,
3264 files_struct *dstfsp,
3265 const struct smb_filename *new_smb_fname,
3266 int flags)
3268 int result;
3270 START_PROFILE(syscall_linkat);
3272 SMB_ASSERT(!is_named_stream(old_smb_fname));
3273 SMB_ASSERT(!is_named_stream(new_smb_fname));
3275 result = linkat(fsp_get_pathref_fd(srcfsp),
3276 old_smb_fname->base_name,
3277 fsp_get_pathref_fd(dstfsp),
3278 new_smb_fname->base_name,
3279 flags);
3281 END_PROFILE(syscall_linkat);
3282 return result;
3285 static int vfswrap_mknodat(vfs_handle_struct *handle,
3286 files_struct *dirfsp,
3287 const struct smb_filename *smb_fname,
3288 mode_t mode,
3289 SMB_DEV_T dev)
3291 int result;
3293 START_PROFILE(syscall_mknodat);
3295 SMB_ASSERT(!is_named_stream(smb_fname));
3297 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3298 smb_fname->base_name,
3299 mode,
3300 dev);
3302 END_PROFILE(syscall_mknodat);
3303 return result;
3306 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3307 TALLOC_CTX *ctx,
3308 const struct smb_filename *smb_fname)
3310 char *result;
3311 struct smb_filename *result_fname = NULL;
3313 START_PROFILE(syscall_realpath);
3314 result = sys_realpath(smb_fname->base_name);
3315 END_PROFILE(syscall_realpath);
3316 if (result) {
3317 result_fname = synthetic_smb_fname(ctx,
3318 result,
3319 NULL,
3320 NULL,
3323 SAFE_FREE(result);
3325 return result_fname;
3328 static int vfswrap_fchflags(vfs_handle_struct *handle,
3329 struct files_struct *fsp,
3330 unsigned int flags)
3332 #ifdef HAVE_FCHFLAGS
3333 int fd = fsp_get_pathref_fd(fsp);
3335 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3337 if (!fsp->fsp_flags.is_pathref) {
3338 return fchflags(fd, flags);
3341 if (fsp->fsp_flags.have_proc_fds) {
3342 struct sys_proc_fd_path_buf buf;
3344 return chflags(sys_proc_fd_path(fd, &buf), flags);
3348 * This is no longer a handle based call.
3350 return chflags(fsp->fsp_name->base_name, flags);
3351 #else
3352 errno = ENOSYS;
3353 return -1;
3354 #endif
3357 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3358 const SMB_STRUCT_STAT *sbuf)
3360 struct file_id key;
3362 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3363 * blob */
3364 ZERO_STRUCT(key);
3366 key.devid = sbuf->st_ex_dev;
3367 key.inode = sbuf->st_ex_ino;
3368 /* key.extid is unused by default. */
3370 return key;
3373 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3374 const SMB_STRUCT_STAT *psbuf)
3376 uint64_t file_id;
3378 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3379 return (uint64_t)psbuf->st_ex_ino;
3382 /* FileIDLow */
3383 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3385 /* FileIDHigh */
3386 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3388 return file_id;
3391 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3392 struct files_struct *fsp,
3393 TALLOC_CTX *mem_ctx,
3394 unsigned int *pnum_streams,
3395 struct stream_struct **pstreams)
3397 struct stream_struct *tmp_streams = NULL;
3398 unsigned int num_streams = *pnum_streams;
3399 struct stream_struct *streams = *pstreams;
3400 NTSTATUS status;
3402 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3404 if (fsp->fsp_flags.is_directory) {
3406 * No default streams on directories
3408 goto done;
3410 status = vfs_stat_fsp(fsp);
3411 if (!NT_STATUS_IS_OK(status)) {
3412 return status;
3415 if (num_streams + 1 < 1) {
3416 /* Integer wrap. */
3417 return NT_STATUS_INVALID_PARAMETER;
3420 tmp_streams = talloc_realloc(mem_ctx,
3421 streams,
3422 struct stream_struct,
3423 num_streams + 1);
3424 if (tmp_streams == NULL) {
3425 return NT_STATUS_NO_MEMORY;
3427 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3428 if (tmp_streams[num_streams].name == NULL) {
3429 return NT_STATUS_NO_MEMORY;
3431 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3432 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3433 handle->conn,
3434 fsp,
3435 &fsp->fsp_name->st);
3436 num_streams += 1;
3438 *pnum_streams = num_streams;
3439 *pstreams = tmp_streams;
3440 done:
3441 return NT_STATUS_OK;
3444 static NTSTATUS vfswrap_get_real_filename_at(
3445 struct vfs_handle_struct *handle,
3446 struct files_struct *dirfsp,
3447 const char *name,
3448 TALLOC_CTX *mem_ctx,
3449 char **found_name)
3452 * Don't fall back to get_real_filename so callers can differentiate
3453 * between a full directory scan and an actual case-insensitive stat.
3455 return NT_STATUS_NOT_SUPPORTED;
3458 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3459 const struct files_struct *dirfsp,
3460 const struct smb_filename *smb_fname)
3462 return handle->conn->connectpath;
3465 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3466 struct byte_range_lock *br_lck,
3467 struct lock_struct *plock)
3469 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3471 /* Note: blr is not used in the default implementation. */
3472 return brl_lock_windows_default(br_lck, plock);
3475 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3476 struct byte_range_lock *br_lck,
3477 const struct lock_struct *plock)
3479 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3481 return brl_unlock_windows_default(br_lck, plock);
3484 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3485 files_struct *fsp,
3486 struct lock_struct *plock)
3488 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3489 plock->lock_type == WRITE_LOCK);
3491 return strict_lock_check_default(fsp, plock);
3494 /* NT ACL operations. */
3496 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3497 files_struct *fsp,
3498 uint32_t security_info,
3499 TALLOC_CTX *mem_ctx,
3500 struct security_descriptor **ppdesc)
3502 NTSTATUS result;
3504 START_PROFILE(fget_nt_acl);
3506 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3508 result = posix_fget_nt_acl(fsp, security_info,
3509 mem_ctx, ppdesc);
3510 END_PROFILE(fget_nt_acl);
3511 return result;
3514 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3516 NTSTATUS result;
3518 START_PROFILE(fset_nt_acl);
3520 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3522 result = set_nt_acl(fsp, security_info_sent, psd);
3523 END_PROFILE(fset_nt_acl);
3524 return result;
3527 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3528 struct smb_filename *file,
3529 struct security_acl *sacl,
3530 uint32_t access_requested,
3531 uint32_t access_denied)
3533 return NT_STATUS_OK; /* Nothing to do here ... */
3536 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3537 files_struct *fsp,
3538 SMB_ACL_TYPE_T type,
3539 TALLOC_CTX *mem_ctx)
3541 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3543 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3546 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3547 files_struct *fsp,
3548 SMB_ACL_TYPE_T type,
3549 SMB_ACL_T theacl)
3551 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3553 return sys_acl_set_fd(handle, fsp, type, theacl);
3556 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3557 files_struct *fsp)
3559 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3561 return sys_acl_delete_def_fd(handle, fsp);
3564 /****************************************************************
3565 Extended attribute operations.
3566 *****************************************************************/
3568 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3569 struct files_struct *fsp,
3570 const char *name,
3571 void *value,
3572 size_t size)
3574 int fd = fsp_get_pathref_fd(fsp);
3576 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3578 if (!fsp->fsp_flags.is_pathref) {
3579 return fgetxattr(fd, name, value, size);
3582 if (fsp->fsp_flags.have_proc_fds) {
3583 struct sys_proc_fd_path_buf buf;
3585 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3589 * This is no longer a handle based call.
3591 return getxattr(fsp->fsp_name->base_name, name, value, size);
3594 struct vfswrap_getxattrat_state {
3595 struct tevent_context *ev;
3596 struct vfs_handle_struct *handle;
3597 files_struct *dir_fsp;
3598 const struct smb_filename *smb_fname;
3601 * The following variables are talloced off "state" which is protected
3602 * by a destructor and thus are guaranteed to be safe to be used in the
3603 * job function in the worker thread.
3605 char *name;
3606 const char *xattr_name;
3607 uint8_t *xattr_value;
3608 struct security_unix_token *token;
3610 ssize_t xattr_size;
3611 struct vfs_aio_state vfs_aio_state;
3612 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3615 static int vfswrap_getxattrat_state_destructor(
3616 struct vfswrap_getxattrat_state *state)
3618 return -1;
3621 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3622 static void vfswrap_getxattrat_do_async(void *private_data);
3623 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3625 static struct tevent_req *vfswrap_getxattrat_send(
3626 TALLOC_CTX *mem_ctx,
3627 struct tevent_context *ev,
3628 struct vfs_handle_struct *handle,
3629 files_struct *dir_fsp,
3630 const struct smb_filename *smb_fname,
3631 const char *xattr_name,
3632 size_t alloc_hint)
3634 struct tevent_req *req = NULL;
3635 struct tevent_req *subreq = NULL;
3636 struct vfswrap_getxattrat_state *state = NULL;
3637 size_t max_threads = 0;
3638 bool have_per_thread_cwd = false;
3639 bool have_per_thread_creds = false;
3640 bool do_async = false;
3642 SMB_ASSERT(!is_named_stream(smb_fname));
3644 req = tevent_req_create(mem_ctx, &state,
3645 struct vfswrap_getxattrat_state);
3646 if (req == NULL) {
3647 return NULL;
3649 *state = (struct vfswrap_getxattrat_state) {
3650 .ev = ev,
3651 .handle = handle,
3652 .dir_fsp = dir_fsp,
3653 .smb_fname = smb_fname,
3656 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3657 if (max_threads >= 1) {
3659 * We need a non sync threadpool!
3661 have_per_thread_cwd = per_thread_cwd_supported();
3663 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3664 have_per_thread_creds = true;
3665 #endif
3666 if (have_per_thread_cwd && have_per_thread_creds) {
3667 do_async = true;
3670 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3671 state->profile_bytes, 0);
3673 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3674 DBG_ERR("Need a valid directory fd\n");
3675 tevent_req_error(req, EINVAL);
3676 return tevent_req_post(req, ev);
3679 if (alloc_hint > 0) {
3680 state->xattr_value = talloc_zero_array(state,
3681 uint8_t,
3682 alloc_hint);
3683 if (tevent_req_nomem(state->xattr_value, req)) {
3684 return tevent_req_post(req, ev);
3688 if (!do_async) {
3689 vfswrap_getxattrat_do_sync(req);
3690 return tevent_req_post(req, ev);
3694 * Now allocate all parameters from a memory context that won't go away
3695 * no matter what. These parameters will get used in threads and we
3696 * can't reliably cancel threads, so all buffers passed to the threads
3697 * must not be freed before all referencing threads terminate.
3700 state->name = talloc_strdup(state, smb_fname->base_name);
3701 if (tevent_req_nomem(state->name, req)) {
3702 return tevent_req_post(req, ev);
3705 state->xattr_name = talloc_strdup(state, xattr_name);
3706 if (tevent_req_nomem(state->xattr_name, req)) {
3707 return tevent_req_post(req, ev);
3711 * This is a hot codepath so at first glance one might think we should
3712 * somehow optimize away the token allocation and do a
3713 * talloc_reference() or similar black magic instead. But due to the
3714 * talloc_stackframe pool per SMB2 request this should be a simple copy
3715 * without a malloc in most cases.
3717 if (geteuid() == sec_initial_uid()) {
3718 state->token = root_unix_token(state);
3719 } else {
3720 state->token = copy_unix_token(
3721 state,
3722 dir_fsp->conn->session_info->unix_token);
3724 if (tevent_req_nomem(state->token, req)) {
3725 return tevent_req_post(req, ev);
3728 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3730 subreq = pthreadpool_tevent_job_send(
3731 state,
3733 dir_fsp->conn->sconn->pool,
3734 vfswrap_getxattrat_do_async,
3735 state);
3736 if (tevent_req_nomem(subreq, req)) {
3737 return tevent_req_post(req, ev);
3739 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3741 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3743 return req;
3746 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3748 struct vfswrap_getxattrat_state *state = tevent_req_data(
3749 req, struct vfswrap_getxattrat_state);
3751 state->xattr_size = vfswrap_fgetxattr(state->handle,
3752 state->smb_fname->fsp,
3753 state->xattr_name,
3754 state->xattr_value,
3755 talloc_array_length(state->xattr_value));
3756 if (state->xattr_size == -1) {
3757 tevent_req_error(req, errno);
3758 return;
3761 tevent_req_done(req);
3762 return;
3765 static void vfswrap_getxattrat_do_async(void *private_data)
3767 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3768 private_data, struct vfswrap_getxattrat_state);
3769 struct timespec start_time;
3770 struct timespec end_time;
3771 int ret;
3773 PROFILE_TIMESTAMP(&start_time);
3774 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3777 * Here we simulate a getxattrat()
3778 * call using fchdir();getxattr()
3781 per_thread_cwd_activate();
3783 /* Become the correct credential on this thread. */
3784 ret = set_thread_credentials(state->token->uid,
3785 state->token->gid,
3786 (size_t)state->token->ngroups,
3787 state->token->groups);
3788 if (ret != 0) {
3789 state->xattr_size = -1;
3790 state->vfs_aio_state.error = errno;
3791 goto end_profile;
3794 state->xattr_size = vfswrap_fgetxattr(state->handle,
3795 state->smb_fname->fsp,
3796 state->xattr_name,
3797 state->xattr_value,
3798 talloc_array_length(state->xattr_value));
3799 if (state->xattr_size == -1) {
3800 state->vfs_aio_state.error = errno;
3803 end_profile:
3804 PROFILE_TIMESTAMP(&end_time);
3805 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3806 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3809 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3811 struct tevent_req *req = tevent_req_callback_data(
3812 subreq, struct tevent_req);
3813 struct vfswrap_getxattrat_state *state = tevent_req_data(
3814 req, struct vfswrap_getxattrat_state);
3815 int ret;
3816 bool ok;
3819 * Make sure we run as the user again
3821 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3822 SMB_ASSERT(ok);
3824 ret = pthreadpool_tevent_job_recv(subreq);
3825 TALLOC_FREE(subreq);
3826 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3827 talloc_set_destructor(state, NULL);
3828 if (ret != 0) {
3829 if (ret != EAGAIN) {
3830 tevent_req_error(req, ret);
3831 return;
3834 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3835 * means the lower level pthreadpool failed to create a new
3836 * thread. Fallback to sync processing in that case to allow
3837 * some progress for the client.
3839 vfswrap_getxattrat_do_sync(req);
3840 return;
3843 if (state->xattr_size == -1) {
3844 tevent_req_error(req, state->vfs_aio_state.error);
3845 return;
3848 if (state->xattr_value == NULL) {
3850 * The caller only wanted the size.
3852 tevent_req_done(req);
3853 return;
3857 * shrink the buffer to the returned size.
3858 * (can't fail). It means NULL if size is 0.
3860 state->xattr_value = talloc_realloc(state,
3861 state->xattr_value,
3862 uint8_t,
3863 state->xattr_size);
3865 tevent_req_done(req);
3868 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3869 struct vfs_aio_state *aio_state,
3870 TALLOC_CTX *mem_ctx,
3871 uint8_t **xattr_value)
3873 struct vfswrap_getxattrat_state *state = tevent_req_data(
3874 req, struct vfswrap_getxattrat_state);
3875 ssize_t xattr_size;
3877 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3878 tevent_req_received(req);
3879 return -1;
3882 *aio_state = state->vfs_aio_state;
3883 xattr_size = state->xattr_size;
3884 if (xattr_value != NULL) {
3885 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3888 tevent_req_received(req);
3889 return xattr_size;
3892 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3894 int fd = fsp_get_pathref_fd(fsp);
3896 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3898 if (!fsp->fsp_flags.is_pathref) {
3899 return flistxattr(fd, list, size);
3902 if (fsp->fsp_flags.have_proc_fds) {
3903 struct sys_proc_fd_path_buf buf;
3905 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3909 * This is no longer a handle based call.
3911 return listxattr(fsp->fsp_name->base_name, list, size);
3914 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3916 int fd = fsp_get_pathref_fd(fsp);
3918 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3920 if (!fsp->fsp_flags.is_pathref) {
3921 return fremovexattr(fd, name);
3924 if (fsp->fsp_flags.have_proc_fds) {
3925 struct sys_proc_fd_path_buf buf;
3927 return removexattr(sys_proc_fd_path(fd, &buf), name);
3931 * This is no longer a handle based call.
3933 return removexattr(fsp->fsp_name->base_name, name);
3936 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3938 int fd = fsp_get_pathref_fd(fsp);
3940 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3942 if (!fsp->fsp_flags.is_pathref) {
3943 return fsetxattr(fd, name, value, size, flags);
3946 if (fsp->fsp_flags.have_proc_fds) {
3947 struct sys_proc_fd_path_buf buf;
3949 return setxattr(sys_proc_fd_path(fd, &buf),
3950 name,
3951 value,
3952 size,
3953 flags);
3957 * This is no longer a handle based call.
3959 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3962 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3964 return false;
3967 static bool vfswrap_is_offline(struct connection_struct *conn,
3968 const struct smb_filename *fname)
3970 NTSTATUS status;
3971 char *path;
3972 bool offline = false;
3974 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3975 return false;
3978 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3979 #if defined(ENOTSUP)
3980 errno = ENOTSUP;
3981 #endif
3982 return false;
3985 status = get_full_smb_filename(talloc_tos(), fname, &path);
3986 if (!NT_STATUS_IS_OK(status)) {
3987 errno = map_errno_from_nt_status(status);
3988 return false;
3991 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3993 TALLOC_FREE(path);
3995 return offline;
3998 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3999 struct files_struct *fsp,
4000 TALLOC_CTX *mem_ctx,
4001 DATA_BLOB *cookie)
4003 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
4006 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
4007 struct files_struct *fsp,
4008 const DATA_BLOB old_cookie,
4009 TALLOC_CTX *mem_ctx,
4010 DATA_BLOB *new_cookie)
4012 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
4013 new_cookie);
4016 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
4017 struct smb_request *smb1req,
4018 struct smbXsrv_open *op,
4019 const DATA_BLOB old_cookie,
4020 TALLOC_CTX *mem_ctx,
4021 struct files_struct **fsp,
4022 DATA_BLOB *new_cookie)
4024 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
4025 old_cookie, mem_ctx,
4026 fsp, new_cookie);
4029 static struct vfs_fn_pointers vfs_default_fns = {
4030 /* Disk operations */
4032 .connect_fn = vfswrap_connect,
4033 .disconnect_fn = vfswrap_disconnect,
4034 .disk_free_fn = vfswrap_disk_free,
4035 .get_quota_fn = vfswrap_get_quota,
4036 .set_quota_fn = vfswrap_set_quota,
4037 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
4038 .statvfs_fn = vfswrap_statvfs,
4039 .fs_capabilities_fn = vfswrap_fs_capabilities,
4040 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
4041 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
4042 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
4043 .snap_check_path_fn = vfswrap_snap_check_path,
4044 .snap_create_fn = vfswrap_snap_create,
4045 .snap_delete_fn = vfswrap_snap_delete,
4047 /* Directory operations */
4049 .fdopendir_fn = vfswrap_fdopendir,
4050 .readdir_fn = vfswrap_readdir,
4051 .freaddir_attr_fn = vfswrap_freaddir_attr,
4052 .rewind_dir_fn = vfswrap_rewinddir,
4053 .mkdirat_fn = vfswrap_mkdirat,
4054 .closedir_fn = vfswrap_closedir,
4056 /* File operations */
4058 .openat_fn = vfswrap_openat,
4059 .create_file_fn = vfswrap_create_file,
4060 .close_fn = vfswrap_close,
4061 .pread_fn = vfswrap_pread,
4062 .pread_send_fn = vfswrap_pread_send,
4063 .pread_recv_fn = vfswrap_pread_recv,
4064 .pwrite_fn = vfswrap_pwrite,
4065 .pwrite_send_fn = vfswrap_pwrite_send,
4066 .pwrite_recv_fn = vfswrap_pwrite_recv,
4067 .lseek_fn = vfswrap_lseek,
4068 .sendfile_fn = vfswrap_sendfile,
4069 .recvfile_fn = vfswrap_recvfile,
4070 .renameat_fn = vfswrap_renameat,
4071 .fsync_send_fn = vfswrap_fsync_send,
4072 .fsync_recv_fn = vfswrap_fsync_recv,
4073 .stat_fn = vfswrap_stat,
4074 .fstat_fn = vfswrap_fstat,
4075 .lstat_fn = vfswrap_lstat,
4076 .fstatat_fn = vfswrap_fstatat,
4077 .get_alloc_size_fn = vfswrap_get_alloc_size,
4078 .unlinkat_fn = vfswrap_unlinkat,
4079 .fchmod_fn = vfswrap_fchmod,
4080 .fchown_fn = vfswrap_fchown,
4081 .lchown_fn = vfswrap_lchown,
4082 .chdir_fn = vfswrap_chdir,
4083 .getwd_fn = vfswrap_getwd,
4084 .fntimes_fn = vfswrap_fntimes,
4085 .ftruncate_fn = vfswrap_ftruncate,
4086 .fallocate_fn = vfswrap_fallocate,
4087 .lock_fn = vfswrap_lock,
4088 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4089 .fcntl_fn = vfswrap_fcntl,
4090 .linux_setlease_fn = vfswrap_linux_setlease,
4091 .getlock_fn = vfswrap_getlock,
4092 .symlinkat_fn = vfswrap_symlinkat,
4093 .readlinkat_fn = vfswrap_readlinkat,
4094 .linkat_fn = vfswrap_linkat,
4095 .mknodat_fn = vfswrap_mknodat,
4096 .realpath_fn = vfswrap_realpath,
4097 .fchflags_fn = vfswrap_fchflags,
4098 .file_id_create_fn = vfswrap_file_id_create,
4099 .fs_file_id_fn = vfswrap_fs_file_id,
4100 .fstreaminfo_fn = vfswrap_fstreaminfo,
4101 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4102 .connectpath_fn = vfswrap_connectpath,
4103 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4104 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4105 .strict_lock_check_fn = vfswrap_strict_lock_check,
4106 .translate_name_fn = vfswrap_translate_name,
4107 .parent_pathname_fn = vfswrap_parent_pathname,
4108 .fsctl_fn = vfswrap_fsctl,
4109 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4110 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4111 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4112 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4113 .offload_read_send_fn = vfswrap_offload_read_send,
4114 .offload_read_recv_fn = vfswrap_offload_read_recv,
4115 .offload_write_send_fn = vfswrap_offload_write_send,
4116 .offload_write_recv_fn = vfswrap_offload_write_recv,
4117 .fget_compression_fn = vfswrap_fget_compression,
4118 .set_compression_fn = vfswrap_set_compression,
4120 /* NT ACL operations. */
4122 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4123 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4124 .audit_file_fn = vfswrap_audit_file,
4126 /* POSIX ACL operations. */
4128 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4129 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4130 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4131 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4133 /* EA operations. */
4134 .getxattrat_send_fn = vfswrap_getxattrat_send,
4135 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4136 .fgetxattr_fn = vfswrap_fgetxattr,
4137 .flistxattr_fn = vfswrap_flistxattr,
4138 .fremovexattr_fn = vfswrap_fremovexattr,
4139 .fsetxattr_fn = vfswrap_fsetxattr,
4141 /* aio operations */
4142 .aio_force_fn = vfswrap_aio_force,
4144 /* durable handle operations */
4145 .durable_cookie_fn = vfswrap_durable_cookie,
4146 .durable_disconnect_fn = vfswrap_durable_disconnect,
4147 .durable_reconnect_fn = vfswrap_durable_reconnect,
4150 static_decl_vfs;
4151 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4154 * Here we need to implement every call!
4156 * As this is the end of the vfs module chain.
4158 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4159 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4160 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);