s3:utils: let smbstatus report anonymous signing/encryption explicitly
[Samba.git] / source3 / modules / vfs_default.c
blob48b5dd9e39f46b178ba734651a8cf25242839358
1 /*
2 Unix SMB/CIFS implementation.
3 Wrap disk only vfs functions to sidestep dodgy compilers.
4 Copyright (C) Tim Potter 1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "ntioctl.h"
27 #include "smbprofile.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/lookup_sid.h"
30 #include "source3/include/msdfs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "lib/util/sys_rw.h"
35 #include "lib/pthreadpool/pthreadpool_tevent.h"
36 #include "librpc/gen_ndr/ndr_ioctl.h"
37 #include "offload_token.h"
38 #include "util_reparse.h"
39 #include "lib/util/string_wrappers.h"
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_VFS
44 /* Check for NULL pointer parameters in vfswrap_* functions */
46 /* We don't want to have NULL function pointers lying around. Someone
47 is sure to try and execute them. These stubs are used to prevent
48 this possibility. */
50 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
52 bool bval;
54 handle->conn->have_proc_fds = sys_have_proc_fds();
55 #ifdef DISABLE_PROC_FDS
56 handle->conn->have_proc_fds = false;
57 #endif
60 * assume the kernel will support openat2(),
61 * it will be reset on the first ENOSYS.
63 * Note that libreplace will always provide openat2(),
64 * but return -1/errno = ENOSYS...
66 * The option is only there to test the fallback code.
68 bval = lp_parm_bool(SNUM(handle->conn),
69 "vfs_default",
70 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
71 true);
72 if (bval) {
73 handle->conn->open_how_resolve |=
74 VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
76 #ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
77 handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
78 #endif
80 return 0; /* Return >= 0 for success */
83 static void vfswrap_disconnect(vfs_handle_struct *handle)
87 /* Disk operations */
89 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
90 const struct smb_filename *smb_fname,
91 uint64_t *bsize,
92 uint64_t *dfree,
93 uint64_t *dsize)
95 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
96 return (uint64_t)-1;
99 *bsize = 512;
100 return *dfree / 2;
103 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
104 const struct smb_filename *smb_fname,
105 enum SMB_QUOTA_TYPE qtype,
106 unid_t id,
107 SMB_DISK_QUOTA *qt)
109 #ifdef HAVE_SYS_QUOTAS
110 int result;
112 START_PROFILE(syscall_get_quota);
113 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
114 END_PROFILE(syscall_get_quota);
115 return result;
116 #else
117 errno = ENOSYS;
118 return -1;
119 #endif
122 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
124 #ifdef HAVE_SYS_QUOTAS
125 int result;
127 START_PROFILE(syscall_set_quota);
128 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
129 END_PROFILE(syscall_set_quota);
130 return result;
131 #else
132 errno = ENOSYS;
133 return -1;
134 #endif
137 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
138 struct files_struct *fsp,
139 struct shadow_copy_data *shadow_copy_data,
140 bool labels)
142 errno = ENOSYS;
143 return -1; /* Not implemented. */
146 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
147 const struct smb_filename *smb_fname,
148 struct vfs_statvfs_struct *statbuf)
150 return sys_statvfs(smb_fname->base_name, statbuf);
153 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
154 enum timestamp_set_resolution *p_ts_res)
156 const struct loadparm_substitution *lp_sub =
157 loadparm_s3_global_substitution();
158 connection_struct *conn = handle->conn;
159 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
160 struct smb_filename *smb_fname_cpath = NULL;
161 struct vfs_statvfs_struct statbuf;
162 int ret;
164 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
165 conn->connectpath,
166 NULL,
167 NULL,
170 if (smb_fname_cpath == NULL) {
171 return caps;
174 ZERO_STRUCT(statbuf);
175 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
176 if (ret == 0) {
177 caps = statbuf.FsCapabilities;
180 *p_ts_res = TIMESTAMP_SET_SECONDS;
182 /* Work out what timestamp resolution we can
183 * use when setting a timestamp. */
185 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
186 if (ret == -1) {
187 TALLOC_FREE(smb_fname_cpath);
188 return caps;
191 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
192 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
193 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
194 /* If any of the normal UNIX directory timestamps
195 * have a non-zero tv_nsec component assume
196 * we might be able to set sub-second timestamps.
197 * See what filetime set primitives we have.
199 #if defined(HAVE_UTIMENSAT)
200 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
201 #elif defined(HAVE_UTIMES)
202 /* utimes allows msec timestamps to be set. */
203 *p_ts_res = TIMESTAMP_SET_MSEC;
204 #elif defined(HAVE_UTIME)
205 /* utime only allows sec timestamps to be set. */
206 *p_ts_res = TIMESTAMP_SET_SECONDS;
207 #endif
209 DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
210 "resolution of %s "
211 "available on share %s, directory %s\n",
212 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
213 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
214 conn->connectpath );
216 TALLOC_FREE(smb_fname_cpath);
217 return caps;
220 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
221 struct dfs_GetDFSReferral *r)
223 struct junction_map *junction = NULL;
224 size_t consumedcnt = 0;
225 bool self_referral = false;
226 char *pathnamep = NULL;
227 char *local_dfs_path = NULL;
228 NTSTATUS status;
229 size_t i;
230 uint16_t max_referral_level = r->in.req.max_referral_level;
232 if (DEBUGLVL(DBGLVL_DEBUG)) {
233 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
236 /* get the junction entry */
237 if (r->in.req.servername == NULL) {
238 return NT_STATUS_NOT_FOUND;
242 * Trim pathname sent by client so it begins with only one backslash.
243 * Two backslashes confuse some dfs clients
246 local_dfs_path = talloc_strdup(r, r->in.req.servername);
247 if (local_dfs_path == NULL) {
248 return NT_STATUS_NO_MEMORY;
250 pathnamep = local_dfs_path;
251 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
252 IS_DIRECTORY_SEP(pathnamep[1])) {
253 pathnamep++;
256 junction = talloc_zero(r, struct junction_map);
257 if (junction == NULL) {
258 return NT_STATUS_NO_MEMORY;
261 /* The following call can change cwd. */
262 status = get_referred_path(r,
263 handle->conn->session_info,
264 pathnamep,
265 handle->conn->sconn->remote_address,
266 handle->conn->sconn->local_address,
267 junction, &consumedcnt, &self_referral);
268 if (!NT_STATUS_IS_OK(status)) {
269 struct smb_filename connectpath_fname = {
270 .base_name = handle->conn->connectpath
272 vfs_ChDir(handle->conn, &connectpath_fname);
273 return status;
276 struct smb_filename connectpath_fname = {
277 .base_name = handle->conn->connectpath
279 vfs_ChDir(handle->conn, &connectpath_fname);
282 if (!self_referral) {
283 pathnamep[consumedcnt] = '\0';
285 if (DEBUGLVL(DBGLVL_INFO)) {
286 dbgtext("Path %s to alternate path(s):",
287 pathnamep);
288 for (i=0; i < junction->referral_count; i++) {
289 dbgtext(" %s",
290 junction->referral_list[i].alternate_path);
292 dbgtext(".\n");
296 if (r->in.req.max_referral_level <= 2) {
297 max_referral_level = 2;
299 if (r->in.req.max_referral_level >= 3) {
300 max_referral_level = 3;
303 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
304 if (r->out.resp == NULL) {
305 return NT_STATUS_NO_MEMORY;
308 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
309 r->out.resp->nb_referrals = junction->referral_count;
311 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
312 if (self_referral) {
313 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
316 r->out.resp->referral_entries = talloc_zero_array(r,
317 struct dfs_referral_type,
318 r->out.resp->nb_referrals);
319 if (r->out.resp->referral_entries == NULL) {
320 return NT_STATUS_NO_MEMORY;
323 switch (max_referral_level) {
324 case 2:
325 for(i=0; i < junction->referral_count; i++) {
326 struct referral *ref = &junction->referral_list[i];
327 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
328 struct dfs_referral_type *t =
329 &r->out.resp->referral_entries[i];
330 struct dfs_referral_v2 *v2 = &t->referral.v2;
332 t->version = 2;
333 v2->size = VERSION2_REFERRAL_SIZE;
334 if (self_referral) {
335 v2->server_type = DFS_SERVER_ROOT;
336 } else {
337 v2->server_type = DFS_SERVER_NON_ROOT;
339 v2->entry_flags = 0;
340 v2->proximity = ref->proximity;
341 v2->ttl = ref->ttl;
342 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
343 if (v2->DFS_path == NULL) {
344 return NT_STATUS_NO_MEMORY;
346 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
347 if (v2->DFS_alt_path == NULL) {
348 return NT_STATUS_NO_MEMORY;
350 v2->netw_address = talloc_strdup(mem_ctx,
351 ref->alternate_path);
352 if (v2->netw_address == NULL) {
353 return NT_STATUS_NO_MEMORY;
357 break;
358 case 3:
359 for(i=0; i < junction->referral_count; i++) {
360 struct referral *ref = &junction->referral_list[i];
361 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
362 struct dfs_referral_type *t =
363 &r->out.resp->referral_entries[i];
364 struct dfs_referral_v3 *v3 = &t->referral.v3;
365 struct dfs_normal_referral *r1 = &v3->referrals.r1;
367 t->version = 3;
368 v3->size = VERSION3_REFERRAL_SIZE;
369 if (self_referral) {
370 v3->server_type = DFS_SERVER_ROOT;
371 } else {
372 v3->server_type = DFS_SERVER_NON_ROOT;
374 v3->entry_flags = 0;
375 v3->ttl = ref->ttl;
376 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
377 if (r1->DFS_path == NULL) {
378 return NT_STATUS_NO_MEMORY;
380 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
381 if (r1->DFS_alt_path == NULL) {
382 return NT_STATUS_NO_MEMORY;
384 r1->netw_address = talloc_strdup(mem_ctx,
385 ref->alternate_path);
386 if (r1->netw_address == NULL) {
387 return NT_STATUS_NO_MEMORY;
390 break;
391 default:
392 DBG_ERR("Invalid dfs referral version: %d\n",
393 max_referral_level);
394 return NT_STATUS_INVALID_LEVEL;
397 if (DEBUGLVL(DBGLVL_DEBUG)) {
398 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
401 return NT_STATUS_OK;
404 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
405 struct files_struct *dirfsp,
406 const struct smb_filename *smb_fname,
407 const struct referral *reflist,
408 size_t referral_count)
410 TALLOC_CTX *frame = talloc_stackframe();
411 NTSTATUS status = NT_STATUS_NO_MEMORY;
412 int ret;
413 char *msdfs_link = NULL;
415 /* Form the msdfs_link contents */
416 msdfs_link = msdfs_link_string(frame,
417 reflist,
418 referral_count);
419 if (msdfs_link == NULL) {
420 goto out;
423 ret = symlinkat(msdfs_link,
424 fsp_get_pathref_fd(dirfsp),
425 smb_fname->base_name);
426 if (ret == 0) {
427 status = NT_STATUS_OK;
428 } else {
429 status = map_nt_error_from_unix(errno);
432 out:
434 TALLOC_FREE(frame);
435 return status;
439 * Read and return the contents of a DFS redirect given a
440 * pathname. A caller can pass in NULL for ppreflist and
441 * preferral_count but still determine if this was a
442 * DFS redirect point by getting NT_STATUS_OK back
443 * without incurring the overhead of reading and parsing
444 * the referral contents.
447 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
448 TALLOC_CTX *mem_ctx,
449 struct files_struct *dirfsp,
450 struct smb_filename *smb_fname,
451 struct referral **ppreflist,
452 size_t *preferral_count)
454 NTSTATUS status = NT_STATUS_NO_MEMORY;
455 size_t bufsize;
456 char *link_target = NULL;
457 int referral_len;
458 bool ok;
459 #if defined(HAVE_BROKEN_READLINK)
460 char link_target_buf[PATH_MAX];
461 #else
462 char link_target_buf[7];
463 #endif
464 int ret;
466 if (is_named_stream(smb_fname)) {
467 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
468 goto err;
471 if (ppreflist == NULL && preferral_count == NULL) {
473 * We're only checking if this is a DFS
474 * redirect. We don't need to return data.
476 bufsize = sizeof(link_target_buf);
477 link_target = link_target_buf;
478 } else {
479 bufsize = PATH_MAX;
480 link_target = talloc_array(mem_ctx, char, bufsize);
481 if (!link_target) {
482 goto err;
486 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
487 smb_fname->base_name,
488 link_target,
489 bufsize - 1);
490 if (referral_len == -1) {
491 if (errno == EINVAL) {
493 * If the path isn't a link, readlinkat
494 * returns EINVAL. Allow the caller to
495 * detect this.
497 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
498 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
499 } else {
500 status = map_nt_error_from_unix(errno);
501 if (errno == ENOENT) {
502 DBG_NOTICE("Error reading "
503 "msdfs link %s: %s\n",
504 smb_fname->base_name,
505 strerror(errno));
506 } else {
507 DBG_ERR("Error reading "
508 "msdfs link %s: %s\n",
509 smb_fname->base_name,
510 strerror(errno));
513 goto err;
515 link_target[referral_len] = '\0';
517 DBG_INFO("%s -> %s\n",
518 smb_fname->base_name,
519 link_target);
521 if (!strnequal(link_target, "msdfs:", 6)) {
522 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
523 goto err;
526 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
527 smb_fname->base_name,
528 &smb_fname->st,
529 AT_SYMLINK_NOFOLLOW,
530 lp_fake_directory_create_times(SNUM(handle->conn)));
531 if (ret < 0) {
532 status = map_nt_error_from_unix(errno);
533 goto err;
536 if (ppreflist == NULL && preferral_count == NULL) {
537 /* Early return for checking if this is a DFS link. */
538 return NT_STATUS_OK;
541 ok = parse_msdfs_symlink(mem_ctx,
542 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
543 link_target,
544 ppreflist,
545 preferral_count);
547 if (ok) {
548 status = NT_STATUS_OK;
549 } else {
550 status = NT_STATUS_NO_MEMORY;
553 err:
555 if (link_target != link_target_buf) {
556 TALLOC_FREE(link_target);
558 return status;
561 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
562 TALLOC_CTX *mem_ctx,
563 const char *service_path,
564 char **base_volume)
566 return NT_STATUS_NOT_SUPPORTED;
569 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
570 TALLOC_CTX *mem_ctx,
571 const char *base_volume,
572 time_t *tstamp,
573 bool rw,
574 char **base_path,
575 char **snap_path)
577 return NT_STATUS_NOT_SUPPORTED;
580 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
581 TALLOC_CTX *mem_ctx,
582 char *base_path,
583 char *snap_path)
585 return NT_STATUS_NOT_SUPPORTED;
588 /* Directory operations */
590 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
591 files_struct *fsp,
592 const char *mask,
593 uint32_t attr)
595 DIR *result;
597 START_PROFILE(syscall_fdopendir);
598 result = sys_fdopendir(fsp_get_io_fd(fsp));
599 END_PROFILE(syscall_fdopendir);
600 return result;
603 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
604 struct files_struct *dirfsp,
605 DIR *dirp)
607 struct dirent *result;
609 START_PROFILE(syscall_readdir);
611 result = readdir(dirp);
612 END_PROFILE(syscall_readdir);
614 return result;
617 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
618 struct files_struct *fsp,
619 TALLOC_CTX *mem_ctx,
620 struct readdir_attr_data **attr_data)
622 return NT_STATUS_NOT_SUPPORTED;
625 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
627 START_PROFILE(syscall_rewinddir);
628 rewinddir(dirp);
629 END_PROFILE(syscall_rewinddir);
632 static int vfswrap_mkdirat(vfs_handle_struct *handle,
633 struct files_struct *dirfsp,
634 const struct smb_filename *smb_fname,
635 mode_t mode)
637 int result;
639 START_PROFILE(syscall_mkdirat);
641 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
643 END_PROFILE(syscall_mkdirat);
644 return result;
647 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
649 int result;
651 START_PROFILE(syscall_closedir);
652 result = closedir(dirp);
653 END_PROFILE(syscall_closedir);
654 return result;
657 /* File operations */
659 static int vfswrap_openat(vfs_handle_struct *handle,
660 const struct files_struct *dirfsp,
661 const struct smb_filename *smb_fname,
662 files_struct *fsp,
663 const struct vfs_open_how *how)
665 int flags = how->flags;
666 mode_t mode = how->mode;
667 bool have_opath = false;
668 bool became_root = false;
669 int result;
671 START_PROFILE(syscall_openat);
673 if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
674 VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
675 errno = ENOSYS;
676 result = -1;
677 goto out;
680 SMB_ASSERT(!is_named_stream(smb_fname));
682 #ifdef O_PATH
683 have_opath = true;
684 if (fsp->fsp_flags.is_pathref) {
685 flags |= O_PATH;
687 if (flags & O_PATH) {
689 * From "man 2 openat":
691 * When O_PATH is specified in flags, flag bits other than
692 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
694 * From "man 2 openat2":
696 * Whereas openat(2) ignores unknown bits in its flags
697 * argument, openat2() returns an error if unknown or
698 * conflicting flags are specified in how.flags.
700 * So we better clear ignored/invalid flags
701 * and only keep the expected ones.
703 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
705 #endif
707 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
708 struct open_how linux_how = {
709 .flags = flags,
710 .mode = mode,
711 .resolve = RESOLVE_NO_SYMLINKS,
714 result = openat2(fsp_get_pathref_fd(dirfsp),
715 smb_fname->base_name,
716 &linux_how,
717 sizeof(linux_how));
718 if (result == -1) {
719 if (errno == ENOSYS) {
721 * The kernel doesn't support
722 * openat2(), so indicate to
723 * the callers that
724 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
725 * would just be a waste of time.
727 fsp->conn->open_how_resolve &=
728 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
730 goto out;
733 goto done;
736 if (fsp->fsp_flags.is_pathref && !have_opath) {
737 become_root();
738 became_root = true;
741 result = openat(fsp_get_pathref_fd(dirfsp),
742 smb_fname->base_name,
743 flags,
744 mode);
746 if (became_root) {
747 int err = errno;
748 unbecome_root();
749 errno = err;
752 done:
753 if (result >= 0) {
754 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
755 } else {
757 * "/proc/self/fd/-1" never exists. Indicate to upper
758 * layers that for this fsp a possible name-based
759 * fallback is the only way to go.
761 fsp->fsp_flags.have_proc_fds = false;
764 out:
765 END_PROFILE(syscall_openat);
766 return result;
768 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
769 struct smb_request *req,
770 struct files_struct *dirfsp,
771 struct smb_filename *smb_fname,
772 uint32_t access_mask,
773 uint32_t share_access,
774 uint32_t create_disposition,
775 uint32_t create_options,
776 uint32_t file_attributes,
777 uint32_t oplock_request,
778 const struct smb2_lease *lease,
779 uint64_t allocation_size,
780 uint32_t private_flags,
781 struct security_descriptor *sd,
782 struct ea_list *ea_list,
783 files_struct **result,
784 int *pinfo,
785 const struct smb2_create_blobs *in_context_blobs,
786 struct smb2_create_blobs *out_context_blobs)
788 return create_file_default(handle->conn, req, dirfsp, smb_fname,
789 access_mask, share_access,
790 create_disposition, create_options,
791 file_attributes, oplock_request, lease,
792 allocation_size, private_flags,
793 sd, ea_list, result,
794 pinfo, in_context_blobs, out_context_blobs);
797 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
799 int result;
801 START_PROFILE(syscall_close);
802 result = fd_close_posix(fsp);
803 END_PROFILE(syscall_close);
804 return result;
807 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
808 size_t n, off_t offset)
810 ssize_t result;
812 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
813 START_PROFILE_BYTES(syscall_pread, n);
814 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
815 END_PROFILE_BYTES(syscall_pread);
817 if (result == -1 && errno == ESPIPE) {
818 /* Maintain the fiction that pipes can be seeked (sought?) on. */
819 result = sys_read(fsp_get_io_fd(fsp), data, n);
820 fh_set_pos(fsp->fh, 0);
823 #else /* HAVE_PREAD */
824 errno = ENOSYS;
825 result = -1;
826 #endif /* HAVE_PREAD */
828 return result;
831 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
832 size_t n, off_t offset)
834 ssize_t result;
836 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
837 START_PROFILE_BYTES(syscall_pwrite, n);
838 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
839 END_PROFILE_BYTES(syscall_pwrite);
841 if (result == -1 && errno == ESPIPE) {
842 /* Maintain the fiction that pipes can be sought on. */
843 result = sys_write(fsp_get_io_fd(fsp), data, n);
846 #else /* HAVE_PWRITE */
847 errno = ENOSYS;
848 result = -1;
849 #endif /* HAVE_PWRITE */
851 return result;
854 struct vfswrap_pread_state {
855 ssize_t ret;
856 int fd;
857 void *buf;
858 size_t count;
859 off_t offset;
861 struct vfs_aio_state vfs_aio_state;
862 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
865 static void vfs_pread_do(void *private_data);
866 static void vfs_pread_done(struct tevent_req *subreq);
867 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
869 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
870 TALLOC_CTX *mem_ctx,
871 struct tevent_context *ev,
872 struct files_struct *fsp,
873 void *data,
874 size_t n, off_t offset)
876 struct tevent_req *req, *subreq;
877 struct vfswrap_pread_state *state;
879 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
880 if (req == NULL) {
881 return NULL;
884 state->ret = -1;
885 state->fd = fsp_get_io_fd(fsp);
886 state->buf = data;
887 state->count = n;
888 state->offset = offset;
890 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
891 state->profile_bytes, n);
892 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
894 subreq = pthreadpool_tevent_job_send(
895 state, ev, handle->conn->sconn->pool,
896 vfs_pread_do, state);
897 if (tevent_req_nomem(subreq, req)) {
898 return tevent_req_post(req, ev);
900 tevent_req_set_callback(subreq, vfs_pread_done, req);
902 talloc_set_destructor(state, vfs_pread_state_destructor);
904 return req;
907 static void vfs_pread_do(void *private_data)
909 struct vfswrap_pread_state *state = talloc_get_type_abort(
910 private_data, struct vfswrap_pread_state);
911 struct timespec start_time;
912 struct timespec end_time;
914 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
916 PROFILE_TIMESTAMP(&start_time);
918 state->ret = sys_pread_full(state->fd,
919 state->buf,
920 state->count,
921 state->offset);
923 if (state->ret == -1) {
924 state->vfs_aio_state.error = errno;
927 PROFILE_TIMESTAMP(&end_time);
929 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
931 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
934 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
936 return -1;
939 static void vfs_pread_done(struct tevent_req *subreq)
941 struct tevent_req *req = tevent_req_callback_data(
942 subreq, struct tevent_req);
943 struct vfswrap_pread_state *state = tevent_req_data(
944 req, struct vfswrap_pread_state);
945 int ret;
947 ret = pthreadpool_tevent_job_recv(subreq);
948 TALLOC_FREE(subreq);
949 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
950 talloc_set_destructor(state, NULL);
951 if (ret != 0) {
952 if (ret != EAGAIN) {
953 tevent_req_error(req, ret);
954 return;
957 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
958 * means the lower level pthreadpool failed to create a new
959 * thread. Fallback to sync processing in that case to allow
960 * some progress for the client.
962 vfs_pread_do(state);
965 tevent_req_done(req);
968 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
969 struct vfs_aio_state *vfs_aio_state)
971 struct vfswrap_pread_state *state = tevent_req_data(
972 req, struct vfswrap_pread_state);
974 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
975 return -1;
978 *vfs_aio_state = state->vfs_aio_state;
979 return state->ret;
982 struct vfswrap_pwrite_state {
983 ssize_t ret;
984 int fd;
985 const void *buf;
986 size_t count;
987 off_t offset;
989 struct vfs_aio_state vfs_aio_state;
990 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
993 static void vfs_pwrite_do(void *private_data);
994 static void vfs_pwrite_done(struct tevent_req *subreq);
995 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
997 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
998 TALLOC_CTX *mem_ctx,
999 struct tevent_context *ev,
1000 struct files_struct *fsp,
1001 const void *data,
1002 size_t n, off_t offset)
1004 struct tevent_req *req, *subreq;
1005 struct vfswrap_pwrite_state *state;
1007 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1008 if (req == NULL) {
1009 return NULL;
1012 state->ret = -1;
1013 state->fd = fsp_get_io_fd(fsp);
1014 state->buf = data;
1015 state->count = n;
1016 state->offset = offset;
1018 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1019 state->profile_bytes, n);
1020 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1022 subreq = pthreadpool_tevent_job_send(
1023 state, ev, handle->conn->sconn->pool,
1024 vfs_pwrite_do, state);
1025 if (tevent_req_nomem(subreq, req)) {
1026 return tevent_req_post(req, ev);
1028 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1030 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1032 return req;
1035 static void vfs_pwrite_do(void *private_data)
1037 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1038 private_data, struct vfswrap_pwrite_state);
1039 struct timespec start_time;
1040 struct timespec end_time;
1042 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1044 PROFILE_TIMESTAMP(&start_time);
1046 state->ret = sys_pwrite_full(state->fd,
1047 state->buf,
1048 state->count,
1049 state->offset);
1051 if (state->ret == -1) {
1052 state->vfs_aio_state.error = errno;
1055 PROFILE_TIMESTAMP(&end_time);
1057 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1059 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1062 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1064 return -1;
1067 static void vfs_pwrite_done(struct tevent_req *subreq)
1069 struct tevent_req *req = tevent_req_callback_data(
1070 subreq, struct tevent_req);
1071 struct vfswrap_pwrite_state *state = tevent_req_data(
1072 req, struct vfswrap_pwrite_state);
1073 int ret;
1075 ret = pthreadpool_tevent_job_recv(subreq);
1076 TALLOC_FREE(subreq);
1077 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1078 talloc_set_destructor(state, NULL);
1079 if (ret != 0) {
1080 if (ret != EAGAIN) {
1081 tevent_req_error(req, ret);
1082 return;
1085 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1086 * means the lower level pthreadpool failed to create a new
1087 * thread. Fallback to sync processing in that case to allow
1088 * some progress for the client.
1090 vfs_pwrite_do(state);
1093 tevent_req_done(req);
1096 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1097 struct vfs_aio_state *vfs_aio_state)
1099 struct vfswrap_pwrite_state *state = tevent_req_data(
1100 req, struct vfswrap_pwrite_state);
1102 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1103 return -1;
1106 *vfs_aio_state = state->vfs_aio_state;
1107 return state->ret;
1110 struct vfswrap_fsync_state {
1111 ssize_t ret;
1112 int fd;
1114 struct vfs_aio_state vfs_aio_state;
1115 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1118 static void vfs_fsync_do(void *private_data);
1119 static void vfs_fsync_done(struct tevent_req *subreq);
1120 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1122 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1123 TALLOC_CTX *mem_ctx,
1124 struct tevent_context *ev,
1125 struct files_struct *fsp)
1127 struct tevent_req *req, *subreq;
1128 struct vfswrap_fsync_state *state;
1130 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1131 if (req == NULL) {
1132 return NULL;
1135 state->ret = -1;
1136 state->fd = fsp_get_io_fd(fsp);
1138 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1139 state->profile_bytes, 0);
1140 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1142 subreq = pthreadpool_tevent_job_send(
1143 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1144 if (tevent_req_nomem(subreq, req)) {
1145 return tevent_req_post(req, ev);
1147 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1149 talloc_set_destructor(state, vfs_fsync_state_destructor);
1151 return req;
1154 static void vfs_fsync_do(void *private_data)
1156 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1157 private_data, struct vfswrap_fsync_state);
1158 struct timespec start_time;
1159 struct timespec end_time;
1161 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1163 PROFILE_TIMESTAMP(&start_time);
1165 do {
1166 state->ret = fsync(state->fd);
1167 } while ((state->ret == -1) && (errno == EINTR));
1169 if (state->ret == -1) {
1170 state->vfs_aio_state.error = errno;
1173 PROFILE_TIMESTAMP(&end_time);
1175 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1177 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1180 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1182 return -1;
1185 static void vfs_fsync_done(struct tevent_req *subreq)
1187 struct tevent_req *req = tevent_req_callback_data(
1188 subreq, struct tevent_req);
1189 struct vfswrap_fsync_state *state = tevent_req_data(
1190 req, struct vfswrap_fsync_state);
1191 int ret;
1193 ret = pthreadpool_tevent_job_recv(subreq);
1194 TALLOC_FREE(subreq);
1195 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1196 talloc_set_destructor(state, NULL);
1197 if (ret != 0) {
1198 if (ret != EAGAIN) {
1199 tevent_req_error(req, ret);
1200 return;
1203 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1204 * means the lower level pthreadpool failed to create a new
1205 * thread. Fallback to sync processing in that case to allow
1206 * some progress for the client.
1208 vfs_fsync_do(state);
1211 tevent_req_done(req);
1214 static int vfswrap_fsync_recv(struct tevent_req *req,
1215 struct vfs_aio_state *vfs_aio_state)
1217 struct vfswrap_fsync_state *state = tevent_req_data(
1218 req, struct vfswrap_fsync_state);
1220 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1221 return -1;
1224 *vfs_aio_state = state->vfs_aio_state;
1225 return state->ret;
1228 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1230 off_t result = 0;
1232 START_PROFILE(syscall_lseek);
1234 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1236 * We want to maintain the fiction that we can seek
1237 * on a fifo for file system purposes. This allows
1238 * people to set up UNIX fifo's that feed data to Windows
1239 * applications. JRA.
1242 if((result == -1) && (errno == ESPIPE)) {
1243 result = 0;
1244 errno = 0;
1247 END_PROFILE(syscall_lseek);
1248 return result;
1251 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1252 off_t offset, size_t n)
1254 ssize_t result;
1256 START_PROFILE_BYTES(syscall_sendfile, n);
1257 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1258 END_PROFILE_BYTES(syscall_sendfile);
1259 return result;
1262 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1263 int fromfd,
1264 files_struct *tofsp,
1265 off_t offset,
1266 size_t n)
1268 ssize_t result;
1270 START_PROFILE_BYTES(syscall_recvfile, n);
1271 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1272 END_PROFILE_BYTES(syscall_recvfile);
1273 return result;
1276 static int vfswrap_renameat(vfs_handle_struct *handle,
1277 files_struct *srcfsp,
1278 const struct smb_filename *smb_fname_src,
1279 files_struct *dstfsp,
1280 const struct smb_filename *smb_fname_dst)
1282 int result = -1;
1284 START_PROFILE(syscall_renameat);
1286 SMB_ASSERT(!is_named_stream(smb_fname_src));
1287 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1289 result = renameat(fsp_get_pathref_fd(srcfsp),
1290 smb_fname_src->base_name,
1291 fsp_get_pathref_fd(dstfsp),
1292 smb_fname_dst->base_name);
1294 END_PROFILE(syscall_renameat);
1295 return result;
1298 static int vfswrap_stat(vfs_handle_struct *handle,
1299 struct smb_filename *smb_fname)
1301 int result = -1;
1303 START_PROFILE(syscall_stat);
1305 SMB_ASSERT(!is_named_stream(smb_fname));
1307 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1308 lp_fake_directory_create_times(SNUM(handle->conn)));
1310 END_PROFILE(syscall_stat);
1311 return result;
1314 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1316 int result;
1318 START_PROFILE(syscall_fstat);
1319 result = sys_fstat(fsp_get_pathref_fd(fsp),
1320 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1321 END_PROFILE(syscall_fstat);
1322 return result;
1325 static int vfswrap_lstat(vfs_handle_struct *handle,
1326 struct smb_filename *smb_fname)
1328 int result = -1;
1330 START_PROFILE(syscall_lstat);
1332 SMB_ASSERT(!is_named_stream(smb_fname));
1334 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1335 lp_fake_directory_create_times(SNUM(handle->conn)));
1337 END_PROFILE(syscall_lstat);
1338 return result;
1341 static int vfswrap_fstatat(
1342 struct vfs_handle_struct *handle,
1343 const struct files_struct *dirfsp,
1344 const struct smb_filename *smb_fname,
1345 SMB_STRUCT_STAT *sbuf,
1346 int flags)
1348 int result = -1;
1350 START_PROFILE(syscall_fstatat);
1352 SMB_ASSERT(!is_named_stream(smb_fname));
1354 result = sys_fstatat(
1355 fsp_get_pathref_fd(dirfsp),
1356 smb_fname->base_name,
1357 sbuf,
1358 flags,
1359 lp_fake_directory_create_times(SNUM(handle->conn)));
1361 END_PROFILE(syscall_fstatat);
1362 return result;
1365 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1366 const char *name,
1367 enum vfs_translate_direction direction,
1368 TALLOC_CTX *mem_ctx,
1369 char **mapped_name)
1371 return NT_STATUS_NONE_MAPPED;
1375 * Return allocated parent directory and basename of path
1377 * Note: if requesting atname, it is returned as talloc child of the
1378 * parent. Freeing the parent is thus sufficient to free both.
1380 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1381 TALLOC_CTX *mem_ctx,
1382 const struct smb_filename *smb_fname_in,
1383 struct smb_filename **parent_dir_out,
1384 struct smb_filename **atname_out)
1386 struct smb_filename *parent = NULL;
1387 struct smb_filename *name = NULL;
1388 char *p = NULL;
1390 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1391 if (parent == NULL) {
1392 return NT_STATUS_NO_MEMORY;
1394 SET_STAT_INVALID(parent->st);
1396 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1397 if (p == NULL) {
1398 TALLOC_FREE(parent->base_name);
1399 parent->base_name = talloc_strdup(parent, ".");
1400 if (parent->base_name == NULL) {
1401 TALLOC_FREE(parent);
1402 return NT_STATUS_NO_MEMORY;
1404 p = smb_fname_in->base_name;
1405 } else {
1406 *p = '\0';
1407 p++;
1410 if (atname_out == NULL) {
1411 *parent_dir_out = parent;
1412 return NT_STATUS_OK;
1415 name = synthetic_smb_fname(
1416 parent,
1418 smb_fname_in->stream_name,
1419 &smb_fname_in->st,
1420 smb_fname_in->twrp,
1421 smb_fname_in->flags);
1422 if (name == NULL) {
1423 return NT_STATUS_NO_MEMORY;
1426 *parent_dir_out = parent;
1427 *atname_out = name;
1428 return NT_STATUS_OK;
1432 * Implement the default fsctl operation.
1434 static bool vfswrap_logged_ioctl_message = false;
1436 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1437 struct files_struct *fsp,
1438 TALLOC_CTX *ctx,
1439 uint32_t function,
1440 uint16_t req_flags, /* Needed for UNICODE ... */
1441 const uint8_t *_in_data,
1442 uint32_t in_len,
1443 uint8_t **_out_data,
1444 uint32_t max_out_len,
1445 uint32_t *out_len)
1447 const char *in_data = (const char *)_in_data;
1448 char **out_data = (char **)_out_data;
1449 NTSTATUS status;
1452 * Currently all fsctls operate on the base
1453 * file if given an alternate data stream.
1454 * Revisit this if we implement fsctls later
1455 * that need access to the ADS handle.
1457 fsp = metadata_fsp(fsp);
1459 switch (function) {
1460 case FSCTL_SET_SPARSE:
1462 bool set_sparse = true;
1464 if (in_len >= 1 && in_data[0] == 0) {
1465 set_sparse = false;
1468 status = file_set_sparse(handle->conn, fsp, set_sparse);
1470 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1471 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1472 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1473 nt_errstr(status)));
1475 return status;
1478 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1480 unsigned char objid[16];
1481 uint8_t *return_data = NULL;
1483 /* This should return the object-id on this file.
1484 * I think I'll make this be the inode+dev. JRA.
1487 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1488 fsp_fnum_dbg(fsp));
1490 *out_len = MIN(max_out_len, 64);
1492 /* Hmmm, will this cause problems if less data asked for? */
1493 return_data = talloc_array(ctx, uint8_t, 64);
1494 if (return_data == NULL) {
1495 return NT_STATUS_NO_MEMORY;
1498 /* For backwards compatibility only store the dev/inode. */
1499 push_file_id_16(return_data, &fsp->file_id);
1500 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1501 push_file_id_16(return_data + 32, &fsp->file_id);
1502 memset(return_data+48, 0, 16);
1503 *_out_data = return_data;
1504 return NT_STATUS_OK;
1507 case FSCTL_GET_REPARSE_POINT:
1509 uint32_t tag;
1510 status = fsctl_get_reparse_point(
1511 fsp, ctx, &tag, _out_data, max_out_len, out_len);
1512 return status;
1515 case FSCTL_SET_REPARSE_POINT:
1517 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1518 return status;
1521 case FSCTL_DELETE_REPARSE_POINT:
1523 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1524 return status;
1527 case FSCTL_GET_SHADOW_COPY_DATA:
1530 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1531 * and return their volume names. If max_data_count is 16, then it is just
1532 * asking for the number of volumes and length of the combined names.
1534 * pdata is the data allocated by our caller, but that uses
1535 * total_data_count (which is 0 in our case) rather than max_data_count.
1536 * Allocate the correct amount and return the pointer to let
1537 * it be deallocated when we return.
1539 struct shadow_copy_data *shadow_data = NULL;
1540 bool labels = False;
1541 uint32_t labels_data_count = 0;
1542 uint32_t i;
1543 char *cur_pdata = NULL;
1545 if (max_out_len < 16) {
1546 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1547 max_out_len);
1548 return NT_STATUS_INVALID_PARAMETER;
1551 if (max_out_len > 16) {
1552 labels = True;
1555 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1556 if (shadow_data == NULL) {
1557 DBG_ERR("TALLOC_ZERO() failed!\n");
1558 return NT_STATUS_NO_MEMORY;
1562 * Call the VFS routine to actually do the work.
1564 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1565 int log_lev = DBGLVL_ERR;
1566 if (errno == 0) {
1567 /* broken module didn't set errno on error */
1568 status = NT_STATUS_UNSUCCESSFUL;
1569 } else {
1570 status = map_nt_error_from_unix(errno);
1571 if (NT_STATUS_EQUAL(status,
1572 NT_STATUS_NOT_SUPPORTED)) {
1573 log_lev = DBGLVL_INFO;
1576 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1577 "connectpath %s, failed - %s.\n",
1578 fsp->conn->connectpath,
1579 nt_errstr(status)));
1580 TALLOC_FREE(shadow_data);
1581 return status;
1584 labels_data_count = (shadow_data->num_volumes * 2 *
1585 sizeof(SHADOW_COPY_LABEL)) + 2;
1587 if (!labels) {
1588 *out_len = 16;
1589 } else {
1590 *out_len = 12 + labels_data_count;
1593 if (max_out_len < *out_len) {
1594 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1595 max_out_len, *out_len);
1596 TALLOC_FREE(shadow_data);
1597 return NT_STATUS_BUFFER_TOO_SMALL;
1600 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1601 if (cur_pdata == NULL) {
1602 TALLOC_FREE(shadow_data);
1603 return NT_STATUS_NO_MEMORY;
1606 *out_data = cur_pdata;
1608 /* num_volumes 4 bytes */
1609 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1611 if (labels) {
1612 /* num_labels 4 bytes */
1613 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1616 /* needed_data_count 4 bytes */
1617 SIVAL(cur_pdata, 8, labels_data_count);
1619 cur_pdata += 12;
1621 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1622 shadow_data->num_volumes, fsp_str_dbg(fsp));
1623 if (labels && shadow_data->labels) {
1624 for (i=0; i<shadow_data->num_volumes; i++) {
1625 size_t len = 0;
1626 status = srvstr_push(cur_pdata, req_flags,
1627 cur_pdata, shadow_data->labels[i],
1628 2 * sizeof(SHADOW_COPY_LABEL),
1629 STR_UNICODE|STR_TERMINATE, &len);
1630 if (!NT_STATUS_IS_OK(status)) {
1631 TALLOC_FREE(*out_data);
1632 TALLOC_FREE(shadow_data);
1633 return status;
1635 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1636 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1640 TALLOC_FREE(shadow_data);
1642 return NT_STATUS_OK;
1645 case FSCTL_FIND_FILES_BY_SID:
1647 /* pretend this succeeded -
1649 * we have to send back a list with all files owned by this SID
1651 * but I have to check that --metze
1653 ssize_t ret;
1654 struct dom_sid sid;
1655 struct dom_sid_buf buf;
1656 uid_t uid;
1657 size_t sid_len;
1659 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1660 fsp_fnum_dbg(fsp));
1662 if (in_len < 8) {
1663 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1664 return NT_STATUS_INVALID_PARAMETER;
1667 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1669 /* unknown 4 bytes: this is not the length of the sid :-( */
1670 /*unknown = IVAL(pdata,0);*/
1672 ret = sid_parse(_in_data + 4, sid_len, &sid);
1673 if (ret == -1) {
1674 return NT_STATUS_INVALID_PARAMETER;
1676 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1677 dom_sid_str_buf(&sid, &buf)));
1679 if (!sid_to_uid(&sid, &uid)) {
1680 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1681 dom_sid_str_buf(&sid, &buf),
1682 (unsigned long)sid_len);
1683 uid = (-1);
1686 /* we can take a look at the find source :-)
1688 * find ./ -uid $uid -name '*' is what we need here
1691 * and send 4bytes len and then NULL terminated unicode strings
1692 * for each file
1694 * but I don't know how to deal with the paged results
1695 * (maybe we can hang the result anywhere in the fsp struct)
1697 * but I don't know how to deal with the paged results
1698 * (maybe we can hang the result anywhere in the fsp struct)
1700 * we don't send all files at once
1701 * and at the next we should *not* start from the beginning,
1702 * so we have to cache the result
1704 * --metze
1707 /* this works for now... */
1708 return NT_STATUS_OK;
1711 case FSCTL_QUERY_ALLOCATED_RANGES:
1713 /* FIXME: This is just a dummy reply, telling that all of the
1714 * file is allocated. MKS cp needs that.
1715 * Adding the real allocated ranges via FIEMAP on Linux
1716 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1717 * this FSCTL correct for sparse files.
1719 uint64_t offset, length;
1720 char *out_data_tmp = NULL;
1722 if (in_len != 16) {
1723 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1724 in_len);
1725 return NT_STATUS_INVALID_PARAMETER;
1728 if (max_out_len < 16) {
1729 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1730 max_out_len);
1731 return NT_STATUS_INVALID_PARAMETER;
1734 offset = BVAL(in_data,0);
1735 length = BVAL(in_data,8);
1737 if (offset + length < offset) {
1738 /* No 64-bit integer wrap. */
1739 return NT_STATUS_INVALID_PARAMETER;
1742 /* Shouldn't this be SMB_VFS_STAT ... ? */
1743 status = vfs_stat_fsp(fsp);
1744 if (!NT_STATUS_IS_OK(status)) {
1745 return status;
1748 *out_len = 16;
1749 out_data_tmp = talloc_array(ctx, char, *out_len);
1750 if (out_data_tmp == NULL) {
1751 DBG_DEBUG("unable to allocate memory for response\n");
1752 return NT_STATUS_NO_MEMORY;
1755 if (offset > fsp->fsp_name->st.st_ex_size ||
1756 fsp->fsp_name->st.st_ex_size == 0 ||
1757 length == 0) {
1758 memset(out_data_tmp, 0, *out_len);
1759 } else {
1760 uint64_t end = offset + length;
1761 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1762 SBVAL(out_data_tmp, 0, 0);
1763 SBVAL(out_data_tmp, 8, end);
1766 *out_data = out_data_tmp;
1768 return NT_STATUS_OK;
1771 case FSCTL_IS_VOLUME_DIRTY:
1773 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1774 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1776 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1777 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1779 return NT_STATUS_INVALID_PARAMETER;
1782 default:
1784 * Only print once ... unfortunately there could be lots of
1785 * different FSCTLs that are called.
1787 if (!vfswrap_logged_ioctl_message) {
1788 vfswrap_logged_ioctl_message = true;
1789 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1790 __func__, function);
1794 return NT_STATUS_NOT_SUPPORTED;
1797 static bool vfswrap_is_offline(struct connection_struct *conn,
1798 const struct smb_filename *fname);
1800 struct vfswrap_get_dos_attributes_state {
1801 struct vfs_aio_state aio_state;
1802 connection_struct *conn;
1803 TALLOC_CTX *mem_ctx;
1804 struct tevent_context *ev;
1805 files_struct *dir_fsp;
1806 struct smb_filename *smb_fname;
1807 uint32_t dosmode;
1808 bool as_root;
1811 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1813 static struct tevent_req *vfswrap_get_dos_attributes_send(
1814 TALLOC_CTX *mem_ctx,
1815 struct tevent_context *ev,
1816 struct vfs_handle_struct *handle,
1817 files_struct *dir_fsp,
1818 struct smb_filename *smb_fname)
1820 struct tevent_req *req = NULL;
1821 struct tevent_req *subreq = NULL;
1822 struct vfswrap_get_dos_attributes_state *state = NULL;
1824 SMB_ASSERT(!is_named_stream(smb_fname));
1826 req = tevent_req_create(mem_ctx, &state,
1827 struct vfswrap_get_dos_attributes_state);
1828 if (req == NULL) {
1829 return NULL;
1832 *state = (struct vfswrap_get_dos_attributes_state) {
1833 .conn = dir_fsp->conn,
1834 .mem_ctx = mem_ctx,
1835 .ev = ev,
1836 .dir_fsp = dir_fsp,
1837 .smb_fname = smb_fname,
1840 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1841 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1842 "\"store dos attributes\" is disabled\n",
1843 dir_fsp->conn->connectpath);
1844 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1845 return tevent_req_post(req, ev);
1848 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1850 dir_fsp,
1851 smb_fname,
1852 SAMBA_XATTR_DOS_ATTRIB,
1853 sizeof(fstring));
1854 if (tevent_req_nomem(subreq, req)) {
1855 return tevent_req_post(req, ev);
1857 tevent_req_set_callback(subreq,
1858 vfswrap_get_dos_attributes_getxattr_done,
1859 req);
1861 return req;
1864 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1866 struct tevent_req *req =
1867 tevent_req_callback_data(subreq,
1868 struct tevent_req);
1869 struct vfswrap_get_dos_attributes_state *state =
1870 tevent_req_data(req,
1871 struct vfswrap_get_dos_attributes_state);
1872 ssize_t xattr_size;
1873 DATA_BLOB blob = {0};
1874 char *path = NULL;
1875 char *tofree = NULL;
1876 char pathbuf[PATH_MAX+1];
1877 ssize_t pathlen;
1878 struct smb_filename smb_fname;
1879 bool offline;
1880 NTSTATUS status;
1882 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1883 &state->aio_state,
1884 state,
1885 &blob.data);
1886 TALLOC_FREE(subreq);
1887 if (xattr_size == -1) {
1888 status = map_nt_error_from_unix(state->aio_state.error);
1890 if (state->as_root) {
1891 tevent_req_nterror(req, status);
1892 return;
1894 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1895 tevent_req_nterror(req, status);
1896 return;
1899 state->as_root = true;
1901 become_root();
1902 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1903 state->ev,
1904 state->dir_fsp,
1905 state->smb_fname,
1906 SAMBA_XATTR_DOS_ATTRIB,
1907 sizeof(fstring));
1908 unbecome_root();
1909 if (tevent_req_nomem(subreq, req)) {
1910 return;
1912 tevent_req_set_callback(subreq,
1913 vfswrap_get_dos_attributes_getxattr_done,
1914 req);
1915 return;
1918 blob.length = xattr_size;
1920 status = parse_dos_attribute_blob(state->smb_fname,
1921 blob,
1922 &state->dosmode);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 tevent_req_nterror(req, status);
1925 return;
1928 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1929 state->smb_fname->base_name,
1930 pathbuf,
1931 sizeof(pathbuf),
1932 &path,
1933 &tofree);
1934 if (pathlen == -1) {
1935 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1936 return;
1939 smb_fname = (struct smb_filename) {
1940 .base_name = path,
1941 .st = state->smb_fname->st,
1942 .flags = state->smb_fname->flags,
1943 .twrp = state->smb_fname->twrp,
1946 offline = vfswrap_is_offline(state->conn, &smb_fname);
1947 if (offline) {
1948 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1950 TALLOC_FREE(tofree);
1952 tevent_req_done(req);
1953 return;
1956 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1957 struct vfs_aio_state *aio_state,
1958 uint32_t *dosmode)
1960 struct vfswrap_get_dos_attributes_state *state =
1961 tevent_req_data(req,
1962 struct vfswrap_get_dos_attributes_state);
1963 NTSTATUS status;
1965 if (tevent_req_is_nterror(req, &status)) {
1966 tevent_req_received(req);
1967 return status;
1970 *aio_state = state->aio_state;
1971 *dosmode = state->dosmode;
1972 tevent_req_received(req);
1973 return NT_STATUS_OK;
1976 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1977 struct files_struct *fsp,
1978 uint32_t *dosmode)
1980 bool offline;
1982 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1984 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1985 if (offline) {
1986 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1989 return fget_ea_dos_attribute(fsp, dosmode);
1992 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1993 struct files_struct *fsp,
1994 uint32_t dosmode)
1996 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1998 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2001 static struct vfs_offload_ctx *vfswrap_offload_ctx;
2003 struct vfswrap_offload_read_state {
2004 DATA_BLOB token;
2007 static struct tevent_req *vfswrap_offload_read_send(
2008 TALLOC_CTX *mem_ctx,
2009 struct tevent_context *ev,
2010 struct vfs_handle_struct *handle,
2011 struct files_struct *fsp,
2012 uint32_t fsctl,
2013 uint32_t ttl,
2014 off_t offset,
2015 size_t to_copy)
2017 struct tevent_req *req = NULL;
2018 struct vfswrap_offload_read_state *state = NULL;
2019 NTSTATUS status;
2021 req = tevent_req_create(mem_ctx, &state,
2022 struct vfswrap_offload_read_state);
2023 if (req == NULL) {
2024 return NULL;
2027 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2028 &vfswrap_offload_ctx);
2029 if (tevent_req_nterror(req, status)) {
2030 return tevent_req_post(req, ev);
2033 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2034 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2035 return tevent_req_post(req, ev);
2038 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2039 &state->token);
2040 if (tevent_req_nterror(req, status)) {
2041 return tevent_req_post(req, ev);
2044 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2045 &state->token);
2046 if (tevent_req_nterror(req, status)) {
2047 return tevent_req_post(req, ev);
2050 tevent_req_done(req);
2051 return tevent_req_post(req, ev);
2054 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2055 struct vfs_handle_struct *handle,
2056 TALLOC_CTX *mem_ctx,
2057 uint32_t *flags,
2058 uint64_t *xferlen,
2059 DATA_BLOB *token)
2061 struct vfswrap_offload_read_state *state = tevent_req_data(
2062 req, struct vfswrap_offload_read_state);
2063 NTSTATUS status;
2065 if (tevent_req_is_nterror(req, &status)) {
2066 tevent_req_received(req);
2067 return status;
2070 *flags = 0;
2071 *xferlen = 0;
2072 token->length = state->token.length;
2073 token->data = talloc_move(mem_ctx, &state->token.data);
2075 tevent_req_received(req);
2076 return NT_STATUS_OK;
2079 struct vfswrap_offload_write_state {
2080 uint8_t *buf;
2081 bool read_lck_locked;
2082 bool write_lck_locked;
2083 DATA_BLOB *token;
2084 struct tevent_context *src_ev;
2085 struct files_struct *src_fsp;
2086 off_t src_off;
2087 struct tevent_context *dst_ev;
2088 struct files_struct *dst_fsp;
2089 off_t dst_off;
2090 off_t to_copy;
2091 off_t remaining;
2092 off_t copied;
2093 size_t next_io_size;
2096 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2097 enum tevent_req_state req_state)
2099 struct vfswrap_offload_write_state *state = tevent_req_data(
2100 req, struct vfswrap_offload_write_state);
2101 bool ok;
2103 if (state->dst_fsp == NULL) {
2104 return;
2107 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2108 SMB_ASSERT(ok);
2109 state->dst_fsp = NULL;
2112 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2113 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2115 static struct tevent_req *vfswrap_offload_write_send(
2116 struct vfs_handle_struct *handle,
2117 TALLOC_CTX *mem_ctx,
2118 struct tevent_context *ev,
2119 uint32_t fsctl,
2120 DATA_BLOB *token,
2121 off_t transfer_offset,
2122 struct files_struct *dest_fsp,
2123 off_t dest_off,
2124 off_t to_copy)
2126 struct tevent_req *req;
2127 struct vfswrap_offload_write_state *state = NULL;
2128 /* off_t is signed! */
2129 off_t max_offset = INT64_MAX - to_copy;
2130 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2131 files_struct *src_fsp = NULL;
2132 NTSTATUS status;
2133 bool ok;
2135 req = tevent_req_create(mem_ctx, &state,
2136 struct vfswrap_offload_write_state);
2137 if (req == NULL) {
2138 return NULL;
2141 *state = (struct vfswrap_offload_write_state) {
2142 .token = token,
2143 .src_off = transfer_offset,
2144 .dst_ev = ev,
2145 .dst_fsp = dest_fsp,
2146 .dst_off = dest_off,
2147 .to_copy = to_copy,
2148 .remaining = to_copy,
2151 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2153 switch (fsctl) {
2154 case FSCTL_SRV_COPYCHUNK:
2155 case FSCTL_SRV_COPYCHUNK_WRITE:
2156 break;
2158 case FSCTL_OFFLOAD_WRITE:
2159 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2160 return tevent_req_post(req, ev);
2162 case FSCTL_DUP_EXTENTS_TO_FILE:
2163 DBG_DEBUG("COW clones not supported by vfs_default\n");
2164 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2165 return tevent_req_post(req, ev);
2167 default:
2168 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2169 return tevent_req_post(req, ev);
2173 * From here on we assume a copy-chunk fsctl
2176 if (to_copy == 0) {
2177 tevent_req_done(req);
2178 return tevent_req_post(req, ev);
2181 if (state->src_off > max_offset) {
2183 * Protect integer checks below.
2185 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2186 return tevent_req_post(req, ev);
2188 if (state->src_off < 0) {
2190 * Protect integer checks below.
2192 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2193 return tevent_req_post(req, ev);
2195 if (state->dst_off > max_offset) {
2197 * Protect integer checks below.
2199 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2200 return tevent_req_post(req, ev);
2202 if (state->dst_off < 0) {
2204 * Protect integer checks below.
2206 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2207 return tevent_req_post(req, ev);
2210 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2211 token, &src_fsp);
2212 if (tevent_req_nterror(req, status)) {
2213 return tevent_req_post(req, ev);
2216 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2218 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2219 if (!NT_STATUS_IS_OK(status)) {
2220 tevent_req_nterror(req, status);
2221 return tevent_req_post(req, ev);
2224 ok = change_to_user_and_service_by_fsp(src_fsp);
2225 if (!ok) {
2226 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2227 return tevent_req_post(req, ev);
2230 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2231 state->src_fsp = src_fsp;
2233 status = vfs_stat_fsp(src_fsp);
2234 if (tevent_req_nterror(req, status)) {
2235 return tevent_req_post(req, ev);
2238 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2240 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2241 * If the SourceOffset or SourceOffset + Length extends beyond
2242 * the end of file, the server SHOULD<240> treat this as a
2243 * STATUS_END_OF_FILE error.
2244 * ...
2245 * <240> Section 3.3.5.15.6: Windows servers will return
2246 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2248 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2249 return tevent_req_post(req, ev);
2252 status = vfswrap_offload_copy_file_range(req);
2253 if (NT_STATUS_IS_OK(status)) {
2254 tevent_req_done(req);
2255 return tevent_req_post(req, ev);
2257 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2258 tevent_req_nterror(req, status);
2259 return tevent_req_post(req, ev);
2262 state->buf = talloc_array(state, uint8_t, num);
2263 if (tevent_req_nomem(state->buf, req)) {
2264 return tevent_req_post(req, ev);
2267 status = vfswrap_offload_write_loop(req);
2268 if (!NT_STATUS_IS_OK(status)) {
2269 tevent_req_nterror(req, status);
2270 return tevent_req_post(req, ev);
2273 return req;
2276 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2278 struct vfswrap_offload_write_state *state = tevent_req_data(
2279 req, struct vfswrap_offload_write_state);
2280 struct lock_struct lck;
2281 ssize_t nwritten;
2282 NTSTATUS status;
2283 bool same_file;
2284 bool ok;
2285 static bool try_copy_file_range = true;
2287 if (!try_copy_file_range) {
2288 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2291 same_file = file_id_equal(&state->src_fsp->file_id,
2292 &state->dst_fsp->file_id);
2293 if (same_file &&
2294 sys_io_ranges_overlap(state->remaining,
2295 state->src_off,
2296 state->remaining,
2297 state->dst_off))
2299 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2302 if (fsp_is_alternate_stream(state->src_fsp) ||
2303 fsp_is_alternate_stream(state->dst_fsp))
2305 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2308 init_strict_lock_struct(state->src_fsp,
2309 state->src_fsp->op->global->open_persistent_id,
2310 state->src_off,
2311 state->remaining,
2312 READ_LOCK,
2313 lp_posix_cifsu_locktype(state->src_fsp),
2314 &lck);
2316 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2317 state->src_fsp,
2318 &lck);
2319 if (!ok) {
2320 return NT_STATUS_FILE_LOCK_CONFLICT;
2323 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2324 if (!ok) {
2325 return NT_STATUS_INTERNAL_ERROR;
2328 init_strict_lock_struct(state->dst_fsp,
2329 state->dst_fsp->op->global->open_persistent_id,
2330 state->dst_off,
2331 state->remaining,
2332 WRITE_LOCK,
2333 lp_posix_cifsu_locktype(state->dst_fsp),
2334 &lck);
2336 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2337 state->dst_fsp,
2338 &lck);
2339 if (!ok) {
2340 return NT_STATUS_FILE_LOCK_CONFLICT;
2343 while (state->remaining > 0) {
2344 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2345 &state->src_off,
2346 fsp_get_io_fd(state->dst_fsp),
2347 &state->dst_off,
2348 state->remaining,
2350 if (nwritten == -1) {
2351 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2352 "n [%jd] failed: %s\n",
2353 fsp_str_dbg(state->src_fsp),
2354 (intmax_t)state->src_off,
2355 fsp_str_dbg(state->dst_fsp),
2356 (intmax_t)state->dst_off,
2357 (intmax_t)state->remaining,
2358 strerror(errno));
2359 switch (errno) {
2360 case EOPNOTSUPP:
2361 case ENOSYS:
2362 try_copy_file_range = false;
2363 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2364 break;
2365 case EXDEV:
2366 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2367 break;
2368 default:
2369 status = map_nt_error_from_unix(errno);
2370 if (NT_STATUS_EQUAL(
2371 status,
2372 NT_STATUS_MORE_PROCESSING_REQUIRED))
2374 /* Avoid triggering the fallback */
2375 status = NT_STATUS_INTERNAL_ERROR;
2377 break;
2379 return status;
2382 if (state->remaining < nwritten) {
2383 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2384 "n [%jd] remaining [%jd]\n",
2385 fsp_str_dbg(state->src_fsp),
2386 fsp_str_dbg(state->dst_fsp),
2387 (intmax_t)nwritten,
2388 (intmax_t)state->remaining);
2389 return NT_STATUS_INTERNAL_ERROR;
2392 if (nwritten == 0) {
2393 break;
2395 state->copied += nwritten;
2396 state->remaining -= nwritten;
2400 * Tell the req cleanup function there's no need to call
2401 * change_to_user_and_service_by_fsp() on the dst handle.
2403 state->dst_fsp = NULL;
2404 return NT_STATUS_OK;
2407 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2409 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2411 struct vfswrap_offload_write_state *state = tevent_req_data(
2412 req, struct vfswrap_offload_write_state);
2413 struct tevent_req *subreq = NULL;
2414 struct lock_struct read_lck;
2415 bool ok;
2418 * This is called under the context of state->src_fsp.
2421 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2423 init_strict_lock_struct(state->src_fsp,
2424 state->src_fsp->op->global->open_persistent_id,
2425 state->src_off,
2426 state->next_io_size,
2427 READ_LOCK,
2428 lp_posix_cifsu_locktype(state->src_fsp),
2429 &read_lck);
2431 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2432 state->src_fsp,
2433 &read_lck);
2434 if (!ok) {
2435 return NT_STATUS_FILE_LOCK_CONFLICT;
2438 subreq = SMB_VFS_PREAD_SEND(state,
2439 state->src_ev,
2440 state->src_fsp,
2441 state->buf,
2442 state->next_io_size,
2443 state->src_off);
2444 if (subreq == NULL) {
2445 return NT_STATUS_NO_MEMORY;
2447 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2449 return NT_STATUS_OK;
2452 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2454 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2456 struct tevent_req *req = tevent_req_callback_data(
2457 subreq, struct tevent_req);
2458 struct vfswrap_offload_write_state *state = tevent_req_data(
2459 req, struct vfswrap_offload_write_state);
2460 struct vfs_aio_state aio_state;
2461 struct lock_struct write_lck;
2462 ssize_t nread;
2463 bool ok;
2465 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2466 TALLOC_FREE(subreq);
2467 if (nread == -1) {
2468 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2469 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2470 return;
2472 if (nread != state->next_io_size) {
2473 DBG_ERR("Short read, only %zd of %zu\n",
2474 nread, state->next_io_size);
2475 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2476 return;
2479 state->src_off += nread;
2481 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2482 if (!ok) {
2483 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2484 return;
2487 init_strict_lock_struct(state->dst_fsp,
2488 state->dst_fsp->op->global->open_persistent_id,
2489 state->dst_off,
2490 state->next_io_size,
2491 WRITE_LOCK,
2492 lp_posix_cifsu_locktype(state->dst_fsp),
2493 &write_lck);
2495 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2496 state->dst_fsp,
2497 &write_lck);
2498 if (!ok) {
2499 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2500 return;
2503 subreq = SMB_VFS_PWRITE_SEND(state,
2504 state->dst_ev,
2505 state->dst_fsp,
2506 state->buf,
2507 state->next_io_size,
2508 state->dst_off);
2509 if (subreq == NULL) {
2510 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2511 return;
2513 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2516 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2518 struct tevent_req *req = tevent_req_callback_data(
2519 subreq, struct tevent_req);
2520 struct vfswrap_offload_write_state *state = tevent_req_data(
2521 req, struct vfswrap_offload_write_state);
2522 struct vfs_aio_state aio_state;
2523 ssize_t nwritten;
2524 NTSTATUS status;
2525 bool ok;
2527 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2528 TALLOC_FREE(subreq);
2529 if (nwritten == -1) {
2530 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2531 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2532 return;
2534 if (nwritten != state->next_io_size) {
2535 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2536 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2537 return;
2540 state->dst_off += nwritten;
2542 if (state->remaining < nwritten) {
2543 /* Paranoia check */
2544 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2545 return;
2547 state->copied += nwritten;
2548 state->remaining -= nwritten;
2549 if (state->remaining == 0) {
2550 tevent_req_done(req);
2551 return;
2554 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2555 if (!ok) {
2556 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2557 return;
2560 status = vfswrap_offload_write_loop(req);
2561 if (!NT_STATUS_IS_OK(status)) {
2562 tevent_req_nterror(req, status);
2563 return;
2566 return;
2569 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2570 struct tevent_req *req,
2571 off_t *copied)
2573 struct vfswrap_offload_write_state *state = tevent_req_data(
2574 req, struct vfswrap_offload_write_state);
2575 NTSTATUS status;
2577 if (tevent_req_is_nterror(req, &status)) {
2578 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2579 *copied = 0;
2580 tevent_req_received(req);
2581 return status;
2584 *copied = state->copied;
2585 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2586 tevent_req_received(req);
2588 return NT_STATUS_OK;
2591 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2592 TALLOC_CTX *mem_ctx,
2593 struct files_struct *fsp,
2594 uint16_t *_compression_fmt)
2596 return NT_STATUS_INVALID_DEVICE_REQUEST;
2599 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2600 TALLOC_CTX *mem_ctx,
2601 struct files_struct *fsp,
2602 uint16_t compression_fmt)
2604 return NT_STATUS_INVALID_DEVICE_REQUEST;
2607 /********************************************************************
2608 Given a stat buffer return the allocated size on disk, taking into
2609 account sparse files.
2610 ********************************************************************/
2611 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2612 struct files_struct *fsp,
2613 const SMB_STRUCT_STAT *sbuf)
2615 uint64_t result;
2617 START_PROFILE(syscall_get_alloc_size);
2619 if(S_ISDIR(sbuf->st_ex_mode)) {
2620 result = 0;
2621 goto out;
2624 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2625 /* The type of st_blocksize is blkcnt_t which *MUST* be
2626 signed (according to POSIX) and can be less than 64-bits.
2627 Ensure when we're converting to 64 bits wide we don't
2628 sign extend. */
2629 #if defined(SIZEOF_BLKCNT_T_8)
2630 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2631 #elif defined(SIZEOF_BLKCNT_T_4)
2633 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2634 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2636 #else
2637 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2638 #endif
2639 if (result == 0) {
2641 * Some file systems do not allocate a block for very
2642 * small files. But for non-empty file should report a
2643 * positive size.
2646 uint64_t filesize = get_file_size_stat(sbuf);
2647 if (filesize > 0) {
2648 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2651 #else
2652 result = get_file_size_stat(sbuf);
2653 #endif
2655 if (fsp && fsp->initial_allocation_size)
2656 result = MAX(result,fsp->initial_allocation_size);
2658 result = smb_roundup(handle->conn, result);
2660 out:
2661 END_PROFILE(syscall_get_alloc_size);
2662 return result;
2665 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2666 struct files_struct *dirfsp,
2667 const struct smb_filename *smb_fname,
2668 int flags)
2670 int result = -1;
2672 START_PROFILE(syscall_unlinkat);
2674 SMB_ASSERT(!is_named_stream(smb_fname));
2676 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2677 smb_fname->base_name,
2678 flags);
2680 END_PROFILE(syscall_unlinkat);
2681 return result;
2684 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2686 int result;
2688 START_PROFILE(syscall_fchmod);
2690 if (!fsp->fsp_flags.is_pathref) {
2691 result = fchmod(fsp_get_io_fd(fsp), mode);
2692 END_PROFILE(syscall_fchmod);
2693 return result;
2696 if (fsp->fsp_flags.have_proc_fds) {
2697 int fd = fsp_get_pathref_fd(fsp);
2698 struct sys_proc_fd_path_buf buf;
2700 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2702 END_PROFILE(syscall_fchmod);
2703 return result;
2707 * This is no longer a handle based call.
2709 result = chmod(fsp->fsp_name->base_name, mode);
2711 END_PROFILE(syscall_fchmod);
2712 return result;
2715 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2717 #ifdef HAVE_FCHOWN
2718 int result;
2720 START_PROFILE(syscall_fchown);
2721 if (!fsp->fsp_flags.is_pathref) {
2722 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2723 END_PROFILE(syscall_fchown);
2724 return result;
2727 if (fsp->fsp_flags.have_proc_fds) {
2728 int fd = fsp_get_pathref_fd(fsp);
2729 struct sys_proc_fd_path_buf buf;
2731 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2733 END_PROFILE(syscall_fchown);
2734 return result;
2738 * This is no longer a handle based call.
2740 result = chown(fsp->fsp_name->base_name, uid, gid);
2741 END_PROFILE(syscall_fchown);
2742 return result;
2743 #else
2744 errno = ENOSYS;
2745 return -1;
2746 #endif
2749 static int vfswrap_lchown(vfs_handle_struct *handle,
2750 const struct smb_filename *smb_fname,
2751 uid_t uid,
2752 gid_t gid)
2754 int result;
2756 START_PROFILE(syscall_lchown);
2757 result = lchown(smb_fname->base_name, uid, gid);
2758 END_PROFILE(syscall_lchown);
2759 return result;
2762 static int vfswrap_chdir(vfs_handle_struct *handle,
2763 const struct smb_filename *smb_fname)
2765 int result;
2767 START_PROFILE(syscall_chdir);
2768 result = chdir(smb_fname->base_name);
2769 END_PROFILE(syscall_chdir);
2770 return result;
2773 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2774 TALLOC_CTX *ctx)
2776 char *result;
2777 struct smb_filename *smb_fname = NULL;
2779 START_PROFILE(syscall_getwd);
2780 result = sys_getwd();
2781 END_PROFILE(syscall_getwd);
2783 if (result == NULL) {
2784 return NULL;
2786 smb_fname = synthetic_smb_fname(ctx,
2787 result,
2788 NULL,
2789 NULL,
2793 * sys_getwd() *always* returns malloced memory.
2794 * We must free here to avoid leaks:
2795 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2797 SAFE_FREE(result);
2798 return smb_fname;
2801 /*********************************************************************
2802 nsec timestamp resolution call. Convert down to whatever the underlying
2803 system will support.
2804 **********************************************************************/
2806 static int vfswrap_fntimes(vfs_handle_struct *handle,
2807 files_struct *fsp,
2808 struct smb_file_time *ft)
2810 int result = -1;
2811 struct timespec ts[2];
2812 struct timespec *times = NULL;
2814 START_PROFILE(syscall_fntimes);
2816 if (fsp_is_alternate_stream(fsp)) {
2817 errno = ENOENT;
2818 goto out;
2821 if (ft != NULL) {
2822 if (is_omit_timespec(&ft->atime)) {
2823 ft->atime = fsp->fsp_name->st.st_ex_atime;
2826 if (is_omit_timespec(&ft->mtime)) {
2827 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2830 if (!is_omit_timespec(&ft->create_time)) {
2831 set_create_timespec_ea(fsp,
2832 ft->create_time);
2835 if ((timespec_compare(&ft->atime,
2836 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2837 (timespec_compare(&ft->mtime,
2838 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2839 result = 0;
2840 goto out;
2843 ts[0] = ft->atime;
2844 ts[1] = ft->mtime;
2845 times = ts;
2846 } else {
2847 times = NULL;
2850 if (!fsp->fsp_flags.is_pathref) {
2851 result = futimens(fsp_get_io_fd(fsp), times);
2852 goto out;
2855 if (fsp->fsp_flags.have_proc_fds) {
2856 int fd = fsp_get_pathref_fd(fsp);
2857 struct sys_proc_fd_path_buf buf;
2859 result = utimensat(AT_FDCWD,
2860 sys_proc_fd_path(fd, &buf),
2861 times,
2864 goto out;
2868 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2869 * path translation mechanism. Fallback to path based call.
2871 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2873 out:
2874 END_PROFILE(syscall_fntimes);
2876 return result;
2880 /*********************************************************************
2881 A version of ftruncate that will write the space on disk if strict
2882 allocate is set.
2883 **********************************************************************/
2885 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2887 off_t space_to_write;
2888 uint64_t space_avail;
2889 uint64_t bsize,dfree,dsize;
2890 int ret;
2891 NTSTATUS status;
2892 SMB_STRUCT_STAT *pst;
2893 bool ok;
2895 ok = vfs_valid_pwrite_range(len, 0);
2896 if (!ok) {
2897 errno = EINVAL;
2898 return -1;
2901 status = vfs_stat_fsp(fsp);
2902 if (!NT_STATUS_IS_OK(status)) {
2903 return -1;
2905 pst = &fsp->fsp_name->st;
2907 #ifdef S_ISFIFO
2908 if (S_ISFIFO(pst->st_ex_mode))
2909 return 0;
2910 #endif
2912 if (pst->st_ex_size == len)
2913 return 0;
2915 /* Shrink - just ftruncate. */
2916 if (pst->st_ex_size > len)
2917 return ftruncate(fsp_get_io_fd(fsp), len);
2919 space_to_write = len - pst->st_ex_size;
2921 /* for allocation try fallocate first. This can fail on some
2922 platforms e.g. when the filesystem doesn't support it and no
2923 emulation is being done by the libc (like on AIX with JFS1). In that
2924 case we do our own emulation. fallocate implementations can
2925 return ENOTSUP or EINVAL in cases like that. */
2926 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2927 if (ret == -1 && errno == ENOSPC) {
2928 return -1;
2930 if (ret == 0) {
2931 return 0;
2933 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2934 "error %d. Falling back to slow manual allocation\n", errno);
2936 /* available disk space is enough or not? */
2937 space_avail =
2938 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2939 /* space_avail is 1k blocks */
2940 if (space_avail == (uint64_t)-1 ||
2941 ((uint64_t)space_to_write/1024 > space_avail) ) {
2942 errno = ENOSPC;
2943 return -1;
2946 /* Write out the real space on disk. */
2947 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2948 if (ret != 0) {
2949 return -1;
2952 return 0;
2955 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2957 int result = -1;
2958 SMB_STRUCT_STAT *pst;
2959 NTSTATUS status;
2960 char c = 0;
2962 START_PROFILE(syscall_ftruncate);
2964 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2965 result = strict_allocate_ftruncate(handle, fsp, len);
2966 END_PROFILE(syscall_ftruncate);
2967 return result;
2970 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2971 ftruncate if the system supports it. Then I discovered that
2972 you can have some filesystems that support ftruncate
2973 expansion and some that don't! On Linux fat can't do
2974 ftruncate extend but ext2 can. */
2976 result = ftruncate(fsp_get_io_fd(fsp), len);
2978 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2979 extend a file with ftruncate. Provide alternate implementation
2980 for this */
2982 /* Do an fstat to see if the file is longer than the requested
2983 size in which case the ftruncate above should have
2984 succeeded or shorter, in which case seek to len - 1 and
2985 write 1 byte of zero */
2986 status = vfs_stat_fsp(fsp);
2987 if (!NT_STATUS_IS_OK(status)) {
2988 goto done;
2991 /* We need to update the files_struct after successful ftruncate */
2992 if (result == 0) {
2993 goto done;
2996 pst = &fsp->fsp_name->st;
2998 #ifdef S_ISFIFO
2999 if (S_ISFIFO(pst->st_ex_mode)) {
3000 result = 0;
3001 goto done;
3003 #endif
3005 if (pst->st_ex_size == len) {
3006 result = 0;
3007 goto done;
3010 if (pst->st_ex_size > len) {
3011 /* the ftruncate should have worked */
3012 goto done;
3015 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3016 goto done;
3019 result = 0;
3021 done:
3023 END_PROFILE(syscall_ftruncate);
3024 return result;
3027 static int vfswrap_fallocate(vfs_handle_struct *handle,
3028 files_struct *fsp,
3029 uint32_t mode,
3030 off_t offset,
3031 off_t len)
3033 int result;
3035 START_PROFILE(syscall_fallocate);
3036 if (mode == 0) {
3037 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3039 * posix_fallocate returns 0 on success, errno on error
3040 * and doesn't set errno. Make it behave like fallocate()
3041 * which returns -1, and sets errno on failure.
3043 if (result != 0) {
3044 errno = result;
3045 result = -1;
3047 } else {
3048 /* sys_fallocate handles filtering of unsupported mode flags */
3049 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3051 END_PROFILE(syscall_fallocate);
3052 return result;
3055 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3057 bool result;
3059 START_PROFILE(syscall_fcntl_lock);
3061 if (fsp->fsp_flags.use_ofd_locks) {
3062 op = map_process_lock_to_ofd_lock(op);
3065 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3066 END_PROFILE(syscall_fcntl_lock);
3067 return result;
3070 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3071 files_struct *fsp,
3072 uint32_t share_access,
3073 uint32_t access_mask)
3075 errno = ENOTSUP;
3076 return -1;
3079 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3080 va_list cmd_arg)
3082 void *argp;
3083 va_list dup_cmd_arg;
3084 int result;
3085 int val;
3087 START_PROFILE(syscall_fcntl);
3089 va_copy(dup_cmd_arg, cmd_arg);
3091 switch(cmd) {
3092 case F_SETLK:
3093 case F_SETLKW:
3094 case F_GETLK:
3095 #if defined(HAVE_OFD_LOCKS)
3096 case F_OFD_SETLK:
3097 case F_OFD_SETLKW:
3098 case F_OFD_GETLK:
3099 #endif
3100 #if defined(HAVE_F_OWNER_EX)
3101 case F_GETOWN_EX:
3102 case F_SETOWN_EX:
3103 #endif
3104 #if defined(HAVE_RW_HINTS)
3105 case F_GET_RW_HINT:
3106 case F_SET_RW_HINT:
3107 case F_GET_FILE_RW_HINT:
3108 case F_SET_FILE_RW_HINT:
3109 #endif
3110 argp = va_arg(dup_cmd_arg, void *);
3111 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3112 break;
3113 default:
3114 val = va_arg(dup_cmd_arg, int);
3115 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3118 va_end(dup_cmd_arg);
3120 END_PROFILE(syscall_fcntl);
3121 return result;
3124 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3126 bool result;
3127 int op = F_GETLK;
3129 START_PROFILE(syscall_fcntl_getlock);
3131 if (fsp->fsp_flags.use_ofd_locks) {
3132 op = map_process_lock_to_ofd_lock(op);
3135 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3136 END_PROFILE(syscall_fcntl_getlock);
3137 return result;
3140 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3141 int leasetype)
3143 int result = -1;
3145 START_PROFILE(syscall_linux_setlease);
3147 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3149 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3150 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3151 #else
3152 errno = ENOSYS;
3153 #endif
3154 END_PROFILE(syscall_linux_setlease);
3155 return result;
3158 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3159 const struct smb_filename *link_target,
3160 struct files_struct *dirfsp,
3161 const struct smb_filename *new_smb_fname)
3163 int result;
3165 START_PROFILE(syscall_symlinkat);
3167 SMB_ASSERT(!is_named_stream(new_smb_fname));
3169 result = symlinkat(link_target->base_name,
3170 fsp_get_pathref_fd(dirfsp),
3171 new_smb_fname->base_name);
3172 END_PROFILE(syscall_symlinkat);
3173 return result;
3176 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3177 const struct files_struct *dirfsp,
3178 const struct smb_filename *smb_fname,
3179 char *buf,
3180 size_t bufsiz)
3182 int result;
3184 START_PROFILE(syscall_readlinkat);
3186 SMB_ASSERT(!is_named_stream(smb_fname));
3188 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3189 smb_fname->base_name,
3190 buf,
3191 bufsiz);
3193 END_PROFILE(syscall_readlinkat);
3194 return result;
3197 static int vfswrap_linkat(vfs_handle_struct *handle,
3198 files_struct *srcfsp,
3199 const struct smb_filename *old_smb_fname,
3200 files_struct *dstfsp,
3201 const struct smb_filename *new_smb_fname,
3202 int flags)
3204 int result;
3206 START_PROFILE(syscall_linkat);
3208 SMB_ASSERT(!is_named_stream(old_smb_fname));
3209 SMB_ASSERT(!is_named_stream(new_smb_fname));
3211 result = linkat(fsp_get_pathref_fd(srcfsp),
3212 old_smb_fname->base_name,
3213 fsp_get_pathref_fd(dstfsp),
3214 new_smb_fname->base_name,
3215 flags);
3217 END_PROFILE(syscall_linkat);
3218 return result;
3221 static int vfswrap_mknodat(vfs_handle_struct *handle,
3222 files_struct *dirfsp,
3223 const struct smb_filename *smb_fname,
3224 mode_t mode,
3225 SMB_DEV_T dev)
3227 int result;
3229 START_PROFILE(syscall_mknodat);
3231 SMB_ASSERT(!is_named_stream(smb_fname));
3233 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3234 smb_fname->base_name,
3235 mode,
3236 dev);
3238 END_PROFILE(syscall_mknodat);
3239 return result;
3242 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3243 TALLOC_CTX *ctx,
3244 const struct smb_filename *smb_fname)
3246 char *result;
3247 struct smb_filename *result_fname = NULL;
3249 START_PROFILE(syscall_realpath);
3250 result = sys_realpath(smb_fname->base_name);
3251 END_PROFILE(syscall_realpath);
3252 if (result) {
3253 result_fname = synthetic_smb_fname(ctx,
3254 result,
3255 NULL,
3256 NULL,
3259 SAFE_FREE(result);
3261 return result_fname;
3264 static int vfswrap_fchflags(vfs_handle_struct *handle,
3265 struct files_struct *fsp,
3266 unsigned int flags)
3268 #ifdef HAVE_FCHFLAGS
3269 int fd = fsp_get_pathref_fd(fsp);
3271 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3273 if (!fsp->fsp_flags.is_pathref) {
3274 return fchflags(fd, flags);
3277 if (fsp->fsp_flags.have_proc_fds) {
3278 struct sys_proc_fd_path_buf buf;
3280 return chflags(sys_proc_fd_path(fd, &buf), flags);
3284 * This is no longer a handle based call.
3286 return chflags(fsp->fsp_name->base_name, flags);
3287 #else
3288 errno = ENOSYS;
3289 return -1;
3290 #endif
3293 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3294 const SMB_STRUCT_STAT *sbuf)
3296 struct file_id key;
3298 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3299 * blob */
3300 ZERO_STRUCT(key);
3302 key.devid = sbuf->st_ex_dev;
3303 key.inode = sbuf->st_ex_ino;
3304 /* key.extid is unused by default. */
3306 return key;
3309 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3310 const SMB_STRUCT_STAT *psbuf)
3312 uint64_t file_id;
3314 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3315 return (uint64_t)psbuf->st_ex_ino;
3318 /* FileIDLow */
3319 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3321 /* FileIDHigh */
3322 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3324 return file_id;
3327 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3328 struct files_struct *fsp,
3329 TALLOC_CTX *mem_ctx,
3330 unsigned int *pnum_streams,
3331 struct stream_struct **pstreams)
3333 struct stream_struct *tmp_streams = NULL;
3334 unsigned int num_streams = *pnum_streams;
3335 struct stream_struct *streams = *pstreams;
3336 NTSTATUS status;
3338 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3340 if (fsp->fsp_flags.is_directory) {
3342 * No default streams on directories
3344 goto done;
3346 status = vfs_stat_fsp(fsp);
3347 if (!NT_STATUS_IS_OK(status)) {
3348 return status;
3351 if (num_streams + 1 < 1) {
3352 /* Integer wrap. */
3353 return NT_STATUS_INVALID_PARAMETER;
3356 tmp_streams = talloc_realloc(mem_ctx,
3357 streams,
3358 struct stream_struct,
3359 num_streams + 1);
3360 if (tmp_streams == NULL) {
3361 return NT_STATUS_NO_MEMORY;
3363 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3364 if (tmp_streams[num_streams].name == NULL) {
3365 return NT_STATUS_NO_MEMORY;
3367 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3368 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3369 handle->conn,
3370 fsp,
3371 &fsp->fsp_name->st);
3372 num_streams += 1;
3374 *pnum_streams = num_streams;
3375 *pstreams = tmp_streams;
3376 done:
3377 return NT_STATUS_OK;
3380 static NTSTATUS vfswrap_get_real_filename_at(
3381 struct vfs_handle_struct *handle,
3382 struct files_struct *dirfsp,
3383 const char *name,
3384 TALLOC_CTX *mem_ctx,
3385 char **found_name)
3388 * Don't fall back to get_real_filename so callers can differentiate
3389 * between a full directory scan and an actual case-insensitive stat.
3391 return NT_STATUS_NOT_SUPPORTED;
3394 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3395 const struct files_struct *dirfsp,
3396 const struct smb_filename *smb_fname)
3398 return handle->conn->connectpath;
3401 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3402 struct byte_range_lock *br_lck,
3403 struct lock_struct *plock)
3405 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3407 /* Note: blr is not used in the default implementation. */
3408 return brl_lock_windows_default(br_lck, plock);
3411 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3412 struct byte_range_lock *br_lck,
3413 const struct lock_struct *plock)
3415 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3417 return brl_unlock_windows_default(br_lck, plock);
3420 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3421 files_struct *fsp,
3422 struct lock_struct *plock)
3424 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3425 plock->lock_type == WRITE_LOCK);
3427 return strict_lock_check_default(fsp, plock);
3430 /* NT ACL operations. */
3432 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3433 files_struct *fsp,
3434 uint32_t security_info,
3435 TALLOC_CTX *mem_ctx,
3436 struct security_descriptor **ppdesc)
3438 NTSTATUS result;
3440 START_PROFILE(fget_nt_acl);
3442 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3444 result = posix_fget_nt_acl(fsp, security_info,
3445 mem_ctx, ppdesc);
3446 END_PROFILE(fget_nt_acl);
3447 return result;
3450 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3452 NTSTATUS result;
3454 START_PROFILE(fset_nt_acl);
3456 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3458 result = set_nt_acl(fsp, security_info_sent, psd);
3459 END_PROFILE(fset_nt_acl);
3460 return result;
3463 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3464 struct smb_filename *file,
3465 struct security_acl *sacl,
3466 uint32_t access_requested,
3467 uint32_t access_denied)
3469 return NT_STATUS_OK; /* Nothing to do here ... */
3472 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3473 files_struct *fsp,
3474 SMB_ACL_TYPE_T type,
3475 TALLOC_CTX *mem_ctx)
3477 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3479 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3482 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3483 files_struct *fsp,
3484 SMB_ACL_TYPE_T type,
3485 SMB_ACL_T theacl)
3487 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3489 return sys_acl_set_fd(handle, fsp, type, theacl);
3492 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3493 files_struct *fsp)
3495 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3497 return sys_acl_delete_def_fd(handle, fsp);
3500 /****************************************************************
3501 Extended attribute operations.
3502 *****************************************************************/
3504 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3505 struct files_struct *fsp,
3506 const char *name,
3507 void *value,
3508 size_t size)
3510 int fd = fsp_get_pathref_fd(fsp);
3512 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3514 if (!fsp->fsp_flags.is_pathref) {
3515 return fgetxattr(fd, name, value, size);
3518 if (fsp->fsp_flags.have_proc_fds) {
3519 struct sys_proc_fd_path_buf buf;
3521 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3525 * This is no longer a handle based call.
3527 return getxattr(fsp->fsp_name->base_name, name, value, size);
3530 struct vfswrap_getxattrat_state {
3531 struct tevent_context *ev;
3532 struct vfs_handle_struct *handle;
3533 files_struct *dir_fsp;
3534 const struct smb_filename *smb_fname;
3537 * The following variables are talloced off "state" which is protected
3538 * by a destructor and thus are guaranteed to be safe to be used in the
3539 * job function in the worker thread.
3541 char *name;
3542 const char *xattr_name;
3543 uint8_t *xattr_value;
3544 struct security_unix_token *token;
3546 ssize_t xattr_size;
3547 struct vfs_aio_state vfs_aio_state;
3548 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3551 static int vfswrap_getxattrat_state_destructor(
3552 struct vfswrap_getxattrat_state *state)
3554 return -1;
3557 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3558 static void vfswrap_getxattrat_do_async(void *private_data);
3559 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3561 static struct tevent_req *vfswrap_getxattrat_send(
3562 TALLOC_CTX *mem_ctx,
3563 struct tevent_context *ev,
3564 struct vfs_handle_struct *handle,
3565 files_struct *dir_fsp,
3566 const struct smb_filename *smb_fname,
3567 const char *xattr_name,
3568 size_t alloc_hint)
3570 struct tevent_req *req = NULL;
3571 struct tevent_req *subreq = NULL;
3572 struct vfswrap_getxattrat_state *state = NULL;
3573 size_t max_threads = 0;
3574 bool have_per_thread_cwd = false;
3575 bool have_per_thread_creds = false;
3576 bool do_async = false;
3578 SMB_ASSERT(!is_named_stream(smb_fname));
3580 req = tevent_req_create(mem_ctx, &state,
3581 struct vfswrap_getxattrat_state);
3582 if (req == NULL) {
3583 return NULL;
3585 *state = (struct vfswrap_getxattrat_state) {
3586 .ev = ev,
3587 .handle = handle,
3588 .dir_fsp = dir_fsp,
3589 .smb_fname = smb_fname,
3592 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3593 if (max_threads >= 1) {
3595 * We need a non sync threadpool!
3597 have_per_thread_cwd = per_thread_cwd_supported();
3599 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3600 have_per_thread_creds = true;
3601 #endif
3602 if (have_per_thread_cwd && have_per_thread_creds) {
3603 do_async = true;
3606 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3607 state->profile_bytes, 0);
3609 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3610 DBG_ERR("Need a valid directory fd\n");
3611 tevent_req_error(req, EINVAL);
3612 return tevent_req_post(req, ev);
3615 if (alloc_hint > 0) {
3616 state->xattr_value = talloc_zero_array(state,
3617 uint8_t,
3618 alloc_hint);
3619 if (tevent_req_nomem(state->xattr_value, req)) {
3620 return tevent_req_post(req, ev);
3624 if (!do_async) {
3625 vfswrap_getxattrat_do_sync(req);
3626 return tevent_req_post(req, ev);
3630 * Now allocate all parameters from a memory context that won't go away
3631 * no matter what. These parameters will get used in threads and we
3632 * can't reliably cancel threads, so all buffers passed to the threads
3633 * must not be freed before all referencing threads terminate.
3636 state->name = talloc_strdup(state, smb_fname->base_name);
3637 if (tevent_req_nomem(state->name, req)) {
3638 return tevent_req_post(req, ev);
3641 state->xattr_name = talloc_strdup(state, xattr_name);
3642 if (tevent_req_nomem(state->xattr_name, req)) {
3643 return tevent_req_post(req, ev);
3647 * This is a hot codepath so at first glance one might think we should
3648 * somehow optimize away the token allocation and do a
3649 * talloc_reference() or similar black magic instead. But due to the
3650 * talloc_stackframe pool per SMB2 request this should be a simple copy
3651 * without a malloc in most cases.
3653 if (geteuid() == sec_initial_uid()) {
3654 state->token = root_unix_token(state);
3655 } else {
3656 state->token = copy_unix_token(
3657 state,
3658 dir_fsp->conn->session_info->unix_token);
3660 if (tevent_req_nomem(state->token, req)) {
3661 return tevent_req_post(req, ev);
3664 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3666 subreq = pthreadpool_tevent_job_send(
3667 state,
3669 dir_fsp->conn->sconn->pool,
3670 vfswrap_getxattrat_do_async,
3671 state);
3672 if (tevent_req_nomem(subreq, req)) {
3673 return tevent_req_post(req, ev);
3675 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3677 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3679 return req;
3682 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3684 struct vfswrap_getxattrat_state *state = tevent_req_data(
3685 req, struct vfswrap_getxattrat_state);
3687 state->xattr_size = vfswrap_fgetxattr(state->handle,
3688 state->smb_fname->fsp,
3689 state->xattr_name,
3690 state->xattr_value,
3691 talloc_array_length(state->xattr_value));
3692 if (state->xattr_size == -1) {
3693 tevent_req_error(req, errno);
3694 return;
3697 tevent_req_done(req);
3698 return;
3701 static void vfswrap_getxattrat_do_async(void *private_data)
3703 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3704 private_data, struct vfswrap_getxattrat_state);
3705 struct timespec start_time;
3706 struct timespec end_time;
3707 int ret;
3709 PROFILE_TIMESTAMP(&start_time);
3710 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3713 * Here we simulate a getxattrat()
3714 * call using fchdir();getxattr()
3717 per_thread_cwd_activate();
3719 /* Become the correct credential on this thread. */
3720 ret = set_thread_credentials(state->token->uid,
3721 state->token->gid,
3722 (size_t)state->token->ngroups,
3723 state->token->groups);
3724 if (ret != 0) {
3725 state->xattr_size = -1;
3726 state->vfs_aio_state.error = errno;
3727 goto end_profile;
3730 state->xattr_size = vfswrap_fgetxattr(state->handle,
3731 state->smb_fname->fsp,
3732 state->xattr_name,
3733 state->xattr_value,
3734 talloc_array_length(state->xattr_value));
3735 if (state->xattr_size == -1) {
3736 state->vfs_aio_state.error = errno;
3739 end_profile:
3740 PROFILE_TIMESTAMP(&end_time);
3741 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3742 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3745 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3747 struct tevent_req *req = tevent_req_callback_data(
3748 subreq, struct tevent_req);
3749 struct vfswrap_getxattrat_state *state = tevent_req_data(
3750 req, struct vfswrap_getxattrat_state);
3751 int ret;
3752 bool ok;
3755 * Make sure we run as the user again
3757 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3758 SMB_ASSERT(ok);
3760 ret = pthreadpool_tevent_job_recv(subreq);
3761 TALLOC_FREE(subreq);
3762 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3763 talloc_set_destructor(state, NULL);
3764 if (ret != 0) {
3765 if (ret != EAGAIN) {
3766 tevent_req_error(req, ret);
3767 return;
3770 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3771 * means the lower level pthreadpool failed to create a new
3772 * thread. Fallback to sync processing in that case to allow
3773 * some progress for the client.
3775 vfswrap_getxattrat_do_sync(req);
3776 return;
3779 if (state->xattr_size == -1) {
3780 tevent_req_error(req, state->vfs_aio_state.error);
3781 return;
3784 if (state->xattr_value == NULL) {
3786 * The caller only wanted the size.
3788 tevent_req_done(req);
3789 return;
3793 * shrink the buffer to the returned size.
3794 * (can't fail). It means NULL if size is 0.
3796 state->xattr_value = talloc_realloc(state,
3797 state->xattr_value,
3798 uint8_t,
3799 state->xattr_size);
3801 tevent_req_done(req);
3804 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3805 struct vfs_aio_state *aio_state,
3806 TALLOC_CTX *mem_ctx,
3807 uint8_t **xattr_value)
3809 struct vfswrap_getxattrat_state *state = tevent_req_data(
3810 req, struct vfswrap_getxattrat_state);
3811 ssize_t xattr_size;
3813 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3814 tevent_req_received(req);
3815 return -1;
3818 *aio_state = state->vfs_aio_state;
3819 xattr_size = state->xattr_size;
3820 if (xattr_value != NULL) {
3821 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3824 tevent_req_received(req);
3825 return xattr_size;
3828 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3830 int fd = fsp_get_pathref_fd(fsp);
3832 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3834 if (!fsp->fsp_flags.is_pathref) {
3835 return flistxattr(fd, list, size);
3838 if (fsp->fsp_flags.have_proc_fds) {
3839 struct sys_proc_fd_path_buf buf;
3841 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3845 * This is no longer a handle based call.
3847 return listxattr(fsp->fsp_name->base_name, list, size);
3850 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3852 int fd = fsp_get_pathref_fd(fsp);
3854 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3856 if (!fsp->fsp_flags.is_pathref) {
3857 return fremovexattr(fd, name);
3860 if (fsp->fsp_flags.have_proc_fds) {
3861 struct sys_proc_fd_path_buf buf;
3863 return removexattr(sys_proc_fd_path(fd, &buf), name);
3867 * This is no longer a handle based call.
3869 return removexattr(fsp->fsp_name->base_name, name);
3872 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3874 int fd = fsp_get_pathref_fd(fsp);
3876 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3878 if (!fsp->fsp_flags.is_pathref) {
3879 return fsetxattr(fd, name, value, size, flags);
3882 if (fsp->fsp_flags.have_proc_fds) {
3883 struct sys_proc_fd_path_buf buf;
3885 return setxattr(sys_proc_fd_path(fd, &buf),
3886 name,
3887 value,
3888 size,
3889 flags);
3893 * This is no longer a handle based call.
3895 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3898 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3900 return false;
3903 static bool vfswrap_is_offline(struct connection_struct *conn,
3904 const struct smb_filename *fname)
3906 NTSTATUS status;
3907 char *path;
3908 bool offline = false;
3910 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3911 return false;
3914 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3915 #if defined(ENOTSUP)
3916 errno = ENOTSUP;
3917 #endif
3918 return false;
3921 status = get_full_smb_filename(talloc_tos(), fname, &path);
3922 if (!NT_STATUS_IS_OK(status)) {
3923 errno = map_errno_from_nt_status(status);
3924 return false;
3927 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3929 TALLOC_FREE(path);
3931 return offline;
3934 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3935 struct files_struct *fsp,
3936 TALLOC_CTX *mem_ctx,
3937 DATA_BLOB *cookie)
3939 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3942 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3943 struct files_struct *fsp,
3944 const DATA_BLOB old_cookie,
3945 TALLOC_CTX *mem_ctx,
3946 DATA_BLOB *new_cookie)
3948 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3949 new_cookie);
3952 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3953 struct smb_request *smb1req,
3954 struct smbXsrv_open *op,
3955 const DATA_BLOB old_cookie,
3956 TALLOC_CTX *mem_ctx,
3957 struct files_struct **fsp,
3958 DATA_BLOB *new_cookie)
3960 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3961 old_cookie, mem_ctx,
3962 fsp, new_cookie);
3965 static struct vfs_fn_pointers vfs_default_fns = {
3966 /* Disk operations */
3968 .connect_fn = vfswrap_connect,
3969 .disconnect_fn = vfswrap_disconnect,
3970 .disk_free_fn = vfswrap_disk_free,
3971 .get_quota_fn = vfswrap_get_quota,
3972 .set_quota_fn = vfswrap_set_quota,
3973 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3974 .statvfs_fn = vfswrap_statvfs,
3975 .fs_capabilities_fn = vfswrap_fs_capabilities,
3976 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3977 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3978 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3979 .snap_check_path_fn = vfswrap_snap_check_path,
3980 .snap_create_fn = vfswrap_snap_create,
3981 .snap_delete_fn = vfswrap_snap_delete,
3983 /* Directory operations */
3985 .fdopendir_fn = vfswrap_fdopendir,
3986 .readdir_fn = vfswrap_readdir,
3987 .freaddir_attr_fn = vfswrap_freaddir_attr,
3988 .rewind_dir_fn = vfswrap_rewinddir,
3989 .mkdirat_fn = vfswrap_mkdirat,
3990 .closedir_fn = vfswrap_closedir,
3992 /* File operations */
3994 .openat_fn = vfswrap_openat,
3995 .create_file_fn = vfswrap_create_file,
3996 .close_fn = vfswrap_close,
3997 .pread_fn = vfswrap_pread,
3998 .pread_send_fn = vfswrap_pread_send,
3999 .pread_recv_fn = vfswrap_pread_recv,
4000 .pwrite_fn = vfswrap_pwrite,
4001 .pwrite_send_fn = vfswrap_pwrite_send,
4002 .pwrite_recv_fn = vfswrap_pwrite_recv,
4003 .lseek_fn = vfswrap_lseek,
4004 .sendfile_fn = vfswrap_sendfile,
4005 .recvfile_fn = vfswrap_recvfile,
4006 .renameat_fn = vfswrap_renameat,
4007 .fsync_send_fn = vfswrap_fsync_send,
4008 .fsync_recv_fn = vfswrap_fsync_recv,
4009 .stat_fn = vfswrap_stat,
4010 .fstat_fn = vfswrap_fstat,
4011 .lstat_fn = vfswrap_lstat,
4012 .fstatat_fn = vfswrap_fstatat,
4013 .get_alloc_size_fn = vfswrap_get_alloc_size,
4014 .unlinkat_fn = vfswrap_unlinkat,
4015 .fchmod_fn = vfswrap_fchmod,
4016 .fchown_fn = vfswrap_fchown,
4017 .lchown_fn = vfswrap_lchown,
4018 .chdir_fn = vfswrap_chdir,
4019 .getwd_fn = vfswrap_getwd,
4020 .fntimes_fn = vfswrap_fntimes,
4021 .ftruncate_fn = vfswrap_ftruncate,
4022 .fallocate_fn = vfswrap_fallocate,
4023 .lock_fn = vfswrap_lock,
4024 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4025 .fcntl_fn = vfswrap_fcntl,
4026 .linux_setlease_fn = vfswrap_linux_setlease,
4027 .getlock_fn = vfswrap_getlock,
4028 .symlinkat_fn = vfswrap_symlinkat,
4029 .readlinkat_fn = vfswrap_readlinkat,
4030 .linkat_fn = vfswrap_linkat,
4031 .mknodat_fn = vfswrap_mknodat,
4032 .realpath_fn = vfswrap_realpath,
4033 .fchflags_fn = vfswrap_fchflags,
4034 .file_id_create_fn = vfswrap_file_id_create,
4035 .fs_file_id_fn = vfswrap_fs_file_id,
4036 .fstreaminfo_fn = vfswrap_fstreaminfo,
4037 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4038 .connectpath_fn = vfswrap_connectpath,
4039 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4040 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4041 .strict_lock_check_fn = vfswrap_strict_lock_check,
4042 .translate_name_fn = vfswrap_translate_name,
4043 .parent_pathname_fn = vfswrap_parent_pathname,
4044 .fsctl_fn = vfswrap_fsctl,
4045 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4046 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4047 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4048 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4049 .offload_read_send_fn = vfswrap_offload_read_send,
4050 .offload_read_recv_fn = vfswrap_offload_read_recv,
4051 .offload_write_send_fn = vfswrap_offload_write_send,
4052 .offload_write_recv_fn = vfswrap_offload_write_recv,
4053 .fget_compression_fn = vfswrap_fget_compression,
4054 .set_compression_fn = vfswrap_set_compression,
4056 /* NT ACL operations. */
4058 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4059 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4060 .audit_file_fn = vfswrap_audit_file,
4062 /* POSIX ACL operations. */
4064 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4065 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4066 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4067 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4069 /* EA operations. */
4070 .getxattrat_send_fn = vfswrap_getxattrat_send,
4071 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4072 .fgetxattr_fn = vfswrap_fgetxattr,
4073 .flistxattr_fn = vfswrap_flistxattr,
4074 .fremovexattr_fn = vfswrap_fremovexattr,
4075 .fsetxattr_fn = vfswrap_fsetxattr,
4077 /* aio operations */
4078 .aio_force_fn = vfswrap_aio_force,
4080 /* durable handle operations */
4081 .durable_cookie_fn = vfswrap_durable_cookie,
4082 .durable_disconnect_fn = vfswrap_durable_disconnect,
4083 .durable_reconnect_fn = vfswrap_durable_reconnect,
4086 static_decl_vfs;
4087 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4090 * Here we need to implement every call!
4092 * As this is the end of the vfs module chain.
4094 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4095 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4096 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);