s4:dsdb: Prefer explicit initialization to ZERO_STRUCT()
[Samba.git] / source3 / modules / vfs_default.c
blob1d4b9b1a8402f056d26153f50d5aecd59b2df401
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();
57 * assume the kernel will support openat2(),
58 * it will be reset on the first ENOSYS.
60 * Note that libreplace will always provide openat2(),
61 * but return -1/errno = ENOSYS...
63 * The option is only there to test the fallback code.
65 bval = lp_parm_bool(SNUM(handle->conn),
66 "vfs_default",
67 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
68 true);
69 if (bval) {
70 handle->conn->open_how_resolve |=
71 VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
74 return 0; /* Return >= 0 for success */
77 static void vfswrap_disconnect(vfs_handle_struct *handle)
81 /* Disk operations */
83 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
84 const struct smb_filename *smb_fname,
85 uint64_t *bsize,
86 uint64_t *dfree,
87 uint64_t *dsize)
89 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
90 return (uint64_t)-1;
93 *bsize = 512;
94 return *dfree / 2;
97 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
98 const struct smb_filename *smb_fname,
99 enum SMB_QUOTA_TYPE qtype,
100 unid_t id,
101 SMB_DISK_QUOTA *qt)
103 #ifdef HAVE_SYS_QUOTAS
104 int result;
106 START_PROFILE(syscall_get_quota);
107 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
108 END_PROFILE(syscall_get_quota);
109 return result;
110 #else
111 errno = ENOSYS;
112 return -1;
113 #endif
116 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
118 #ifdef HAVE_SYS_QUOTAS
119 int result;
121 START_PROFILE(syscall_set_quota);
122 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
123 END_PROFILE(syscall_set_quota);
124 return result;
125 #else
126 errno = ENOSYS;
127 return -1;
128 #endif
131 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
132 struct files_struct *fsp,
133 struct shadow_copy_data *shadow_copy_data,
134 bool labels)
136 errno = ENOSYS;
137 return -1; /* Not implemented. */
140 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
141 const struct smb_filename *smb_fname,
142 struct vfs_statvfs_struct *statbuf)
144 return sys_statvfs(smb_fname->base_name, statbuf);
147 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
148 enum timestamp_set_resolution *p_ts_res)
150 const struct loadparm_substitution *lp_sub =
151 loadparm_s3_global_substitution();
152 connection_struct *conn = handle->conn;
153 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
154 struct smb_filename *smb_fname_cpath = NULL;
155 struct vfs_statvfs_struct statbuf;
156 int ret;
158 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
159 conn->connectpath,
160 NULL,
161 NULL,
164 if (smb_fname_cpath == NULL) {
165 return caps;
168 ZERO_STRUCT(statbuf);
169 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
170 if (ret == 0) {
171 caps = statbuf.FsCapabilities;
174 *p_ts_res = TIMESTAMP_SET_SECONDS;
176 /* Work out what timestamp resolution we can
177 * use when setting a timestamp. */
179 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
180 if (ret == -1) {
181 TALLOC_FREE(smb_fname_cpath);
182 return caps;
185 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
186 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
187 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
188 /* If any of the normal UNIX directory timestamps
189 * have a non-zero tv_nsec component assume
190 * we might be able to set sub-second timestamps.
191 * See what filetime set primitives we have.
193 #if defined(HAVE_UTIMENSAT)
194 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
195 #elif defined(HAVE_UTIMES)
196 /* utimes allows msec timestamps to be set. */
197 *p_ts_res = TIMESTAMP_SET_MSEC;
198 #elif defined(HAVE_UTIME)
199 /* utime only allows sec timestamps to be set. */
200 *p_ts_res = TIMESTAMP_SET_SECONDS;
201 #endif
203 DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
204 "resolution of %s "
205 "available on share %s, directory %s\n",
206 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
207 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
208 conn->connectpath );
210 TALLOC_FREE(smb_fname_cpath);
211 return caps;
214 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
215 struct dfs_GetDFSReferral *r)
217 struct junction_map *junction = NULL;
218 size_t consumedcnt = 0;
219 bool self_referral = false;
220 char *pathnamep = NULL;
221 char *local_dfs_path = NULL;
222 NTSTATUS status;
223 size_t i;
224 uint16_t max_referral_level = r->in.req.max_referral_level;
226 if (DEBUGLVL(DBGLVL_DEBUG)) {
227 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
230 /* get the junction entry */
231 if (r->in.req.servername == NULL) {
232 return NT_STATUS_NOT_FOUND;
236 * Trim pathname sent by client so it begins with only one backslash.
237 * Two backslashes confuse some dfs clients
240 local_dfs_path = talloc_strdup(r, r->in.req.servername);
241 if (local_dfs_path == NULL) {
242 return NT_STATUS_NO_MEMORY;
244 pathnamep = local_dfs_path;
245 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
246 IS_DIRECTORY_SEP(pathnamep[1])) {
247 pathnamep++;
250 junction = talloc_zero(r, struct junction_map);
251 if (junction == NULL) {
252 return NT_STATUS_NO_MEMORY;
255 /* The following call can change cwd. */
256 status = get_referred_path(r,
257 handle->conn->session_info,
258 pathnamep,
259 handle->conn->sconn->remote_address,
260 handle->conn->sconn->local_address,
261 junction, &consumedcnt, &self_referral);
262 if (!NT_STATUS_IS_OK(status)) {
263 struct smb_filename connectpath_fname = {
264 .base_name = handle->conn->connectpath
266 vfs_ChDir(handle->conn, &connectpath_fname);
267 return status;
270 struct smb_filename connectpath_fname = {
271 .base_name = handle->conn->connectpath
273 vfs_ChDir(handle->conn, &connectpath_fname);
276 if (!self_referral) {
277 pathnamep[consumedcnt] = '\0';
279 if (DEBUGLVL(DBGLVL_INFO)) {
280 dbgtext("Path %s to alternate path(s):",
281 pathnamep);
282 for (i=0; i < junction->referral_count; i++) {
283 dbgtext(" %s",
284 junction->referral_list[i].alternate_path);
286 dbgtext(".\n");
290 if (r->in.req.max_referral_level <= 2) {
291 max_referral_level = 2;
293 if (r->in.req.max_referral_level >= 3) {
294 max_referral_level = 3;
297 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
298 if (r->out.resp == NULL) {
299 return NT_STATUS_NO_MEMORY;
302 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
303 r->out.resp->nb_referrals = junction->referral_count;
305 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
306 if (self_referral) {
307 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
310 r->out.resp->referral_entries = talloc_zero_array(r,
311 struct dfs_referral_type,
312 r->out.resp->nb_referrals);
313 if (r->out.resp->referral_entries == NULL) {
314 return NT_STATUS_NO_MEMORY;
317 switch (max_referral_level) {
318 case 2:
319 for(i=0; i < junction->referral_count; i++) {
320 struct referral *ref = &junction->referral_list[i];
321 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
322 struct dfs_referral_type *t =
323 &r->out.resp->referral_entries[i];
324 struct dfs_referral_v2 *v2 = &t->referral.v2;
326 t->version = 2;
327 v2->size = VERSION2_REFERRAL_SIZE;
328 if (self_referral) {
329 v2->server_type = DFS_SERVER_ROOT;
330 } else {
331 v2->server_type = DFS_SERVER_NON_ROOT;
333 v2->entry_flags = 0;
334 v2->proximity = ref->proximity;
335 v2->ttl = ref->ttl;
336 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
337 if (v2->DFS_path == NULL) {
338 return NT_STATUS_NO_MEMORY;
340 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
341 if (v2->DFS_alt_path == NULL) {
342 return NT_STATUS_NO_MEMORY;
344 v2->netw_address = talloc_strdup(mem_ctx,
345 ref->alternate_path);
346 if (v2->netw_address == NULL) {
347 return NT_STATUS_NO_MEMORY;
351 break;
352 case 3:
353 for(i=0; i < junction->referral_count; i++) {
354 struct referral *ref = &junction->referral_list[i];
355 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
356 struct dfs_referral_type *t =
357 &r->out.resp->referral_entries[i];
358 struct dfs_referral_v3 *v3 = &t->referral.v3;
359 struct dfs_normal_referral *r1 = &v3->referrals.r1;
361 t->version = 3;
362 v3->size = VERSION3_REFERRAL_SIZE;
363 if (self_referral) {
364 v3->server_type = DFS_SERVER_ROOT;
365 } else {
366 v3->server_type = DFS_SERVER_NON_ROOT;
368 v3->entry_flags = 0;
369 v3->ttl = ref->ttl;
370 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
371 if (r1->DFS_path == NULL) {
372 return NT_STATUS_NO_MEMORY;
374 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
375 if (r1->DFS_alt_path == NULL) {
376 return NT_STATUS_NO_MEMORY;
378 r1->netw_address = talloc_strdup(mem_ctx,
379 ref->alternate_path);
380 if (r1->netw_address == NULL) {
381 return NT_STATUS_NO_MEMORY;
384 break;
385 default:
386 DBG_ERR("Invalid dfs referral version: %d\n",
387 max_referral_level);
388 return NT_STATUS_INVALID_LEVEL;
391 if (DEBUGLVL(DBGLVL_DEBUG)) {
392 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
395 return NT_STATUS_OK;
398 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
399 struct files_struct *dirfsp,
400 const struct smb_filename *smb_fname,
401 const struct referral *reflist,
402 size_t referral_count)
404 TALLOC_CTX *frame = talloc_stackframe();
405 NTSTATUS status = NT_STATUS_NO_MEMORY;
406 int ret;
407 char *msdfs_link = NULL;
409 /* Form the msdfs_link contents */
410 msdfs_link = msdfs_link_string(frame,
411 reflist,
412 referral_count);
413 if (msdfs_link == NULL) {
414 goto out;
417 ret = symlinkat(msdfs_link,
418 fsp_get_pathref_fd(dirfsp),
419 smb_fname->base_name);
420 if (ret == 0) {
421 status = NT_STATUS_OK;
422 } else {
423 status = map_nt_error_from_unix(errno);
426 out:
428 TALLOC_FREE(frame);
429 return status;
433 * Read and return the contents of a DFS redirect given a
434 * pathname. A caller can pass in NULL for ppreflist and
435 * preferral_count but still determine if this was a
436 * DFS redirect point by getting NT_STATUS_OK back
437 * without incurring the overhead of reading and parsing
438 * the referral contents.
441 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
442 TALLOC_CTX *mem_ctx,
443 struct files_struct *dirfsp,
444 struct smb_filename *smb_fname,
445 struct referral **ppreflist,
446 size_t *preferral_count)
448 NTSTATUS status = NT_STATUS_NO_MEMORY;
449 size_t bufsize;
450 char *link_target = NULL;
451 int referral_len;
452 bool ok;
453 #if defined(HAVE_BROKEN_READLINK)
454 char link_target_buf[PATH_MAX];
455 #else
456 char link_target_buf[7];
457 #endif
458 int ret;
460 if (is_named_stream(smb_fname)) {
461 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
462 goto err;
465 if (ppreflist == NULL && preferral_count == NULL) {
467 * We're only checking if this is a DFS
468 * redirect. We don't need to return data.
470 bufsize = sizeof(link_target_buf);
471 link_target = link_target_buf;
472 } else {
473 bufsize = PATH_MAX;
474 link_target = talloc_array(mem_ctx, char, bufsize);
475 if (!link_target) {
476 goto err;
480 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
481 smb_fname->base_name,
482 link_target,
483 bufsize - 1);
484 if (referral_len == -1) {
485 if (errno == EINVAL) {
487 * If the path isn't a link, readlinkat
488 * returns EINVAL. Allow the caller to
489 * detect this.
491 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
492 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
493 } else {
494 status = map_nt_error_from_unix(errno);
495 if (errno == ENOENT) {
496 DBG_NOTICE("Error reading "
497 "msdfs link %s: %s\n",
498 smb_fname->base_name,
499 strerror(errno));
500 } else {
501 DBG_ERR("Error reading "
502 "msdfs link %s: %s\n",
503 smb_fname->base_name,
504 strerror(errno));
507 goto err;
509 link_target[referral_len] = '\0';
511 DBG_INFO("%s -> %s\n",
512 smb_fname->base_name,
513 link_target);
515 if (!strnequal(link_target, "msdfs:", 6)) {
516 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
517 goto err;
520 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
521 smb_fname->base_name,
522 &smb_fname->st,
523 AT_SYMLINK_NOFOLLOW,
524 lp_fake_directory_create_times(SNUM(handle->conn)));
525 if (ret < 0) {
526 status = map_nt_error_from_unix(errno);
527 goto err;
530 if (ppreflist == NULL && preferral_count == NULL) {
531 /* Early return for checking if this is a DFS link. */
532 return NT_STATUS_OK;
535 ok = parse_msdfs_symlink(mem_ctx,
536 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
537 link_target,
538 ppreflist,
539 preferral_count);
541 if (ok) {
542 status = NT_STATUS_OK;
543 } else {
544 status = NT_STATUS_NO_MEMORY;
547 err:
549 if (link_target != link_target_buf) {
550 TALLOC_FREE(link_target);
552 return status;
555 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
556 TALLOC_CTX *mem_ctx,
557 const char *service_path,
558 char **base_volume)
560 return NT_STATUS_NOT_SUPPORTED;
563 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
564 TALLOC_CTX *mem_ctx,
565 const char *base_volume,
566 time_t *tstamp,
567 bool rw,
568 char **base_path,
569 char **snap_path)
571 return NT_STATUS_NOT_SUPPORTED;
574 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
575 TALLOC_CTX *mem_ctx,
576 char *base_path,
577 char *snap_path)
579 return NT_STATUS_NOT_SUPPORTED;
582 /* Directory operations */
584 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
585 files_struct *fsp,
586 const char *mask,
587 uint32_t attr)
589 DIR *result;
591 START_PROFILE(syscall_fdopendir);
592 result = sys_fdopendir(fsp_get_io_fd(fsp));
593 END_PROFILE(syscall_fdopendir);
594 return result;
597 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
598 struct files_struct *dirfsp,
599 DIR *dirp)
601 struct dirent *result;
603 START_PROFILE(syscall_readdir);
605 result = readdir(dirp);
606 END_PROFILE(syscall_readdir);
608 return result;
611 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
612 struct files_struct *fsp,
613 TALLOC_CTX *mem_ctx,
614 struct readdir_attr_data **attr_data)
616 return NT_STATUS_NOT_SUPPORTED;
619 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
621 START_PROFILE(syscall_rewinddir);
622 rewinddir(dirp);
623 END_PROFILE(syscall_rewinddir);
626 static int vfswrap_mkdirat(vfs_handle_struct *handle,
627 struct files_struct *dirfsp,
628 const struct smb_filename *smb_fname,
629 mode_t mode)
631 int result;
633 START_PROFILE(syscall_mkdirat);
635 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
637 END_PROFILE(syscall_mkdirat);
638 return result;
641 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
643 int result;
645 START_PROFILE(syscall_closedir);
646 result = closedir(dirp);
647 END_PROFILE(syscall_closedir);
648 return result;
651 /* File operations */
653 static int vfswrap_openat(vfs_handle_struct *handle,
654 const struct files_struct *dirfsp,
655 const struct smb_filename *smb_fname,
656 files_struct *fsp,
657 const struct vfs_open_how *how)
659 int flags = how->flags;
660 mode_t mode = how->mode;
661 bool have_opath = false;
662 bool became_root = false;
663 int result;
665 START_PROFILE(syscall_openat);
667 if (how->resolve & ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
668 errno = ENOSYS;
669 result = -1;
670 goto out;
673 SMB_ASSERT(!is_named_stream(smb_fname));
675 #ifdef O_PATH
676 have_opath = true;
677 if (fsp->fsp_flags.is_pathref) {
678 flags |= O_PATH;
680 if (flags & O_PATH) {
682 * From "man 2 openat":
684 * When O_PATH is specified in flags, flag bits other than
685 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
687 * From "man 2 openat2":
689 * Whereas openat(2) ignores unknown bits in its flags
690 * argument, openat2() returns an error if unknown or
691 * conflicting flags are specified in how.flags.
693 * So we better clear ignored/invalid flags
694 * and only keep the expected ones.
696 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
698 #endif
700 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
701 struct open_how linux_how = {
702 .flags = flags,
703 .mode = mode,
704 .resolve = RESOLVE_NO_SYMLINKS,
707 result = openat2(fsp_get_pathref_fd(dirfsp),
708 smb_fname->base_name,
709 &linux_how,
710 sizeof(linux_how));
711 if (result == -1) {
712 if (errno == ENOSYS) {
714 * The kernel doesn't support
715 * openat2(), so indicate to
716 * the callers that
717 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
718 * would just be a waste of time.
720 fsp->conn->open_how_resolve &=
721 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
723 goto out;
726 goto done;
729 if (fsp->fsp_flags.is_pathref && !have_opath) {
730 become_root();
731 became_root = true;
734 result = openat(fsp_get_pathref_fd(dirfsp),
735 smb_fname->base_name,
736 flags,
737 mode);
739 if (became_root) {
740 unbecome_root();
743 done:
744 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
746 out:
747 END_PROFILE(syscall_openat);
748 return result;
750 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
751 struct smb_request *req,
752 struct files_struct *dirfsp,
753 struct smb_filename *smb_fname,
754 uint32_t access_mask,
755 uint32_t share_access,
756 uint32_t create_disposition,
757 uint32_t create_options,
758 uint32_t file_attributes,
759 uint32_t oplock_request,
760 const struct smb2_lease *lease,
761 uint64_t allocation_size,
762 uint32_t private_flags,
763 struct security_descriptor *sd,
764 struct ea_list *ea_list,
765 files_struct **result,
766 int *pinfo,
767 const struct smb2_create_blobs *in_context_blobs,
768 struct smb2_create_blobs *out_context_blobs)
770 return create_file_default(handle->conn, req, dirfsp, smb_fname,
771 access_mask, share_access,
772 create_disposition, create_options,
773 file_attributes, oplock_request, lease,
774 allocation_size, private_flags,
775 sd, ea_list, result,
776 pinfo, in_context_blobs, out_context_blobs);
779 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
781 int result;
783 START_PROFILE(syscall_close);
784 result = fd_close_posix(fsp);
785 END_PROFILE(syscall_close);
786 return result;
789 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
790 size_t n, off_t offset)
792 ssize_t result;
794 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
795 START_PROFILE_BYTES(syscall_pread, n);
796 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
797 END_PROFILE_BYTES(syscall_pread);
799 if (result == -1 && errno == ESPIPE) {
800 /* Maintain the fiction that pipes can be seeked (sought?) on. */
801 result = sys_read(fsp_get_io_fd(fsp), data, n);
802 fh_set_pos(fsp->fh, 0);
805 #else /* HAVE_PREAD */
806 errno = ENOSYS;
807 result = -1;
808 #endif /* HAVE_PREAD */
810 return result;
813 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
814 size_t n, off_t offset)
816 ssize_t result;
818 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
819 START_PROFILE_BYTES(syscall_pwrite, n);
820 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
821 END_PROFILE_BYTES(syscall_pwrite);
823 if (result == -1 && errno == ESPIPE) {
824 /* Maintain the fiction that pipes can be sought on. */
825 result = sys_write(fsp_get_io_fd(fsp), data, n);
828 #else /* HAVE_PWRITE */
829 errno = ENOSYS;
830 result = -1;
831 #endif /* HAVE_PWRITE */
833 return result;
836 struct vfswrap_pread_state {
837 ssize_t ret;
838 int fd;
839 void *buf;
840 size_t count;
841 off_t offset;
843 struct vfs_aio_state vfs_aio_state;
844 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
847 static void vfs_pread_do(void *private_data);
848 static void vfs_pread_done(struct tevent_req *subreq);
849 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
851 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
852 TALLOC_CTX *mem_ctx,
853 struct tevent_context *ev,
854 struct files_struct *fsp,
855 void *data,
856 size_t n, off_t offset)
858 struct tevent_req *req, *subreq;
859 struct vfswrap_pread_state *state;
861 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
862 if (req == NULL) {
863 return NULL;
866 state->ret = -1;
867 state->fd = fsp_get_io_fd(fsp);
868 state->buf = data;
869 state->count = n;
870 state->offset = offset;
872 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
873 state->profile_bytes, n);
874 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
876 subreq = pthreadpool_tevent_job_send(
877 state, ev, handle->conn->sconn->pool,
878 vfs_pread_do, state);
879 if (tevent_req_nomem(subreq, req)) {
880 return tevent_req_post(req, ev);
882 tevent_req_set_callback(subreq, vfs_pread_done, req);
884 talloc_set_destructor(state, vfs_pread_state_destructor);
886 return req;
889 static void vfs_pread_do(void *private_data)
891 struct vfswrap_pread_state *state = talloc_get_type_abort(
892 private_data, struct vfswrap_pread_state);
893 struct timespec start_time;
894 struct timespec end_time;
896 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
898 PROFILE_TIMESTAMP(&start_time);
900 state->ret = sys_pread_full(state->fd,
901 state->buf,
902 state->count,
903 state->offset);
905 if (state->ret == -1) {
906 state->vfs_aio_state.error = errno;
909 PROFILE_TIMESTAMP(&end_time);
911 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
913 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
916 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
918 return -1;
921 static void vfs_pread_done(struct tevent_req *subreq)
923 struct tevent_req *req = tevent_req_callback_data(
924 subreq, struct tevent_req);
925 struct vfswrap_pread_state *state = tevent_req_data(
926 req, struct vfswrap_pread_state);
927 int ret;
929 ret = pthreadpool_tevent_job_recv(subreq);
930 TALLOC_FREE(subreq);
931 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
932 talloc_set_destructor(state, NULL);
933 if (ret != 0) {
934 if (ret != EAGAIN) {
935 tevent_req_error(req, ret);
936 return;
939 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
940 * means the lower level pthreadpool failed to create a new
941 * thread. Fallback to sync processing in that case to allow
942 * some progress for the client.
944 vfs_pread_do(state);
947 tevent_req_done(req);
950 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
951 struct vfs_aio_state *vfs_aio_state)
953 struct vfswrap_pread_state *state = tevent_req_data(
954 req, struct vfswrap_pread_state);
956 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
957 return -1;
960 *vfs_aio_state = state->vfs_aio_state;
961 return state->ret;
964 struct vfswrap_pwrite_state {
965 ssize_t ret;
966 int fd;
967 const void *buf;
968 size_t count;
969 off_t offset;
971 struct vfs_aio_state vfs_aio_state;
972 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
975 static void vfs_pwrite_do(void *private_data);
976 static void vfs_pwrite_done(struct tevent_req *subreq);
977 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
979 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
980 TALLOC_CTX *mem_ctx,
981 struct tevent_context *ev,
982 struct files_struct *fsp,
983 const void *data,
984 size_t n, off_t offset)
986 struct tevent_req *req, *subreq;
987 struct vfswrap_pwrite_state *state;
989 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
990 if (req == NULL) {
991 return NULL;
994 state->ret = -1;
995 state->fd = fsp_get_io_fd(fsp);
996 state->buf = data;
997 state->count = n;
998 state->offset = offset;
1000 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1001 state->profile_bytes, n);
1002 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1004 subreq = pthreadpool_tevent_job_send(
1005 state, ev, handle->conn->sconn->pool,
1006 vfs_pwrite_do, state);
1007 if (tevent_req_nomem(subreq, req)) {
1008 return tevent_req_post(req, ev);
1010 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1012 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1014 return req;
1017 static void vfs_pwrite_do(void *private_data)
1019 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1020 private_data, struct vfswrap_pwrite_state);
1021 struct timespec start_time;
1022 struct timespec end_time;
1024 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1026 PROFILE_TIMESTAMP(&start_time);
1028 state->ret = sys_pwrite_full(state->fd,
1029 state->buf,
1030 state->count,
1031 state->offset);
1033 if (state->ret == -1) {
1034 state->vfs_aio_state.error = errno;
1037 PROFILE_TIMESTAMP(&end_time);
1039 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1041 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1044 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1046 return -1;
1049 static void vfs_pwrite_done(struct tevent_req *subreq)
1051 struct tevent_req *req = tevent_req_callback_data(
1052 subreq, struct tevent_req);
1053 struct vfswrap_pwrite_state *state = tevent_req_data(
1054 req, struct vfswrap_pwrite_state);
1055 int ret;
1057 ret = pthreadpool_tevent_job_recv(subreq);
1058 TALLOC_FREE(subreq);
1059 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1060 talloc_set_destructor(state, NULL);
1061 if (ret != 0) {
1062 if (ret != EAGAIN) {
1063 tevent_req_error(req, ret);
1064 return;
1067 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1068 * means the lower level pthreadpool failed to create a new
1069 * thread. Fallback to sync processing in that case to allow
1070 * some progress for the client.
1072 vfs_pwrite_do(state);
1075 tevent_req_done(req);
1078 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1079 struct vfs_aio_state *vfs_aio_state)
1081 struct vfswrap_pwrite_state *state = tevent_req_data(
1082 req, struct vfswrap_pwrite_state);
1084 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1085 return -1;
1088 *vfs_aio_state = state->vfs_aio_state;
1089 return state->ret;
1092 struct vfswrap_fsync_state {
1093 ssize_t ret;
1094 int fd;
1096 struct vfs_aio_state vfs_aio_state;
1097 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1100 static void vfs_fsync_do(void *private_data);
1101 static void vfs_fsync_done(struct tevent_req *subreq);
1102 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1104 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1105 TALLOC_CTX *mem_ctx,
1106 struct tevent_context *ev,
1107 struct files_struct *fsp)
1109 struct tevent_req *req, *subreq;
1110 struct vfswrap_fsync_state *state;
1112 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1113 if (req == NULL) {
1114 return NULL;
1117 state->ret = -1;
1118 state->fd = fsp_get_io_fd(fsp);
1120 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1121 state->profile_bytes, 0);
1122 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1124 subreq = pthreadpool_tevent_job_send(
1125 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1126 if (tevent_req_nomem(subreq, req)) {
1127 return tevent_req_post(req, ev);
1129 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1131 talloc_set_destructor(state, vfs_fsync_state_destructor);
1133 return req;
1136 static void vfs_fsync_do(void *private_data)
1138 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1139 private_data, struct vfswrap_fsync_state);
1140 struct timespec start_time;
1141 struct timespec end_time;
1143 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1145 PROFILE_TIMESTAMP(&start_time);
1147 do {
1148 state->ret = fsync(state->fd);
1149 } while ((state->ret == -1) && (errno == EINTR));
1151 if (state->ret == -1) {
1152 state->vfs_aio_state.error = errno;
1155 PROFILE_TIMESTAMP(&end_time);
1157 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1159 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1162 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1164 return -1;
1167 static void vfs_fsync_done(struct tevent_req *subreq)
1169 struct tevent_req *req = tevent_req_callback_data(
1170 subreq, struct tevent_req);
1171 struct vfswrap_fsync_state *state = tevent_req_data(
1172 req, struct vfswrap_fsync_state);
1173 int ret;
1175 ret = pthreadpool_tevent_job_recv(subreq);
1176 TALLOC_FREE(subreq);
1177 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1178 talloc_set_destructor(state, NULL);
1179 if (ret != 0) {
1180 if (ret != EAGAIN) {
1181 tevent_req_error(req, ret);
1182 return;
1185 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1186 * means the lower level pthreadpool failed to create a new
1187 * thread. Fallback to sync processing in that case to allow
1188 * some progress for the client.
1190 vfs_fsync_do(state);
1193 tevent_req_done(req);
1196 static int vfswrap_fsync_recv(struct tevent_req *req,
1197 struct vfs_aio_state *vfs_aio_state)
1199 struct vfswrap_fsync_state *state = tevent_req_data(
1200 req, struct vfswrap_fsync_state);
1202 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1203 return -1;
1206 *vfs_aio_state = state->vfs_aio_state;
1207 return state->ret;
1210 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1212 off_t result = 0;
1214 START_PROFILE(syscall_lseek);
1216 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1218 * We want to maintain the fiction that we can seek
1219 * on a fifo for file system purposes. This allows
1220 * people to set up UNIX fifo's that feed data to Windows
1221 * applications. JRA.
1224 if((result == -1) && (errno == ESPIPE)) {
1225 result = 0;
1226 errno = 0;
1229 END_PROFILE(syscall_lseek);
1230 return result;
1233 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1234 off_t offset, size_t n)
1236 ssize_t result;
1238 START_PROFILE_BYTES(syscall_sendfile, n);
1239 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1240 END_PROFILE_BYTES(syscall_sendfile);
1241 return result;
1244 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1245 int fromfd,
1246 files_struct *tofsp,
1247 off_t offset,
1248 size_t n)
1250 ssize_t result;
1252 START_PROFILE_BYTES(syscall_recvfile, n);
1253 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1254 END_PROFILE_BYTES(syscall_recvfile);
1255 return result;
1258 static int vfswrap_renameat(vfs_handle_struct *handle,
1259 files_struct *srcfsp,
1260 const struct smb_filename *smb_fname_src,
1261 files_struct *dstfsp,
1262 const struct smb_filename *smb_fname_dst)
1264 int result = -1;
1266 START_PROFILE(syscall_renameat);
1268 SMB_ASSERT(!is_named_stream(smb_fname_src));
1269 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1271 result = renameat(fsp_get_pathref_fd(srcfsp),
1272 smb_fname_src->base_name,
1273 fsp_get_pathref_fd(dstfsp),
1274 smb_fname_dst->base_name);
1276 END_PROFILE(syscall_renameat);
1277 return result;
1280 static int vfswrap_stat(vfs_handle_struct *handle,
1281 struct smb_filename *smb_fname)
1283 int result = -1;
1285 START_PROFILE(syscall_stat);
1287 SMB_ASSERT(!is_named_stream(smb_fname));
1289 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1290 lp_fake_directory_create_times(SNUM(handle->conn)));
1292 END_PROFILE(syscall_stat);
1293 return result;
1296 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1298 int result;
1300 START_PROFILE(syscall_fstat);
1301 result = sys_fstat(fsp_get_pathref_fd(fsp),
1302 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1303 END_PROFILE(syscall_fstat);
1304 return result;
1307 static int vfswrap_lstat(vfs_handle_struct *handle,
1308 struct smb_filename *smb_fname)
1310 int result = -1;
1312 START_PROFILE(syscall_lstat);
1314 SMB_ASSERT(!is_named_stream(smb_fname));
1316 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1317 lp_fake_directory_create_times(SNUM(handle->conn)));
1319 END_PROFILE(syscall_lstat);
1320 return result;
1323 static int vfswrap_fstatat(
1324 struct vfs_handle_struct *handle,
1325 const struct files_struct *dirfsp,
1326 const struct smb_filename *smb_fname,
1327 SMB_STRUCT_STAT *sbuf,
1328 int flags)
1330 int result = -1;
1332 START_PROFILE(syscall_fstatat);
1334 SMB_ASSERT(!is_named_stream(smb_fname));
1336 result = sys_fstatat(
1337 fsp_get_pathref_fd(dirfsp),
1338 smb_fname->base_name,
1339 sbuf,
1340 flags,
1341 lp_fake_directory_create_times(SNUM(handle->conn)));
1343 END_PROFILE(syscall_fstatat);
1344 return result;
1347 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1348 const char *name,
1349 enum vfs_translate_direction direction,
1350 TALLOC_CTX *mem_ctx,
1351 char **mapped_name)
1353 return NT_STATUS_NONE_MAPPED;
1357 * Return allocated parent directory and basename of path
1359 * Note: if requesting atname, it is returned as talloc child of the
1360 * parent. Freeing the parent is thus sufficient to free both.
1362 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1363 TALLOC_CTX *mem_ctx,
1364 const struct smb_filename *smb_fname_in,
1365 struct smb_filename **parent_dir_out,
1366 struct smb_filename **atname_out)
1368 struct smb_filename *parent = NULL;
1369 struct smb_filename *name = NULL;
1370 char *p = NULL;
1372 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1373 if (parent == NULL) {
1374 return NT_STATUS_NO_MEMORY;
1376 SET_STAT_INVALID(parent->st);
1378 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1379 if (p == NULL) {
1380 TALLOC_FREE(parent->base_name);
1381 parent->base_name = talloc_strdup(parent, ".");
1382 if (parent->base_name == NULL) {
1383 TALLOC_FREE(parent);
1384 return NT_STATUS_NO_MEMORY;
1386 p = smb_fname_in->base_name;
1387 } else {
1388 *p = '\0';
1389 p++;
1392 if (atname_out == NULL) {
1393 *parent_dir_out = parent;
1394 return NT_STATUS_OK;
1397 name = synthetic_smb_fname(
1398 parent,
1400 smb_fname_in->stream_name,
1401 &smb_fname_in->st,
1402 smb_fname_in->twrp,
1403 smb_fname_in->flags);
1404 if (name == NULL) {
1405 return NT_STATUS_NO_MEMORY;
1408 *parent_dir_out = parent;
1409 *atname_out = name;
1410 return NT_STATUS_OK;
1414 * Implement the default fsctl operation.
1416 static bool vfswrap_logged_ioctl_message = false;
1418 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1419 struct files_struct *fsp,
1420 TALLOC_CTX *ctx,
1421 uint32_t function,
1422 uint16_t req_flags, /* Needed for UNICODE ... */
1423 const uint8_t *_in_data,
1424 uint32_t in_len,
1425 uint8_t **_out_data,
1426 uint32_t max_out_len,
1427 uint32_t *out_len)
1429 const char *in_data = (const char *)_in_data;
1430 char **out_data = (char **)_out_data;
1431 NTSTATUS status;
1434 * Currently all fsctls operate on the base
1435 * file if given an alternate data stream.
1436 * Revisit this if we implement fsctls later
1437 * that need access to the ADS handle.
1439 fsp = metadata_fsp(fsp);
1441 switch (function) {
1442 case FSCTL_SET_SPARSE:
1444 bool set_sparse = true;
1446 if (in_len >= 1 && in_data[0] == 0) {
1447 set_sparse = false;
1450 status = file_set_sparse(handle->conn, fsp, set_sparse);
1452 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1453 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1454 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1455 nt_errstr(status)));
1457 return status;
1460 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1462 unsigned char objid[16];
1463 char *return_data = NULL;
1465 /* This should return the object-id on this file.
1466 * I think I'll make this be the inode+dev. JRA.
1469 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1470 fsp_fnum_dbg(fsp));
1472 *out_len = MIN(max_out_len, 64);
1474 /* Hmmm, will this cause problems if less data asked for? */
1475 return_data = talloc_array(ctx, char, 64);
1476 if (return_data == NULL) {
1477 return NT_STATUS_NO_MEMORY;
1480 /* For backwards compatibility only store the dev/inode. */
1481 push_file_id_16(return_data, &fsp->file_id);
1482 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1483 push_file_id_16(return_data+32, &fsp->file_id);
1484 memset(return_data+48, 0, 16);
1485 *out_data = return_data;
1486 return NT_STATUS_OK;
1489 case FSCTL_GET_REPARSE_POINT:
1491 status = fsctl_get_reparse_point(
1492 fsp, ctx, out_data, max_out_len, out_len);
1493 return status;
1496 case FSCTL_SET_REPARSE_POINT:
1498 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1499 return status;
1502 case FSCTL_DELETE_REPARSE_POINT:
1504 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1505 return status;
1508 case FSCTL_GET_SHADOW_COPY_DATA:
1511 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1512 * and return their volume names. If max_data_count is 16, then it is just
1513 * asking for the number of volumes and length of the combined names.
1515 * pdata is the data allocated by our caller, but that uses
1516 * total_data_count (which is 0 in our case) rather than max_data_count.
1517 * Allocate the correct amount and return the pointer to let
1518 * it be deallocated when we return.
1520 struct shadow_copy_data *shadow_data = NULL;
1521 bool labels = False;
1522 uint32_t labels_data_count = 0;
1523 uint32_t i;
1524 char *cur_pdata = NULL;
1526 if (max_out_len < 16) {
1527 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1528 max_out_len);
1529 return NT_STATUS_INVALID_PARAMETER;
1532 if (max_out_len > 16) {
1533 labels = True;
1536 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1537 if (shadow_data == NULL) {
1538 DBG_ERR("TALLOC_ZERO() failed!\n");
1539 return NT_STATUS_NO_MEMORY;
1543 * Call the VFS routine to actually do the work.
1545 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1546 int log_lev = DBGLVL_ERR;
1547 if (errno == 0) {
1548 /* broken module didn't set errno on error */
1549 status = NT_STATUS_UNSUCCESSFUL;
1550 } else {
1551 status = map_nt_error_from_unix(errno);
1552 if (NT_STATUS_EQUAL(status,
1553 NT_STATUS_NOT_SUPPORTED)) {
1554 log_lev = DBGLVL_INFO;
1557 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1558 "connectpath %s, failed - %s.\n",
1559 fsp->conn->connectpath,
1560 nt_errstr(status)));
1561 TALLOC_FREE(shadow_data);
1562 return status;
1565 labels_data_count = (shadow_data->num_volumes * 2 *
1566 sizeof(SHADOW_COPY_LABEL)) + 2;
1568 if (!labels) {
1569 *out_len = 16;
1570 } else {
1571 *out_len = 12 + labels_data_count;
1574 if (max_out_len < *out_len) {
1575 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1576 max_out_len, *out_len);
1577 TALLOC_FREE(shadow_data);
1578 return NT_STATUS_BUFFER_TOO_SMALL;
1581 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1582 if (cur_pdata == NULL) {
1583 TALLOC_FREE(shadow_data);
1584 return NT_STATUS_NO_MEMORY;
1587 *out_data = cur_pdata;
1589 /* num_volumes 4 bytes */
1590 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1592 if (labels) {
1593 /* num_labels 4 bytes */
1594 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1597 /* needed_data_count 4 bytes */
1598 SIVAL(cur_pdata, 8, labels_data_count);
1600 cur_pdata += 12;
1602 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1603 shadow_data->num_volumes, fsp_str_dbg(fsp));
1604 if (labels && shadow_data->labels) {
1605 for (i=0; i<shadow_data->num_volumes; i++) {
1606 size_t len = 0;
1607 status = srvstr_push(cur_pdata, req_flags,
1608 cur_pdata, shadow_data->labels[i],
1609 2 * sizeof(SHADOW_COPY_LABEL),
1610 STR_UNICODE|STR_TERMINATE, &len);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 TALLOC_FREE(*out_data);
1613 TALLOC_FREE(shadow_data);
1614 return status;
1616 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1617 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1621 TALLOC_FREE(shadow_data);
1623 return NT_STATUS_OK;
1626 case FSCTL_FIND_FILES_BY_SID:
1628 /* pretend this succeeded -
1630 * we have to send back a list with all files owned by this SID
1632 * but I have to check that --metze
1634 ssize_t ret;
1635 struct dom_sid sid;
1636 struct dom_sid_buf buf;
1637 uid_t uid;
1638 size_t sid_len;
1640 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1641 fsp_fnum_dbg(fsp));
1643 if (in_len < 8) {
1644 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1645 return NT_STATUS_INVALID_PARAMETER;
1648 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1650 /* unknown 4 bytes: this is not the length of the sid :-( */
1651 /*unknown = IVAL(pdata,0);*/
1653 ret = sid_parse(_in_data + 4, sid_len, &sid);
1654 if (ret == -1) {
1655 return NT_STATUS_INVALID_PARAMETER;
1657 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1658 dom_sid_str_buf(&sid, &buf)));
1660 if (!sid_to_uid(&sid, &uid)) {
1661 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1662 dom_sid_str_buf(&sid, &buf),
1663 (unsigned long)sid_len);
1664 uid = (-1);
1667 /* we can take a look at the find source :-)
1669 * find ./ -uid $uid -name '*' is what we need here
1672 * and send 4bytes len and then NULL terminated unicode strings
1673 * for each file
1675 * but I don't know how to deal with the paged results
1676 * (maybe we can hang the result anywhere in the fsp struct)
1678 * but I don't know how to deal with the paged results
1679 * (maybe we can hang the result anywhere in the fsp struct)
1681 * we don't send all files at once
1682 * and at the next we should *not* start from the beginning,
1683 * so we have to cache the result
1685 * --metze
1688 /* this works for now... */
1689 return NT_STATUS_OK;
1692 case FSCTL_QUERY_ALLOCATED_RANGES:
1694 /* FIXME: This is just a dummy reply, telling that all of the
1695 * file is allocated. MKS cp needs that.
1696 * Adding the real allocated ranges via FIEMAP on Linux
1697 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1698 * this FSCTL correct for sparse files.
1700 uint64_t offset, length;
1701 char *out_data_tmp = NULL;
1703 if (in_len != 16) {
1704 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1705 in_len);
1706 return NT_STATUS_INVALID_PARAMETER;
1709 if (max_out_len < 16) {
1710 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1711 max_out_len);
1712 return NT_STATUS_INVALID_PARAMETER;
1715 offset = BVAL(in_data,0);
1716 length = BVAL(in_data,8);
1718 if (offset + length < offset) {
1719 /* No 64-bit integer wrap. */
1720 return NT_STATUS_INVALID_PARAMETER;
1723 /* Shouldn't this be SMB_VFS_STAT ... ? */
1724 status = vfs_stat_fsp(fsp);
1725 if (!NT_STATUS_IS_OK(status)) {
1726 return status;
1729 *out_len = 16;
1730 out_data_tmp = talloc_array(ctx, char, *out_len);
1731 if (out_data_tmp == NULL) {
1732 DBG_DEBUG("unable to allocate memory for response\n");
1733 return NT_STATUS_NO_MEMORY;
1736 if (offset > fsp->fsp_name->st.st_ex_size ||
1737 fsp->fsp_name->st.st_ex_size == 0 ||
1738 length == 0) {
1739 memset(out_data_tmp, 0, *out_len);
1740 } else {
1741 uint64_t end = offset + length;
1742 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1743 SBVAL(out_data_tmp, 0, 0);
1744 SBVAL(out_data_tmp, 8, end);
1747 *out_data = out_data_tmp;
1749 return NT_STATUS_OK;
1752 case FSCTL_IS_VOLUME_DIRTY:
1754 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1755 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1757 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1758 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1760 return NT_STATUS_INVALID_PARAMETER;
1763 default:
1765 * Only print once ... unfortunately there could be lots of
1766 * different FSCTLs that are called.
1768 if (!vfswrap_logged_ioctl_message) {
1769 vfswrap_logged_ioctl_message = true;
1770 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1771 __func__, function);
1775 return NT_STATUS_NOT_SUPPORTED;
1778 static bool vfswrap_is_offline(struct connection_struct *conn,
1779 const struct smb_filename *fname);
1781 struct vfswrap_get_dos_attributes_state {
1782 struct vfs_aio_state aio_state;
1783 connection_struct *conn;
1784 TALLOC_CTX *mem_ctx;
1785 struct tevent_context *ev;
1786 files_struct *dir_fsp;
1787 struct smb_filename *smb_fname;
1788 uint32_t dosmode;
1789 bool as_root;
1792 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1794 static struct tevent_req *vfswrap_get_dos_attributes_send(
1795 TALLOC_CTX *mem_ctx,
1796 struct tevent_context *ev,
1797 struct vfs_handle_struct *handle,
1798 files_struct *dir_fsp,
1799 struct smb_filename *smb_fname)
1801 struct tevent_req *req = NULL;
1802 struct tevent_req *subreq = NULL;
1803 struct vfswrap_get_dos_attributes_state *state = NULL;
1805 SMB_ASSERT(!is_named_stream(smb_fname));
1807 req = tevent_req_create(mem_ctx, &state,
1808 struct vfswrap_get_dos_attributes_state);
1809 if (req == NULL) {
1810 return NULL;
1813 *state = (struct vfswrap_get_dos_attributes_state) {
1814 .conn = dir_fsp->conn,
1815 .mem_ctx = mem_ctx,
1816 .ev = ev,
1817 .dir_fsp = dir_fsp,
1818 .smb_fname = smb_fname,
1821 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1822 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1823 "\"store dos attributes\" is disabled\n",
1824 dir_fsp->conn->connectpath);
1825 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1826 return tevent_req_post(req, ev);
1829 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1831 dir_fsp,
1832 smb_fname,
1833 SAMBA_XATTR_DOS_ATTRIB,
1834 sizeof(fstring));
1835 if (tevent_req_nomem(subreq, req)) {
1836 return tevent_req_post(req, ev);
1838 tevent_req_set_callback(subreq,
1839 vfswrap_get_dos_attributes_getxattr_done,
1840 req);
1842 return req;
1845 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1847 struct tevent_req *req =
1848 tevent_req_callback_data(subreq,
1849 struct tevent_req);
1850 struct vfswrap_get_dos_attributes_state *state =
1851 tevent_req_data(req,
1852 struct vfswrap_get_dos_attributes_state);
1853 ssize_t xattr_size;
1854 DATA_BLOB blob = {0};
1855 char *path = NULL;
1856 char *tofree = NULL;
1857 char pathbuf[PATH_MAX+1];
1858 ssize_t pathlen;
1859 struct smb_filename smb_fname;
1860 bool offline;
1861 NTSTATUS status;
1863 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1864 &state->aio_state,
1865 state,
1866 &blob.data);
1867 TALLOC_FREE(subreq);
1868 if (xattr_size == -1) {
1869 status = map_nt_error_from_unix(state->aio_state.error);
1871 if (state->as_root) {
1872 tevent_req_nterror(req, status);
1873 return;
1875 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1876 tevent_req_nterror(req, status);
1877 return;
1880 state->as_root = true;
1882 become_root();
1883 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1884 state->ev,
1885 state->dir_fsp,
1886 state->smb_fname,
1887 SAMBA_XATTR_DOS_ATTRIB,
1888 sizeof(fstring));
1889 unbecome_root();
1890 if (tevent_req_nomem(subreq, req)) {
1891 return;
1893 tevent_req_set_callback(subreq,
1894 vfswrap_get_dos_attributes_getxattr_done,
1895 req);
1896 return;
1899 blob.length = xattr_size;
1901 status = parse_dos_attribute_blob(state->smb_fname,
1902 blob,
1903 &state->dosmode);
1904 if (!NT_STATUS_IS_OK(status)) {
1905 tevent_req_nterror(req, status);
1906 return;
1909 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1910 state->smb_fname->base_name,
1911 pathbuf,
1912 sizeof(pathbuf),
1913 &path,
1914 &tofree);
1915 if (pathlen == -1) {
1916 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1917 return;
1920 smb_fname = (struct smb_filename) {
1921 .base_name = path,
1922 .st = state->smb_fname->st,
1923 .flags = state->smb_fname->flags,
1924 .twrp = state->smb_fname->twrp,
1927 offline = vfswrap_is_offline(state->conn, &smb_fname);
1928 if (offline) {
1929 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1931 TALLOC_FREE(tofree);
1933 tevent_req_done(req);
1934 return;
1937 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1938 struct vfs_aio_state *aio_state,
1939 uint32_t *dosmode)
1941 struct vfswrap_get_dos_attributes_state *state =
1942 tevent_req_data(req,
1943 struct vfswrap_get_dos_attributes_state);
1944 NTSTATUS status;
1946 if (tevent_req_is_nterror(req, &status)) {
1947 tevent_req_received(req);
1948 return status;
1951 *aio_state = state->aio_state;
1952 *dosmode = state->dosmode;
1953 tevent_req_received(req);
1954 return NT_STATUS_OK;
1957 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1958 struct files_struct *fsp,
1959 uint32_t *dosmode)
1961 bool offline;
1963 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1965 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1966 if (offline) {
1967 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1970 return fget_ea_dos_attribute(fsp, dosmode);
1973 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1974 struct files_struct *fsp,
1975 uint32_t dosmode)
1977 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1979 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1982 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1984 struct vfswrap_offload_read_state {
1985 DATA_BLOB token;
1988 static struct tevent_req *vfswrap_offload_read_send(
1989 TALLOC_CTX *mem_ctx,
1990 struct tevent_context *ev,
1991 struct vfs_handle_struct *handle,
1992 struct files_struct *fsp,
1993 uint32_t fsctl,
1994 uint32_t ttl,
1995 off_t offset,
1996 size_t to_copy)
1998 struct tevent_req *req = NULL;
1999 struct vfswrap_offload_read_state *state = NULL;
2000 NTSTATUS status;
2002 req = tevent_req_create(mem_ctx, &state,
2003 struct vfswrap_offload_read_state);
2004 if (req == NULL) {
2005 return NULL;
2008 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2009 &vfswrap_offload_ctx);
2010 if (tevent_req_nterror(req, status)) {
2011 return tevent_req_post(req, ev);
2014 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2015 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2016 return tevent_req_post(req, ev);
2019 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2020 &state->token);
2021 if (tevent_req_nterror(req, status)) {
2022 return tevent_req_post(req, ev);
2025 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2026 &state->token);
2027 if (tevent_req_nterror(req, status)) {
2028 return tevent_req_post(req, ev);
2031 tevent_req_done(req);
2032 return tevent_req_post(req, ev);
2035 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2036 struct vfs_handle_struct *handle,
2037 TALLOC_CTX *mem_ctx,
2038 uint32_t *flags,
2039 uint64_t *xferlen,
2040 DATA_BLOB *token)
2042 struct vfswrap_offload_read_state *state = tevent_req_data(
2043 req, struct vfswrap_offload_read_state);
2044 NTSTATUS status;
2046 if (tevent_req_is_nterror(req, &status)) {
2047 tevent_req_received(req);
2048 return status;
2051 *flags = 0;
2052 *xferlen = 0;
2053 token->length = state->token.length;
2054 token->data = talloc_move(mem_ctx, &state->token.data);
2056 tevent_req_received(req);
2057 return NT_STATUS_OK;
2060 struct vfswrap_offload_write_state {
2061 uint8_t *buf;
2062 bool read_lck_locked;
2063 bool write_lck_locked;
2064 DATA_BLOB *token;
2065 struct tevent_context *src_ev;
2066 struct files_struct *src_fsp;
2067 off_t src_off;
2068 struct tevent_context *dst_ev;
2069 struct files_struct *dst_fsp;
2070 off_t dst_off;
2071 off_t to_copy;
2072 off_t remaining;
2073 off_t copied;
2074 size_t next_io_size;
2077 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2078 enum tevent_req_state req_state)
2080 struct vfswrap_offload_write_state *state = tevent_req_data(
2081 req, struct vfswrap_offload_write_state);
2082 bool ok;
2084 if (state->dst_fsp == NULL) {
2085 return;
2088 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2089 SMB_ASSERT(ok);
2090 state->dst_fsp = NULL;
2093 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2094 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2096 static struct tevent_req *vfswrap_offload_write_send(
2097 struct vfs_handle_struct *handle,
2098 TALLOC_CTX *mem_ctx,
2099 struct tevent_context *ev,
2100 uint32_t fsctl,
2101 DATA_BLOB *token,
2102 off_t transfer_offset,
2103 struct files_struct *dest_fsp,
2104 off_t dest_off,
2105 off_t to_copy)
2107 struct tevent_req *req;
2108 struct vfswrap_offload_write_state *state = NULL;
2109 /* off_t is signed! */
2110 off_t max_offset = INT64_MAX - to_copy;
2111 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2112 files_struct *src_fsp = NULL;
2113 NTSTATUS status;
2114 bool ok;
2116 req = tevent_req_create(mem_ctx, &state,
2117 struct vfswrap_offload_write_state);
2118 if (req == NULL) {
2119 return NULL;
2122 *state = (struct vfswrap_offload_write_state) {
2123 .token = token,
2124 .src_off = transfer_offset,
2125 .dst_ev = ev,
2126 .dst_fsp = dest_fsp,
2127 .dst_off = dest_off,
2128 .to_copy = to_copy,
2129 .remaining = to_copy,
2132 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2134 switch (fsctl) {
2135 case FSCTL_SRV_COPYCHUNK:
2136 case FSCTL_SRV_COPYCHUNK_WRITE:
2137 break;
2139 case FSCTL_OFFLOAD_WRITE:
2140 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2141 return tevent_req_post(req, ev);
2143 case FSCTL_DUP_EXTENTS_TO_FILE:
2144 DBG_DEBUG("COW clones not supported by vfs_default\n");
2145 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2146 return tevent_req_post(req, ev);
2148 default:
2149 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2150 return tevent_req_post(req, ev);
2154 * From here on we assume a copy-chunk fsctl
2157 if (to_copy == 0) {
2158 tevent_req_done(req);
2159 return tevent_req_post(req, ev);
2162 if (state->src_off > max_offset) {
2164 * Protect integer checks below.
2166 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2167 return tevent_req_post(req, ev);
2169 if (state->src_off < 0) {
2171 * Protect integer checks below.
2173 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2174 return tevent_req_post(req, ev);
2176 if (state->dst_off > max_offset) {
2178 * Protect integer checks below.
2180 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2181 return tevent_req_post(req, ev);
2183 if (state->dst_off < 0) {
2185 * Protect integer checks below.
2187 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2188 return tevent_req_post(req, ev);
2191 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2192 token, &src_fsp);
2193 if (tevent_req_nterror(req, status)) {
2194 return tevent_req_post(req, ev);
2197 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2199 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2200 if (!NT_STATUS_IS_OK(status)) {
2201 tevent_req_nterror(req, status);
2202 return tevent_req_post(req, ev);
2205 ok = change_to_user_and_service_by_fsp(src_fsp);
2206 if (!ok) {
2207 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2208 return tevent_req_post(req, ev);
2211 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2212 state->src_fsp = src_fsp;
2214 status = vfs_stat_fsp(src_fsp);
2215 if (tevent_req_nterror(req, status)) {
2216 return tevent_req_post(req, ev);
2219 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2221 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2222 * If the SourceOffset or SourceOffset + Length extends beyond
2223 * the end of file, the server SHOULD<240> treat this as a
2224 * STATUS_END_OF_FILE error.
2225 * ...
2226 * <240> Section 3.3.5.15.6: Windows servers will return
2227 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2229 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2230 return tevent_req_post(req, ev);
2233 status = vfswrap_offload_copy_file_range(req);
2234 if (NT_STATUS_IS_OK(status)) {
2235 tevent_req_done(req);
2236 return tevent_req_post(req, ev);
2238 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2239 tevent_req_nterror(req, status);
2240 return tevent_req_post(req, ev);
2243 state->buf = talloc_array(state, uint8_t, num);
2244 if (tevent_req_nomem(state->buf, req)) {
2245 return tevent_req_post(req, ev);
2248 status = vfswrap_offload_write_loop(req);
2249 if (!NT_STATUS_IS_OK(status)) {
2250 tevent_req_nterror(req, status);
2251 return tevent_req_post(req, ev);
2254 return req;
2257 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2259 struct vfswrap_offload_write_state *state = tevent_req_data(
2260 req, struct vfswrap_offload_write_state);
2261 struct lock_struct lck;
2262 ssize_t nwritten;
2263 NTSTATUS status;
2264 bool same_file;
2265 bool ok;
2266 static bool try_copy_file_range = true;
2268 if (!try_copy_file_range) {
2269 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2272 same_file = file_id_equal(&state->src_fsp->file_id,
2273 &state->dst_fsp->file_id);
2274 if (same_file &&
2275 sys_io_ranges_overlap(state->remaining,
2276 state->src_off,
2277 state->remaining,
2278 state->dst_off))
2280 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2283 if (fsp_is_alternate_stream(state->src_fsp) ||
2284 fsp_is_alternate_stream(state->dst_fsp))
2286 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2289 init_strict_lock_struct(state->src_fsp,
2290 state->src_fsp->op->global->open_persistent_id,
2291 state->src_off,
2292 state->remaining,
2293 READ_LOCK,
2294 lp_posix_cifsu_locktype(state->src_fsp),
2295 &lck);
2297 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2298 state->src_fsp,
2299 &lck);
2300 if (!ok) {
2301 return NT_STATUS_FILE_LOCK_CONFLICT;
2304 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2305 if (!ok) {
2306 return NT_STATUS_INTERNAL_ERROR;
2309 init_strict_lock_struct(state->dst_fsp,
2310 state->dst_fsp->op->global->open_persistent_id,
2311 state->dst_off,
2312 state->remaining,
2313 WRITE_LOCK,
2314 lp_posix_cifsu_locktype(state->dst_fsp),
2315 &lck);
2317 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2318 state->dst_fsp,
2319 &lck);
2320 if (!ok) {
2321 return NT_STATUS_FILE_LOCK_CONFLICT;
2324 while (state->remaining > 0) {
2325 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2326 &state->src_off,
2327 fsp_get_io_fd(state->dst_fsp),
2328 &state->dst_off,
2329 state->remaining,
2331 if (nwritten == -1) {
2332 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2333 "n [%jd] failed: %s\n",
2334 fsp_str_dbg(state->src_fsp),
2335 (intmax_t)state->src_off,
2336 fsp_str_dbg(state->dst_fsp),
2337 (intmax_t)state->dst_off,
2338 (intmax_t)state->remaining,
2339 strerror(errno));
2340 switch (errno) {
2341 case EOPNOTSUPP:
2342 case ENOSYS:
2343 try_copy_file_range = false;
2344 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2345 break;
2346 case EXDEV:
2347 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2348 break;
2349 default:
2350 status = map_nt_error_from_unix(errno);
2351 if (NT_STATUS_EQUAL(
2352 status,
2353 NT_STATUS_MORE_PROCESSING_REQUIRED))
2355 /* Avoid triggering the fallback */
2356 status = NT_STATUS_INTERNAL_ERROR;
2358 break;
2360 return status;
2363 if (state->remaining < nwritten) {
2364 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2365 "n [%jd] remaining [%jd]\n",
2366 fsp_str_dbg(state->src_fsp),
2367 fsp_str_dbg(state->dst_fsp),
2368 (intmax_t)nwritten,
2369 (intmax_t)state->remaining);
2370 return NT_STATUS_INTERNAL_ERROR;
2373 if (nwritten == 0) {
2374 break;
2376 state->copied += nwritten;
2377 state->remaining -= nwritten;
2381 * Tell the req cleanup function there's no need to call
2382 * change_to_user_and_service_by_fsp() on the dst handle.
2384 state->dst_fsp = NULL;
2385 return NT_STATUS_OK;
2388 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2390 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2392 struct vfswrap_offload_write_state *state = tevent_req_data(
2393 req, struct vfswrap_offload_write_state);
2394 struct tevent_req *subreq = NULL;
2395 struct lock_struct read_lck;
2396 bool ok;
2399 * This is called under the context of state->src_fsp.
2402 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2404 init_strict_lock_struct(state->src_fsp,
2405 state->src_fsp->op->global->open_persistent_id,
2406 state->src_off,
2407 state->next_io_size,
2408 READ_LOCK,
2409 lp_posix_cifsu_locktype(state->src_fsp),
2410 &read_lck);
2412 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2413 state->src_fsp,
2414 &read_lck);
2415 if (!ok) {
2416 return NT_STATUS_FILE_LOCK_CONFLICT;
2419 subreq = SMB_VFS_PREAD_SEND(state,
2420 state->src_ev,
2421 state->src_fsp,
2422 state->buf,
2423 state->next_io_size,
2424 state->src_off);
2425 if (subreq == NULL) {
2426 return NT_STATUS_NO_MEMORY;
2428 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2430 return NT_STATUS_OK;
2433 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2435 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2437 struct tevent_req *req = tevent_req_callback_data(
2438 subreq, struct tevent_req);
2439 struct vfswrap_offload_write_state *state = tevent_req_data(
2440 req, struct vfswrap_offload_write_state);
2441 struct vfs_aio_state aio_state;
2442 struct lock_struct write_lck;
2443 ssize_t nread;
2444 bool ok;
2446 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2447 TALLOC_FREE(subreq);
2448 if (nread == -1) {
2449 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2450 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2451 return;
2453 if (nread != state->next_io_size) {
2454 DBG_ERR("Short read, only %zd of %zu\n",
2455 nread, state->next_io_size);
2456 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2457 return;
2460 state->src_off += nread;
2462 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2463 if (!ok) {
2464 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2465 return;
2468 init_strict_lock_struct(state->dst_fsp,
2469 state->dst_fsp->op->global->open_persistent_id,
2470 state->dst_off,
2471 state->next_io_size,
2472 WRITE_LOCK,
2473 lp_posix_cifsu_locktype(state->dst_fsp),
2474 &write_lck);
2476 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2477 state->dst_fsp,
2478 &write_lck);
2479 if (!ok) {
2480 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2481 return;
2484 subreq = SMB_VFS_PWRITE_SEND(state,
2485 state->dst_ev,
2486 state->dst_fsp,
2487 state->buf,
2488 state->next_io_size,
2489 state->dst_off);
2490 if (subreq == NULL) {
2491 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2492 return;
2494 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2497 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2499 struct tevent_req *req = tevent_req_callback_data(
2500 subreq, struct tevent_req);
2501 struct vfswrap_offload_write_state *state = tevent_req_data(
2502 req, struct vfswrap_offload_write_state);
2503 struct vfs_aio_state aio_state;
2504 ssize_t nwritten;
2505 NTSTATUS status;
2506 bool ok;
2508 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2509 TALLOC_FREE(subreq);
2510 if (nwritten == -1) {
2511 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2512 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2513 return;
2515 if (nwritten != state->next_io_size) {
2516 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2517 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2518 return;
2521 state->dst_off += nwritten;
2523 if (state->remaining < nwritten) {
2524 /* Paranoia check */
2525 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2526 return;
2528 state->copied += nwritten;
2529 state->remaining -= nwritten;
2530 if (state->remaining == 0) {
2531 tevent_req_done(req);
2532 return;
2535 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2536 if (!ok) {
2537 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2538 return;
2541 status = vfswrap_offload_write_loop(req);
2542 if (!NT_STATUS_IS_OK(status)) {
2543 tevent_req_nterror(req, status);
2544 return;
2547 return;
2550 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2551 struct tevent_req *req,
2552 off_t *copied)
2554 struct vfswrap_offload_write_state *state = tevent_req_data(
2555 req, struct vfswrap_offload_write_state);
2556 NTSTATUS status;
2558 if (tevent_req_is_nterror(req, &status)) {
2559 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2560 *copied = 0;
2561 tevent_req_received(req);
2562 return status;
2565 *copied = state->copied;
2566 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2567 tevent_req_received(req);
2569 return NT_STATUS_OK;
2572 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2573 TALLOC_CTX *mem_ctx,
2574 struct files_struct *fsp,
2575 uint16_t *_compression_fmt)
2577 return NT_STATUS_INVALID_DEVICE_REQUEST;
2580 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2581 TALLOC_CTX *mem_ctx,
2582 struct files_struct *fsp,
2583 uint16_t compression_fmt)
2585 return NT_STATUS_INVALID_DEVICE_REQUEST;
2588 /********************************************************************
2589 Given a stat buffer return the allocated size on disk, taking into
2590 account sparse files.
2591 ********************************************************************/
2592 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2593 struct files_struct *fsp,
2594 const SMB_STRUCT_STAT *sbuf)
2596 uint64_t result;
2598 START_PROFILE(syscall_get_alloc_size);
2600 if(S_ISDIR(sbuf->st_ex_mode)) {
2601 result = 0;
2602 goto out;
2605 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2606 /* The type of st_blocksize is blkcnt_t which *MUST* be
2607 signed (according to POSIX) and can be less than 64-bits.
2608 Ensure when we're converting to 64 bits wide we don't
2609 sign extend. */
2610 #if defined(SIZEOF_BLKCNT_T_8)
2611 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2612 #elif defined(SIZEOF_BLKCNT_T_4)
2614 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2615 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2617 #else
2618 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2619 #endif
2620 if (result == 0) {
2622 * Some file systems do not allocate a block for very
2623 * small files. But for non-empty file should report a
2624 * positive size.
2627 uint64_t filesize = get_file_size_stat(sbuf);
2628 if (filesize > 0) {
2629 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2632 #else
2633 result = get_file_size_stat(sbuf);
2634 #endif
2636 if (fsp && fsp->initial_allocation_size)
2637 result = MAX(result,fsp->initial_allocation_size);
2639 result = smb_roundup(handle->conn, result);
2641 out:
2642 END_PROFILE(syscall_get_alloc_size);
2643 return result;
2646 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2647 struct files_struct *dirfsp,
2648 const struct smb_filename *smb_fname,
2649 int flags)
2651 int result = -1;
2653 START_PROFILE(syscall_unlinkat);
2655 SMB_ASSERT(!is_named_stream(smb_fname));
2657 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2658 smb_fname->base_name,
2659 flags);
2661 END_PROFILE(syscall_unlinkat);
2662 return result;
2665 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2667 int result;
2669 START_PROFILE(syscall_fchmod);
2671 if (!fsp->fsp_flags.is_pathref) {
2672 result = fchmod(fsp_get_io_fd(fsp), mode);
2673 END_PROFILE(syscall_fchmod);
2674 return result;
2677 if (fsp->fsp_flags.have_proc_fds) {
2678 int fd = fsp_get_pathref_fd(fsp);
2679 const char *p = NULL;
2680 char buf[PATH_MAX];
2682 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2683 if (p != NULL) {
2684 result = chmod(p, mode);
2685 } else {
2686 result = -1;
2688 END_PROFILE(syscall_fchmod);
2689 return result;
2693 * This is no longer a handle based call.
2695 result = chmod(fsp->fsp_name->base_name, mode);
2697 END_PROFILE(syscall_fchmod);
2698 return result;
2701 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2703 #ifdef HAVE_FCHOWN
2704 int result;
2706 START_PROFILE(syscall_fchown);
2707 if (!fsp->fsp_flags.is_pathref) {
2708 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2709 END_PROFILE(syscall_fchown);
2710 return result;
2713 if (fsp->fsp_flags.have_proc_fds) {
2714 int fd = fsp_get_pathref_fd(fsp);
2715 const char *p = NULL;
2716 char buf[PATH_MAX];
2718 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2719 if (p != NULL) {
2720 result = chown(p, uid, gid);
2721 } else {
2722 result = -1;
2724 END_PROFILE(syscall_fchown);
2725 return result;
2729 * This is no longer a handle based call.
2731 result = chown(fsp->fsp_name->base_name, uid, gid);
2732 END_PROFILE(syscall_fchown);
2733 return result;
2734 #else
2735 errno = ENOSYS;
2736 return -1;
2737 #endif
2740 static int vfswrap_lchown(vfs_handle_struct *handle,
2741 const struct smb_filename *smb_fname,
2742 uid_t uid,
2743 gid_t gid)
2745 int result;
2747 START_PROFILE(syscall_lchown);
2748 result = lchown(smb_fname->base_name, uid, gid);
2749 END_PROFILE(syscall_lchown);
2750 return result;
2753 static int vfswrap_chdir(vfs_handle_struct *handle,
2754 const struct smb_filename *smb_fname)
2756 int result;
2758 START_PROFILE(syscall_chdir);
2759 result = chdir(smb_fname->base_name);
2760 END_PROFILE(syscall_chdir);
2761 return result;
2764 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2765 TALLOC_CTX *ctx)
2767 char *result;
2768 struct smb_filename *smb_fname = NULL;
2770 START_PROFILE(syscall_getwd);
2771 result = sys_getwd();
2772 END_PROFILE(syscall_getwd);
2774 if (result == NULL) {
2775 return NULL;
2777 smb_fname = synthetic_smb_fname(ctx,
2778 result,
2779 NULL,
2780 NULL,
2784 * sys_getwd() *always* returns malloced memory.
2785 * We must free here to avoid leaks:
2786 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2788 SAFE_FREE(result);
2789 return smb_fname;
2792 /*********************************************************************
2793 nsec timestamp resolution call. Convert down to whatever the underlying
2794 system will support.
2795 **********************************************************************/
2797 static int vfswrap_fntimes(vfs_handle_struct *handle,
2798 files_struct *fsp,
2799 struct smb_file_time *ft)
2801 int result = -1;
2802 struct timespec ts[2];
2803 struct timespec *times = NULL;
2805 START_PROFILE(syscall_fntimes);
2807 if (fsp_is_alternate_stream(fsp)) {
2808 errno = ENOENT;
2809 goto out;
2812 if (ft != NULL) {
2813 if (is_omit_timespec(&ft->atime)) {
2814 ft->atime = fsp->fsp_name->st.st_ex_atime;
2817 if (is_omit_timespec(&ft->mtime)) {
2818 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2821 if (!is_omit_timespec(&ft->create_time)) {
2822 set_create_timespec_ea(fsp,
2823 ft->create_time);
2826 if ((timespec_compare(&ft->atime,
2827 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2828 (timespec_compare(&ft->mtime,
2829 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2830 result = 0;
2831 goto out;
2834 ts[0] = ft->atime;
2835 ts[1] = ft->mtime;
2836 times = ts;
2837 } else {
2838 times = NULL;
2841 if (!fsp->fsp_flags.is_pathref) {
2842 result = futimens(fsp_get_io_fd(fsp), times);
2843 goto out;
2846 if (fsp->fsp_flags.have_proc_fds) {
2847 int fd = fsp_get_pathref_fd(fsp);
2848 const char *p = NULL;
2849 char buf[PATH_MAX];
2851 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2852 if (p != NULL) {
2854 * The dirfd argument of utimensat is ignored when
2855 * pathname is an absolute path
2857 result = utimensat(AT_FDCWD, p, times, 0);
2858 } else {
2859 result = -1;
2862 goto out;
2866 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2867 * path translation mechanism. Fallback to path based call.
2869 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2871 out:
2872 END_PROFILE(syscall_fntimes);
2874 return result;
2878 /*********************************************************************
2879 A version of ftruncate that will write the space on disk if strict
2880 allocate is set.
2881 **********************************************************************/
2883 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2885 off_t space_to_write;
2886 uint64_t space_avail;
2887 uint64_t bsize,dfree,dsize;
2888 int ret;
2889 NTSTATUS status;
2890 SMB_STRUCT_STAT *pst;
2891 bool ok;
2893 ok = vfs_valid_pwrite_range(len, 0);
2894 if (!ok) {
2895 errno = EINVAL;
2896 return -1;
2899 status = vfs_stat_fsp(fsp);
2900 if (!NT_STATUS_IS_OK(status)) {
2901 return -1;
2903 pst = &fsp->fsp_name->st;
2905 #ifdef S_ISFIFO
2906 if (S_ISFIFO(pst->st_ex_mode))
2907 return 0;
2908 #endif
2910 if (pst->st_ex_size == len)
2911 return 0;
2913 /* Shrink - just ftruncate. */
2914 if (pst->st_ex_size > len)
2915 return ftruncate(fsp_get_io_fd(fsp), len);
2917 space_to_write = len - pst->st_ex_size;
2919 /* for allocation try fallocate first. This can fail on some
2920 platforms e.g. when the filesystem doesn't support it and no
2921 emulation is being done by the libc (like on AIX with JFS1). In that
2922 case we do our own emulation. fallocate implementations can
2923 return ENOTSUP or EINVAL in cases like that. */
2924 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2925 if (ret == -1 && errno == ENOSPC) {
2926 return -1;
2928 if (ret == 0) {
2929 return 0;
2931 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2932 "error %d. Falling back to slow manual allocation\n", errno);
2934 /* available disk space is enough or not? */
2935 space_avail =
2936 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2937 /* space_avail is 1k blocks */
2938 if (space_avail == (uint64_t)-1 ||
2939 ((uint64_t)space_to_write/1024 > space_avail) ) {
2940 errno = ENOSPC;
2941 return -1;
2944 /* Write out the real space on disk. */
2945 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2946 if (ret != 0) {
2947 return -1;
2950 return 0;
2953 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2955 int result = -1;
2956 SMB_STRUCT_STAT *pst;
2957 NTSTATUS status;
2958 char c = 0;
2960 START_PROFILE(syscall_ftruncate);
2962 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2963 result = strict_allocate_ftruncate(handle, fsp, len);
2964 END_PROFILE(syscall_ftruncate);
2965 return result;
2968 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2969 ftruncate if the system supports it. Then I discovered that
2970 you can have some filesystems that support ftruncate
2971 expansion and some that don't! On Linux fat can't do
2972 ftruncate extend but ext2 can. */
2974 result = ftruncate(fsp_get_io_fd(fsp), len);
2976 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2977 extend a file with ftruncate. Provide alternate implementation
2978 for this */
2980 /* Do an fstat to see if the file is longer than the requested
2981 size in which case the ftruncate above should have
2982 succeeded or shorter, in which case seek to len - 1 and
2983 write 1 byte of zero */
2984 status = vfs_stat_fsp(fsp);
2985 if (!NT_STATUS_IS_OK(status)) {
2986 goto done;
2989 /* We need to update the files_struct after successful ftruncate */
2990 if (result == 0) {
2991 goto done;
2994 pst = &fsp->fsp_name->st;
2996 #ifdef S_ISFIFO
2997 if (S_ISFIFO(pst->st_ex_mode)) {
2998 result = 0;
2999 goto done;
3001 #endif
3003 if (pst->st_ex_size == len) {
3004 result = 0;
3005 goto done;
3008 if (pst->st_ex_size > len) {
3009 /* the ftruncate should have worked */
3010 goto done;
3013 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3014 goto done;
3017 result = 0;
3019 done:
3021 END_PROFILE(syscall_ftruncate);
3022 return result;
3025 static int vfswrap_fallocate(vfs_handle_struct *handle,
3026 files_struct *fsp,
3027 uint32_t mode,
3028 off_t offset,
3029 off_t len)
3031 int result;
3033 START_PROFILE(syscall_fallocate);
3034 if (mode == 0) {
3035 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3037 * posix_fallocate returns 0 on success, errno on error
3038 * and doesn't set errno. Make it behave like fallocate()
3039 * which returns -1, and sets errno on failure.
3041 if (result != 0) {
3042 errno = result;
3043 result = -1;
3045 } else {
3046 /* sys_fallocate handles filtering of unsupported mode flags */
3047 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3049 END_PROFILE(syscall_fallocate);
3050 return result;
3053 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3055 bool result;
3057 START_PROFILE(syscall_fcntl_lock);
3059 if (fsp->fsp_flags.use_ofd_locks) {
3060 op = map_process_lock_to_ofd_lock(op);
3063 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3064 END_PROFILE(syscall_fcntl_lock);
3065 return result;
3068 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3069 files_struct *fsp,
3070 uint32_t share_access,
3071 uint32_t access_mask)
3073 errno = ENOTSUP;
3074 return -1;
3077 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3078 va_list cmd_arg)
3080 void *argp;
3081 va_list dup_cmd_arg;
3082 int result;
3083 int val;
3085 START_PROFILE(syscall_fcntl);
3087 va_copy(dup_cmd_arg, cmd_arg);
3089 switch(cmd) {
3090 case F_SETLK:
3091 case F_SETLKW:
3092 case F_GETLK:
3093 #if defined(HAVE_OFD_LOCKS)
3094 case F_OFD_SETLK:
3095 case F_OFD_SETLKW:
3096 case F_OFD_GETLK:
3097 #endif
3098 #if defined(HAVE_F_OWNER_EX)
3099 case F_GETOWN_EX:
3100 case F_SETOWN_EX:
3101 #endif
3102 #if defined(HAVE_RW_HINTS)
3103 case F_GET_RW_HINT:
3104 case F_SET_RW_HINT:
3105 case F_GET_FILE_RW_HINT:
3106 case F_SET_FILE_RW_HINT:
3107 #endif
3108 argp = va_arg(dup_cmd_arg, void *);
3109 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3110 break;
3111 default:
3112 val = va_arg(dup_cmd_arg, int);
3113 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3116 va_end(dup_cmd_arg);
3118 END_PROFILE(syscall_fcntl);
3119 return result;
3122 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3124 bool result;
3125 int op = F_GETLK;
3127 START_PROFILE(syscall_fcntl_getlock);
3129 if (fsp->fsp_flags.use_ofd_locks) {
3130 op = map_process_lock_to_ofd_lock(op);
3133 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3134 END_PROFILE(syscall_fcntl_getlock);
3135 return result;
3138 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3139 int leasetype)
3141 int result = -1;
3143 START_PROFILE(syscall_linux_setlease);
3145 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3147 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3148 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3149 #else
3150 errno = ENOSYS;
3151 #endif
3152 END_PROFILE(syscall_linux_setlease);
3153 return result;
3156 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3157 const struct smb_filename *link_target,
3158 struct files_struct *dirfsp,
3159 const struct smb_filename *new_smb_fname)
3161 int result;
3163 START_PROFILE(syscall_symlinkat);
3165 SMB_ASSERT(!is_named_stream(new_smb_fname));
3167 result = symlinkat(link_target->base_name,
3168 fsp_get_pathref_fd(dirfsp),
3169 new_smb_fname->base_name);
3170 END_PROFILE(syscall_symlinkat);
3171 return result;
3174 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3175 const struct files_struct *dirfsp,
3176 const struct smb_filename *smb_fname,
3177 char *buf,
3178 size_t bufsiz)
3180 int result;
3182 START_PROFILE(syscall_readlinkat);
3184 SMB_ASSERT(!is_named_stream(smb_fname));
3186 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3187 smb_fname->base_name,
3188 buf,
3189 bufsiz);
3191 END_PROFILE(syscall_readlinkat);
3192 return result;
3195 static int vfswrap_linkat(vfs_handle_struct *handle,
3196 files_struct *srcfsp,
3197 const struct smb_filename *old_smb_fname,
3198 files_struct *dstfsp,
3199 const struct smb_filename *new_smb_fname,
3200 int flags)
3202 int result;
3204 START_PROFILE(syscall_linkat);
3206 SMB_ASSERT(!is_named_stream(old_smb_fname));
3207 SMB_ASSERT(!is_named_stream(new_smb_fname));
3209 result = linkat(fsp_get_pathref_fd(srcfsp),
3210 old_smb_fname->base_name,
3211 fsp_get_pathref_fd(dstfsp),
3212 new_smb_fname->base_name,
3213 flags);
3215 END_PROFILE(syscall_linkat);
3216 return result;
3219 static int vfswrap_mknodat(vfs_handle_struct *handle,
3220 files_struct *dirfsp,
3221 const struct smb_filename *smb_fname,
3222 mode_t mode,
3223 SMB_DEV_T dev)
3225 int result;
3227 START_PROFILE(syscall_mknodat);
3229 SMB_ASSERT(!is_named_stream(smb_fname));
3231 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3232 smb_fname->base_name,
3233 mode,
3234 dev);
3236 END_PROFILE(syscall_mknodat);
3237 return result;
3240 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3241 TALLOC_CTX *ctx,
3242 const struct smb_filename *smb_fname)
3244 char *result;
3245 struct smb_filename *result_fname = NULL;
3247 START_PROFILE(syscall_realpath);
3248 result = sys_realpath(smb_fname->base_name);
3249 END_PROFILE(syscall_realpath);
3250 if (result) {
3251 result_fname = synthetic_smb_fname(ctx,
3252 result,
3253 NULL,
3254 NULL,
3257 SAFE_FREE(result);
3259 return result_fname;
3262 static int vfswrap_fchflags(vfs_handle_struct *handle,
3263 struct files_struct *fsp,
3264 unsigned int flags)
3266 #ifdef HAVE_FCHFLAGS
3267 int fd = fsp_get_pathref_fd(fsp);
3269 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3271 if (!fsp->fsp_flags.is_pathref) {
3272 return fchflags(fd, flags);
3275 if (fsp->fsp_flags.have_proc_fds) {
3276 const char *p = NULL;
3277 char buf[PATH_MAX];
3279 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3280 if (p == NULL) {
3281 return -1;
3284 return chflags(p, flags);
3288 * This is no longer a handle based call.
3290 return chflags(fsp->fsp_name->base_name, flags);
3291 #else
3292 errno = ENOSYS;
3293 return -1;
3294 #endif
3297 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3298 const SMB_STRUCT_STAT *sbuf)
3300 struct file_id key;
3302 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3303 * blob */
3304 ZERO_STRUCT(key);
3306 key.devid = sbuf->st_ex_dev;
3307 key.inode = sbuf->st_ex_ino;
3308 /* key.extid is unused by default. */
3310 return key;
3313 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3314 const SMB_STRUCT_STAT *psbuf)
3316 uint64_t file_id;
3318 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3319 return (uint64_t)psbuf->st_ex_ino;
3322 /* FileIDLow */
3323 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3325 /* FileIDHigh */
3326 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3328 return file_id;
3331 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3332 struct files_struct *fsp,
3333 TALLOC_CTX *mem_ctx,
3334 unsigned int *pnum_streams,
3335 struct stream_struct **pstreams)
3337 struct stream_struct *tmp_streams = NULL;
3338 unsigned int num_streams = *pnum_streams;
3339 struct stream_struct *streams = *pstreams;
3340 NTSTATUS status;
3342 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3344 if (fsp->fsp_flags.is_directory) {
3346 * No default streams on directories
3348 goto done;
3350 status = vfs_stat_fsp(fsp);
3351 if (!NT_STATUS_IS_OK(status)) {
3352 return status;
3355 if (num_streams + 1 < 1) {
3356 /* Integer wrap. */
3357 return NT_STATUS_INVALID_PARAMETER;
3360 tmp_streams = talloc_realloc(mem_ctx,
3361 streams,
3362 struct stream_struct,
3363 num_streams + 1);
3364 if (tmp_streams == NULL) {
3365 return NT_STATUS_NO_MEMORY;
3367 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3368 if (tmp_streams[num_streams].name == NULL) {
3369 return NT_STATUS_NO_MEMORY;
3371 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3372 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3373 handle->conn,
3374 fsp,
3375 &fsp->fsp_name->st);
3376 num_streams += 1;
3378 *pnum_streams = num_streams;
3379 *pstreams = tmp_streams;
3380 done:
3381 return NT_STATUS_OK;
3384 static NTSTATUS vfswrap_get_real_filename_at(
3385 struct vfs_handle_struct *handle,
3386 struct files_struct *dirfsp,
3387 const char *name,
3388 TALLOC_CTX *mem_ctx,
3389 char **found_name)
3392 * Don't fall back to get_real_filename so callers can differentiate
3393 * between a full directory scan and an actual case-insensitive stat.
3395 return NT_STATUS_NOT_SUPPORTED;
3398 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3399 const struct files_struct *dirfsp,
3400 const struct smb_filename *smb_fname)
3402 return handle->conn->connectpath;
3405 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3406 struct byte_range_lock *br_lck,
3407 struct lock_struct *plock)
3409 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3411 /* Note: blr is not used in the default implementation. */
3412 return brl_lock_windows_default(br_lck, plock);
3415 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3416 struct byte_range_lock *br_lck,
3417 const struct lock_struct *plock)
3419 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3421 return brl_unlock_windows_default(br_lck, plock);
3424 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3425 files_struct *fsp,
3426 struct lock_struct *plock)
3428 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3429 plock->lock_type == WRITE_LOCK);
3431 return strict_lock_check_default(fsp, plock);
3434 /* NT ACL operations. */
3436 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3437 files_struct *fsp,
3438 uint32_t security_info,
3439 TALLOC_CTX *mem_ctx,
3440 struct security_descriptor **ppdesc)
3442 NTSTATUS result;
3444 START_PROFILE(fget_nt_acl);
3446 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3448 result = posix_fget_nt_acl(fsp, security_info,
3449 mem_ctx, ppdesc);
3450 END_PROFILE(fget_nt_acl);
3451 return result;
3454 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3456 NTSTATUS result;
3458 START_PROFILE(fset_nt_acl);
3460 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3462 result = set_nt_acl(fsp, security_info_sent, psd);
3463 END_PROFILE(fset_nt_acl);
3464 return result;
3467 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3468 struct smb_filename *file,
3469 struct security_acl *sacl,
3470 uint32_t access_requested,
3471 uint32_t access_denied)
3473 return NT_STATUS_OK; /* Nothing to do here ... */
3476 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3477 files_struct *fsp,
3478 SMB_ACL_TYPE_T type,
3479 TALLOC_CTX *mem_ctx)
3481 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3483 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3486 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3487 files_struct *fsp,
3488 SMB_ACL_TYPE_T type,
3489 SMB_ACL_T theacl)
3491 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3493 return sys_acl_set_fd(handle, fsp, type, theacl);
3496 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3497 files_struct *fsp)
3499 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3501 return sys_acl_delete_def_fd(handle, fsp);
3504 /****************************************************************
3505 Extended attribute operations.
3506 *****************************************************************/
3508 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3509 struct files_struct *fsp,
3510 const char *name,
3511 void *value,
3512 size_t size)
3514 int fd = fsp_get_pathref_fd(fsp);
3516 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3518 if (!fsp->fsp_flags.is_pathref) {
3519 return fgetxattr(fd, name, value, size);
3522 if (fsp->fsp_flags.have_proc_fds) {
3523 const char *p = NULL;
3524 char buf[PATH_MAX];
3526 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3527 if (p == NULL) {
3528 return -1;
3531 return getxattr(p, name, value, size);
3535 * This is no longer a handle based call.
3537 return getxattr(fsp->fsp_name->base_name, name, value, size);
3540 struct vfswrap_getxattrat_state {
3541 struct tevent_context *ev;
3542 struct vfs_handle_struct *handle;
3543 files_struct *dir_fsp;
3544 const struct smb_filename *smb_fname;
3547 * The following variables are talloced off "state" which is protected
3548 * by a destructor and thus are guaranteed to be safe to be used in the
3549 * job function in the worker thread.
3551 char *name;
3552 const char *xattr_name;
3553 uint8_t *xattr_value;
3554 struct security_unix_token *token;
3556 ssize_t xattr_size;
3557 struct vfs_aio_state vfs_aio_state;
3558 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3561 static int vfswrap_getxattrat_state_destructor(
3562 struct vfswrap_getxattrat_state *state)
3564 return -1;
3567 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3568 static void vfswrap_getxattrat_do_async(void *private_data);
3569 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3571 static struct tevent_req *vfswrap_getxattrat_send(
3572 TALLOC_CTX *mem_ctx,
3573 struct tevent_context *ev,
3574 struct vfs_handle_struct *handle,
3575 files_struct *dir_fsp,
3576 const struct smb_filename *smb_fname,
3577 const char *xattr_name,
3578 size_t alloc_hint)
3580 struct tevent_req *req = NULL;
3581 struct tevent_req *subreq = NULL;
3582 struct vfswrap_getxattrat_state *state = NULL;
3583 size_t max_threads = 0;
3584 bool have_per_thread_cwd = false;
3585 bool have_per_thread_creds = false;
3586 bool do_async = false;
3588 SMB_ASSERT(!is_named_stream(smb_fname));
3590 req = tevent_req_create(mem_ctx, &state,
3591 struct vfswrap_getxattrat_state);
3592 if (req == NULL) {
3593 return NULL;
3595 *state = (struct vfswrap_getxattrat_state) {
3596 .ev = ev,
3597 .handle = handle,
3598 .dir_fsp = dir_fsp,
3599 .smb_fname = smb_fname,
3602 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3603 if (max_threads >= 1) {
3605 * We need a non sync threadpool!
3607 have_per_thread_cwd = per_thread_cwd_supported();
3609 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3610 have_per_thread_creds = true;
3611 #endif
3612 if (have_per_thread_cwd && have_per_thread_creds) {
3613 do_async = true;
3616 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3617 state->profile_bytes, 0);
3619 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3620 DBG_ERR("Need a valid directory fd\n");
3621 tevent_req_error(req, EINVAL);
3622 return tevent_req_post(req, ev);
3625 if (alloc_hint > 0) {
3626 state->xattr_value = talloc_zero_array(state,
3627 uint8_t,
3628 alloc_hint);
3629 if (tevent_req_nomem(state->xattr_value, req)) {
3630 return tevent_req_post(req, ev);
3634 if (!do_async) {
3635 vfswrap_getxattrat_do_sync(req);
3636 return tevent_req_post(req, ev);
3640 * Now allocate all parameters from a memory context that won't go away
3641 * no matter what. These parameters will get used in threads and we
3642 * can't reliably cancel threads, so all buffers passed to the threads
3643 * must not be freed before all referencing threads terminate.
3646 state->name = talloc_strdup(state, smb_fname->base_name);
3647 if (tevent_req_nomem(state->name, req)) {
3648 return tevent_req_post(req, ev);
3651 state->xattr_name = talloc_strdup(state, xattr_name);
3652 if (tevent_req_nomem(state->xattr_name, req)) {
3653 return tevent_req_post(req, ev);
3657 * This is a hot codepath so at first glance one might think we should
3658 * somehow optimize away the token allocation and do a
3659 * talloc_reference() or similar black magic instead. But due to the
3660 * talloc_stackframe pool per SMB2 request this should be a simple copy
3661 * without a malloc in most cases.
3663 if (geteuid() == sec_initial_uid()) {
3664 state->token = root_unix_token(state);
3665 } else {
3666 state->token = copy_unix_token(
3667 state,
3668 dir_fsp->conn->session_info->unix_token);
3670 if (tevent_req_nomem(state->token, req)) {
3671 return tevent_req_post(req, ev);
3674 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3676 subreq = pthreadpool_tevent_job_send(
3677 state,
3679 dir_fsp->conn->sconn->pool,
3680 vfswrap_getxattrat_do_async,
3681 state);
3682 if (tevent_req_nomem(subreq, req)) {
3683 return tevent_req_post(req, ev);
3685 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3687 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3689 return req;
3692 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3694 struct vfswrap_getxattrat_state *state = tevent_req_data(
3695 req, struct vfswrap_getxattrat_state);
3697 state->xattr_size = vfswrap_fgetxattr(state->handle,
3698 state->smb_fname->fsp,
3699 state->xattr_name,
3700 state->xattr_value,
3701 talloc_array_length(state->xattr_value));
3702 if (state->xattr_size == -1) {
3703 tevent_req_error(req, errno);
3704 return;
3707 tevent_req_done(req);
3708 return;
3711 static void vfswrap_getxattrat_do_async(void *private_data)
3713 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3714 private_data, struct vfswrap_getxattrat_state);
3715 struct timespec start_time;
3716 struct timespec end_time;
3717 int ret;
3719 PROFILE_TIMESTAMP(&start_time);
3720 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3723 * Here we simulate a getxattrat()
3724 * call using fchdir();getxattr()
3727 per_thread_cwd_activate();
3729 /* Become the correct credential on this thread. */
3730 ret = set_thread_credentials(state->token->uid,
3731 state->token->gid,
3732 (size_t)state->token->ngroups,
3733 state->token->groups);
3734 if (ret != 0) {
3735 state->xattr_size = -1;
3736 state->vfs_aio_state.error = errno;
3737 goto end_profile;
3740 state->xattr_size = vfswrap_fgetxattr(state->handle,
3741 state->smb_fname->fsp,
3742 state->xattr_name,
3743 state->xattr_value,
3744 talloc_array_length(state->xattr_value));
3745 if (state->xattr_size == -1) {
3746 state->vfs_aio_state.error = errno;
3749 end_profile:
3750 PROFILE_TIMESTAMP(&end_time);
3751 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3752 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3755 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3757 struct tevent_req *req = tevent_req_callback_data(
3758 subreq, struct tevent_req);
3759 struct vfswrap_getxattrat_state *state = tevent_req_data(
3760 req, struct vfswrap_getxattrat_state);
3761 int ret;
3762 bool ok;
3765 * Make sure we run as the user again
3767 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3768 SMB_ASSERT(ok);
3770 ret = pthreadpool_tevent_job_recv(subreq);
3771 TALLOC_FREE(subreq);
3772 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3773 talloc_set_destructor(state, NULL);
3774 if (ret != 0) {
3775 if (ret != EAGAIN) {
3776 tevent_req_error(req, ret);
3777 return;
3780 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3781 * means the lower level pthreadpool failed to create a new
3782 * thread. Fallback to sync processing in that case to allow
3783 * some progress for the client.
3785 vfswrap_getxattrat_do_sync(req);
3786 return;
3789 if (state->xattr_size == -1) {
3790 tevent_req_error(req, state->vfs_aio_state.error);
3791 return;
3794 if (state->xattr_value == NULL) {
3796 * The caller only wanted the size.
3798 tevent_req_done(req);
3799 return;
3803 * shrink the buffer to the returned size.
3804 * (can't fail). It means NULL if size is 0.
3806 state->xattr_value = talloc_realloc(state,
3807 state->xattr_value,
3808 uint8_t,
3809 state->xattr_size);
3811 tevent_req_done(req);
3814 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3815 struct vfs_aio_state *aio_state,
3816 TALLOC_CTX *mem_ctx,
3817 uint8_t **xattr_value)
3819 struct vfswrap_getxattrat_state *state = tevent_req_data(
3820 req, struct vfswrap_getxattrat_state);
3821 ssize_t xattr_size;
3823 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3824 tevent_req_received(req);
3825 return -1;
3828 *aio_state = state->vfs_aio_state;
3829 xattr_size = state->xattr_size;
3830 if (xattr_value != NULL) {
3831 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3834 tevent_req_received(req);
3835 return xattr_size;
3838 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3840 int fd = fsp_get_pathref_fd(fsp);
3842 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3844 if (!fsp->fsp_flags.is_pathref) {
3845 return flistxattr(fd, list, size);
3848 if (fsp->fsp_flags.have_proc_fds) {
3849 const char *p = NULL;
3850 char buf[PATH_MAX];
3852 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3853 if (p == NULL) {
3854 return -1;
3857 return listxattr(p, list, size);
3861 * This is no longer a handle based call.
3863 return listxattr(fsp->fsp_name->base_name, list, size);
3866 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3868 int fd = fsp_get_pathref_fd(fsp);
3870 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3872 if (!fsp->fsp_flags.is_pathref) {
3873 return fremovexattr(fd, name);
3876 if (fsp->fsp_flags.have_proc_fds) {
3877 const char *p = NULL;
3878 char buf[PATH_MAX];
3880 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3881 if (p == NULL) {
3882 return -1;
3885 return removexattr(p, name);
3889 * This is no longer a handle based call.
3891 return removexattr(fsp->fsp_name->base_name, name);
3894 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3896 int fd = fsp_get_pathref_fd(fsp);
3898 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3900 if (!fsp->fsp_flags.is_pathref) {
3901 return fsetxattr(fd, name, value, size, flags);
3904 if (fsp->fsp_flags.have_proc_fds) {
3905 const char *p = NULL;
3906 char buf[PATH_MAX];
3908 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3909 if (p == NULL) {
3910 return -1;
3913 return setxattr(p, name, value, size, flags);
3917 * This is no longer a handle based call.
3919 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3922 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3924 return false;
3927 static bool vfswrap_is_offline(struct connection_struct *conn,
3928 const struct smb_filename *fname)
3930 NTSTATUS status;
3931 char *path;
3932 bool offline = false;
3934 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3935 return false;
3938 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3939 #if defined(ENOTSUP)
3940 errno = ENOTSUP;
3941 #endif
3942 return false;
3945 status = get_full_smb_filename(talloc_tos(), fname, &path);
3946 if (!NT_STATUS_IS_OK(status)) {
3947 errno = map_errno_from_nt_status(status);
3948 return false;
3951 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3953 TALLOC_FREE(path);
3955 return offline;
3958 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3959 struct files_struct *fsp,
3960 TALLOC_CTX *mem_ctx,
3961 DATA_BLOB *cookie)
3963 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3966 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3967 struct files_struct *fsp,
3968 const DATA_BLOB old_cookie,
3969 TALLOC_CTX *mem_ctx,
3970 DATA_BLOB *new_cookie)
3972 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3973 new_cookie);
3976 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3977 struct smb_request *smb1req,
3978 struct smbXsrv_open *op,
3979 const DATA_BLOB old_cookie,
3980 TALLOC_CTX *mem_ctx,
3981 struct files_struct **fsp,
3982 DATA_BLOB *new_cookie)
3984 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3985 old_cookie, mem_ctx,
3986 fsp, new_cookie);
3989 static struct vfs_fn_pointers vfs_default_fns = {
3990 /* Disk operations */
3992 .connect_fn = vfswrap_connect,
3993 .disconnect_fn = vfswrap_disconnect,
3994 .disk_free_fn = vfswrap_disk_free,
3995 .get_quota_fn = vfswrap_get_quota,
3996 .set_quota_fn = vfswrap_set_quota,
3997 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3998 .statvfs_fn = vfswrap_statvfs,
3999 .fs_capabilities_fn = vfswrap_fs_capabilities,
4000 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
4001 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
4002 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
4003 .snap_check_path_fn = vfswrap_snap_check_path,
4004 .snap_create_fn = vfswrap_snap_create,
4005 .snap_delete_fn = vfswrap_snap_delete,
4007 /* Directory operations */
4009 .fdopendir_fn = vfswrap_fdopendir,
4010 .readdir_fn = vfswrap_readdir,
4011 .freaddir_attr_fn = vfswrap_freaddir_attr,
4012 .rewind_dir_fn = vfswrap_rewinddir,
4013 .mkdirat_fn = vfswrap_mkdirat,
4014 .closedir_fn = vfswrap_closedir,
4016 /* File operations */
4018 .openat_fn = vfswrap_openat,
4019 .create_file_fn = vfswrap_create_file,
4020 .close_fn = vfswrap_close,
4021 .pread_fn = vfswrap_pread,
4022 .pread_send_fn = vfswrap_pread_send,
4023 .pread_recv_fn = vfswrap_pread_recv,
4024 .pwrite_fn = vfswrap_pwrite,
4025 .pwrite_send_fn = vfswrap_pwrite_send,
4026 .pwrite_recv_fn = vfswrap_pwrite_recv,
4027 .lseek_fn = vfswrap_lseek,
4028 .sendfile_fn = vfswrap_sendfile,
4029 .recvfile_fn = vfswrap_recvfile,
4030 .renameat_fn = vfswrap_renameat,
4031 .fsync_send_fn = vfswrap_fsync_send,
4032 .fsync_recv_fn = vfswrap_fsync_recv,
4033 .stat_fn = vfswrap_stat,
4034 .fstat_fn = vfswrap_fstat,
4035 .lstat_fn = vfswrap_lstat,
4036 .fstatat_fn = vfswrap_fstatat,
4037 .get_alloc_size_fn = vfswrap_get_alloc_size,
4038 .unlinkat_fn = vfswrap_unlinkat,
4039 .fchmod_fn = vfswrap_fchmod,
4040 .fchown_fn = vfswrap_fchown,
4041 .lchown_fn = vfswrap_lchown,
4042 .chdir_fn = vfswrap_chdir,
4043 .getwd_fn = vfswrap_getwd,
4044 .fntimes_fn = vfswrap_fntimes,
4045 .ftruncate_fn = vfswrap_ftruncate,
4046 .fallocate_fn = vfswrap_fallocate,
4047 .lock_fn = vfswrap_lock,
4048 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4049 .fcntl_fn = vfswrap_fcntl,
4050 .linux_setlease_fn = vfswrap_linux_setlease,
4051 .getlock_fn = vfswrap_getlock,
4052 .symlinkat_fn = vfswrap_symlinkat,
4053 .readlinkat_fn = vfswrap_readlinkat,
4054 .linkat_fn = vfswrap_linkat,
4055 .mknodat_fn = vfswrap_mknodat,
4056 .realpath_fn = vfswrap_realpath,
4057 .fchflags_fn = vfswrap_fchflags,
4058 .file_id_create_fn = vfswrap_file_id_create,
4059 .fs_file_id_fn = vfswrap_fs_file_id,
4060 .fstreaminfo_fn = vfswrap_fstreaminfo,
4061 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4062 .connectpath_fn = vfswrap_connectpath,
4063 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4064 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4065 .strict_lock_check_fn = vfswrap_strict_lock_check,
4066 .translate_name_fn = vfswrap_translate_name,
4067 .parent_pathname_fn = vfswrap_parent_pathname,
4068 .fsctl_fn = vfswrap_fsctl,
4069 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4070 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4071 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4072 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4073 .offload_read_send_fn = vfswrap_offload_read_send,
4074 .offload_read_recv_fn = vfswrap_offload_read_recv,
4075 .offload_write_send_fn = vfswrap_offload_write_send,
4076 .offload_write_recv_fn = vfswrap_offload_write_recv,
4077 .fget_compression_fn = vfswrap_fget_compression,
4078 .set_compression_fn = vfswrap_set_compression,
4080 /* NT ACL operations. */
4082 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4083 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4084 .audit_file_fn = vfswrap_audit_file,
4086 /* POSIX ACL operations. */
4088 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4089 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4090 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4091 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4093 /* EA operations. */
4094 .getxattrat_send_fn = vfswrap_getxattrat_send,
4095 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4096 .fgetxattr_fn = vfswrap_fgetxattr,
4097 .flistxattr_fn = vfswrap_flistxattr,
4098 .fremovexattr_fn = vfswrap_fremovexattr,
4099 .fsetxattr_fn = vfswrap_fsetxattr,
4101 /* aio operations */
4102 .aio_force_fn = vfswrap_aio_force,
4104 /* durable handle operations */
4105 .durable_cookie_fn = vfswrap_durable_cookie,
4106 .durable_disconnect_fn = vfswrap_durable_disconnect,
4107 .durable_reconnect_fn = vfswrap_durable_reconnect,
4110 static_decl_vfs;
4111 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4114 * Here we need to implement every call!
4116 * As this is the end of the vfs module chain.
4118 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4119 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4120 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);