s3:registry: Initialize struct security_ace ace[]
[samba4-gss.git] / source3 / modules / vfs_default.c
blobe0ebc7bd1a278a3dcb3749faf9aa698cc31982df
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 status = vfs_offload_token_ctx_init(handle->conn->sconn->client,
2152 &vfswrap_offload_ctx);
2153 if (tevent_req_nterror(req, status)) {
2154 return tevent_req_post(req, ev);
2157 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2159 switch (fsctl) {
2160 case FSCTL_SRV_COPYCHUNK:
2161 case FSCTL_SRV_COPYCHUNK_WRITE:
2162 break;
2164 case FSCTL_OFFLOAD_WRITE:
2165 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2166 return tevent_req_post(req, ev);
2168 case FSCTL_DUP_EXTENTS_TO_FILE:
2169 DBG_DEBUG("COW clones not supported by vfs_default\n");
2170 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2171 return tevent_req_post(req, ev);
2173 default:
2174 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2175 return tevent_req_post(req, ev);
2179 * From here on we assume a copy-chunk fsctl
2182 if (to_copy == 0) {
2183 tevent_req_done(req);
2184 return tevent_req_post(req, ev);
2187 if (state->src_off > max_offset) {
2189 * Protect integer checks below.
2191 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2192 return tevent_req_post(req, ev);
2194 if (state->src_off < 0) {
2196 * Protect integer checks below.
2198 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2199 return tevent_req_post(req, ev);
2201 if (state->dst_off > max_offset) {
2203 * Protect integer checks below.
2205 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2206 return tevent_req_post(req, ev);
2208 if (state->dst_off < 0) {
2210 * Protect integer checks below.
2212 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2213 return tevent_req_post(req, ev);
2216 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2217 token, &src_fsp);
2218 if (tevent_req_nterror(req, status)) {
2219 return tevent_req_post(req, ev);
2222 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2224 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2225 if (!NT_STATUS_IS_OK(status)) {
2226 tevent_req_nterror(req, status);
2227 return tevent_req_post(req, ev);
2230 ok = change_to_user_and_service_by_fsp(src_fsp);
2231 if (!ok) {
2232 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2233 return tevent_req_post(req, ev);
2236 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2237 state->src_fsp = src_fsp;
2239 status = vfs_stat_fsp(src_fsp);
2240 if (tevent_req_nterror(req, status)) {
2241 return tevent_req_post(req, ev);
2244 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2246 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2247 * If the SourceOffset or SourceOffset + Length extends beyond
2248 * the end of file, the server SHOULD<240> treat this as a
2249 * STATUS_END_OF_FILE error.
2250 * ...
2251 * <240> Section 3.3.5.15.6: Windows servers will return
2252 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2254 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2255 return tevent_req_post(req, ev);
2258 status = vfswrap_offload_copy_file_range(req);
2259 if (NT_STATUS_IS_OK(status)) {
2260 tevent_req_done(req);
2261 return tevent_req_post(req, ev);
2263 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2264 tevent_req_nterror(req, status);
2265 return tevent_req_post(req, ev);
2268 state->buf = talloc_array(state, uint8_t, num);
2269 if (tevent_req_nomem(state->buf, req)) {
2270 return tevent_req_post(req, ev);
2273 status = vfswrap_offload_write_loop(req);
2274 if (!NT_STATUS_IS_OK(status)) {
2275 tevent_req_nterror(req, status);
2276 return tevent_req_post(req, ev);
2279 return req;
2282 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2284 struct vfswrap_offload_write_state *state = tevent_req_data(
2285 req, struct vfswrap_offload_write_state);
2286 struct lock_struct lck;
2287 ssize_t nwritten;
2288 NTSTATUS status;
2289 bool same_file;
2290 bool ok;
2291 static bool try_copy_file_range = true;
2293 if (!try_copy_file_range) {
2294 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2297 same_file = file_id_equal(&state->src_fsp->file_id,
2298 &state->dst_fsp->file_id);
2299 if (same_file &&
2300 sys_io_ranges_overlap(state->remaining,
2301 state->src_off,
2302 state->remaining,
2303 state->dst_off))
2305 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2308 if (fsp_is_alternate_stream(state->src_fsp) ||
2309 fsp_is_alternate_stream(state->dst_fsp))
2311 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2314 init_strict_lock_struct(state->src_fsp,
2315 state->src_fsp->op->global->open_persistent_id,
2316 state->src_off,
2317 state->remaining,
2318 READ_LOCK,
2319 lp_posix_cifsu_locktype(state->src_fsp),
2320 &lck);
2322 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2323 state->src_fsp,
2324 &lck);
2325 if (!ok) {
2326 return NT_STATUS_FILE_LOCK_CONFLICT;
2329 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2330 if (!ok) {
2331 return NT_STATUS_INTERNAL_ERROR;
2334 init_strict_lock_struct(state->dst_fsp,
2335 state->dst_fsp->op->global->open_persistent_id,
2336 state->dst_off,
2337 state->remaining,
2338 WRITE_LOCK,
2339 lp_posix_cifsu_locktype(state->dst_fsp),
2340 &lck);
2342 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2343 state->dst_fsp,
2344 &lck);
2345 if (!ok) {
2346 return NT_STATUS_FILE_LOCK_CONFLICT;
2349 while (state->remaining > 0) {
2350 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2351 &state->src_off,
2352 fsp_get_io_fd(state->dst_fsp),
2353 &state->dst_off,
2354 state->remaining,
2356 if (nwritten == -1) {
2357 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2358 "n [%jd] failed: %s\n",
2359 fsp_str_dbg(state->src_fsp),
2360 (intmax_t)state->src_off,
2361 fsp_str_dbg(state->dst_fsp),
2362 (intmax_t)state->dst_off,
2363 (intmax_t)state->remaining,
2364 strerror(errno));
2365 switch (errno) {
2366 case EOPNOTSUPP:
2367 case ENOSYS:
2368 try_copy_file_range = false;
2369 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2370 break;
2371 case EXDEV:
2372 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2373 break;
2374 default:
2375 status = map_nt_error_from_unix(errno);
2376 if (NT_STATUS_EQUAL(
2377 status,
2378 NT_STATUS_MORE_PROCESSING_REQUIRED))
2380 /* Avoid triggering the fallback */
2381 status = NT_STATUS_INTERNAL_ERROR;
2383 break;
2385 return status;
2388 if (state->remaining < nwritten) {
2389 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2390 "n [%jd] remaining [%jd]\n",
2391 fsp_str_dbg(state->src_fsp),
2392 fsp_str_dbg(state->dst_fsp),
2393 (intmax_t)nwritten,
2394 (intmax_t)state->remaining);
2395 return NT_STATUS_INTERNAL_ERROR;
2398 if (nwritten == 0) {
2399 break;
2401 state->copied += nwritten;
2402 state->remaining -= nwritten;
2406 * Tell the req cleanup function there's no need to call
2407 * change_to_user_and_service_by_fsp() on the dst handle.
2409 state->dst_fsp = NULL;
2410 return NT_STATUS_OK;
2413 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2415 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2417 struct vfswrap_offload_write_state *state = tevent_req_data(
2418 req, struct vfswrap_offload_write_state);
2419 struct tevent_req *subreq = NULL;
2420 struct lock_struct read_lck;
2421 bool ok;
2424 * This is called under the context of state->src_fsp.
2427 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2429 init_strict_lock_struct(state->src_fsp,
2430 state->src_fsp->op->global->open_persistent_id,
2431 state->src_off,
2432 state->next_io_size,
2433 READ_LOCK,
2434 lp_posix_cifsu_locktype(state->src_fsp),
2435 &read_lck);
2437 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2438 state->src_fsp,
2439 &read_lck);
2440 if (!ok) {
2441 return NT_STATUS_FILE_LOCK_CONFLICT;
2444 subreq = SMB_VFS_PREAD_SEND(state,
2445 state->src_ev,
2446 state->src_fsp,
2447 state->buf,
2448 state->next_io_size,
2449 state->src_off);
2450 if (subreq == NULL) {
2451 return NT_STATUS_NO_MEMORY;
2453 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2455 return NT_STATUS_OK;
2458 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2460 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2462 struct tevent_req *req = tevent_req_callback_data(
2463 subreq, struct tevent_req);
2464 struct vfswrap_offload_write_state *state = tevent_req_data(
2465 req, struct vfswrap_offload_write_state);
2466 struct vfs_aio_state aio_state;
2467 struct lock_struct write_lck;
2468 ssize_t nread;
2469 bool ok;
2471 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2472 TALLOC_FREE(subreq);
2473 if (nread == -1) {
2474 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2475 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2476 return;
2478 if (nread != state->next_io_size) {
2479 DBG_ERR("Short read, only %zd of %zu\n",
2480 nread, state->next_io_size);
2481 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2482 return;
2485 state->src_off += nread;
2487 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2488 if (!ok) {
2489 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2490 return;
2493 init_strict_lock_struct(state->dst_fsp,
2494 state->dst_fsp->op->global->open_persistent_id,
2495 state->dst_off,
2496 state->next_io_size,
2497 WRITE_LOCK,
2498 lp_posix_cifsu_locktype(state->dst_fsp),
2499 &write_lck);
2501 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2502 state->dst_fsp,
2503 &write_lck);
2504 if (!ok) {
2505 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2506 return;
2509 subreq = SMB_VFS_PWRITE_SEND(state,
2510 state->dst_ev,
2511 state->dst_fsp,
2512 state->buf,
2513 state->next_io_size,
2514 state->dst_off);
2515 if (subreq == NULL) {
2516 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2517 return;
2519 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2522 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2524 struct tevent_req *req = tevent_req_callback_data(
2525 subreq, struct tevent_req);
2526 struct vfswrap_offload_write_state *state = tevent_req_data(
2527 req, struct vfswrap_offload_write_state);
2528 struct vfs_aio_state aio_state;
2529 ssize_t nwritten;
2530 NTSTATUS status;
2531 bool ok;
2533 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2534 TALLOC_FREE(subreq);
2535 if (nwritten == -1) {
2536 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2537 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2538 return;
2540 if (nwritten != state->next_io_size) {
2541 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2542 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2543 return;
2546 state->dst_off += nwritten;
2548 if (state->remaining < nwritten) {
2549 /* Paranoia check */
2550 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2551 return;
2553 state->copied += nwritten;
2554 state->remaining -= nwritten;
2555 if (state->remaining == 0) {
2556 tevent_req_done(req);
2557 return;
2560 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2561 if (!ok) {
2562 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2563 return;
2566 status = vfswrap_offload_write_loop(req);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 tevent_req_nterror(req, status);
2569 return;
2572 return;
2575 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2576 struct tevent_req *req,
2577 off_t *copied)
2579 struct vfswrap_offload_write_state *state = tevent_req_data(
2580 req, struct vfswrap_offload_write_state);
2581 NTSTATUS status;
2583 if (tevent_req_is_nterror(req, &status)) {
2584 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2585 *copied = 0;
2586 tevent_req_received(req);
2587 return status;
2590 *copied = state->copied;
2591 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2592 tevent_req_received(req);
2594 return NT_STATUS_OK;
2597 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2598 TALLOC_CTX *mem_ctx,
2599 struct files_struct *fsp,
2600 uint16_t *_compression_fmt)
2602 return NT_STATUS_INVALID_DEVICE_REQUEST;
2605 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2606 TALLOC_CTX *mem_ctx,
2607 struct files_struct *fsp,
2608 uint16_t compression_fmt)
2610 return NT_STATUS_INVALID_DEVICE_REQUEST;
2613 /********************************************************************
2614 Given a stat buffer return the allocated size on disk, taking into
2615 account sparse files.
2616 ********************************************************************/
2617 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2618 struct files_struct *fsp,
2619 const SMB_STRUCT_STAT *sbuf)
2621 uint64_t result;
2623 START_PROFILE(syscall_get_alloc_size);
2625 if(S_ISDIR(sbuf->st_ex_mode)) {
2626 result = 0;
2627 goto out;
2630 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2631 /* The type of st_blocksize is blkcnt_t which *MUST* be
2632 signed (according to POSIX) and can be less than 64-bits.
2633 Ensure when we're converting to 64 bits wide we don't
2634 sign extend. */
2635 #if defined(SIZEOF_BLKCNT_T_8)
2636 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2637 #elif defined(SIZEOF_BLKCNT_T_4)
2639 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2640 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2642 #else
2643 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2644 #endif
2645 if (result == 0) {
2647 * Some file systems do not allocate a block for very
2648 * small files. But for non-empty file should report a
2649 * positive size.
2652 uint64_t filesize = get_file_size_stat(sbuf);
2653 if (filesize > 0) {
2654 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2657 #else
2658 result = get_file_size_stat(sbuf);
2659 #endif
2661 if (fsp && fsp->initial_allocation_size)
2662 result = MAX(result,fsp->initial_allocation_size);
2664 result = smb_roundup(handle->conn, result);
2666 out:
2667 END_PROFILE(syscall_get_alloc_size);
2668 return result;
2671 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2672 struct files_struct *dirfsp,
2673 const struct smb_filename *smb_fname,
2674 int flags)
2676 int result = -1;
2678 START_PROFILE(syscall_unlinkat);
2680 SMB_ASSERT(!is_named_stream(smb_fname));
2682 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2683 smb_fname->base_name,
2684 flags);
2686 END_PROFILE(syscall_unlinkat);
2687 return result;
2690 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2692 int result;
2694 START_PROFILE(syscall_fchmod);
2696 if (!fsp->fsp_flags.is_pathref) {
2697 result = fchmod(fsp_get_io_fd(fsp), mode);
2698 END_PROFILE(syscall_fchmod);
2699 return result;
2702 if (fsp->fsp_flags.have_proc_fds) {
2703 int fd = fsp_get_pathref_fd(fsp);
2704 struct sys_proc_fd_path_buf buf;
2706 result = chmod(sys_proc_fd_path(fd, &buf), mode);
2708 END_PROFILE(syscall_fchmod);
2709 return result;
2713 * This is no longer a handle based call.
2715 result = chmod(fsp->fsp_name->base_name, mode);
2717 END_PROFILE(syscall_fchmod);
2718 return result;
2721 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2723 #ifdef HAVE_FCHOWN
2724 int result;
2726 START_PROFILE(syscall_fchown);
2727 if (!fsp->fsp_flags.is_pathref) {
2728 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2729 END_PROFILE(syscall_fchown);
2730 return result;
2733 if (fsp->fsp_flags.have_proc_fds) {
2734 int fd = fsp_get_pathref_fd(fsp);
2735 struct sys_proc_fd_path_buf buf;
2737 result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2739 END_PROFILE(syscall_fchown);
2740 return result;
2744 * This is no longer a handle based call.
2746 result = chown(fsp->fsp_name->base_name, uid, gid);
2747 END_PROFILE(syscall_fchown);
2748 return result;
2749 #else
2750 errno = ENOSYS;
2751 return -1;
2752 #endif
2755 static int vfswrap_lchown(vfs_handle_struct *handle,
2756 const struct smb_filename *smb_fname,
2757 uid_t uid,
2758 gid_t gid)
2760 int result;
2762 START_PROFILE(syscall_lchown);
2763 result = lchown(smb_fname->base_name, uid, gid);
2764 END_PROFILE(syscall_lchown);
2765 return result;
2768 static int vfswrap_chdir(vfs_handle_struct *handle,
2769 const struct smb_filename *smb_fname)
2771 int result;
2773 START_PROFILE(syscall_chdir);
2774 result = chdir(smb_fname->base_name);
2775 END_PROFILE(syscall_chdir);
2776 return result;
2779 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2780 TALLOC_CTX *ctx)
2782 char *result;
2783 struct smb_filename *smb_fname = NULL;
2785 START_PROFILE(syscall_getwd);
2786 result = sys_getwd();
2787 END_PROFILE(syscall_getwd);
2789 if (result == NULL) {
2790 return NULL;
2792 smb_fname = synthetic_smb_fname(ctx,
2793 result,
2794 NULL,
2795 NULL,
2799 * sys_getwd() *always* returns malloced memory.
2800 * We must free here to avoid leaks:
2801 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2803 SAFE_FREE(result);
2804 return smb_fname;
2807 /*********************************************************************
2808 nsec timestamp resolution call. Convert down to whatever the underlying
2809 system will support.
2810 **********************************************************************/
2812 static int vfswrap_fntimes(vfs_handle_struct *handle,
2813 files_struct *fsp,
2814 struct smb_file_time *ft)
2816 int result = -1;
2817 struct timespec ts[2];
2818 struct timespec *times = NULL;
2820 START_PROFILE(syscall_fntimes);
2822 if (fsp_is_alternate_stream(fsp)) {
2823 errno = ENOENT;
2824 goto out;
2827 if (ft != NULL) {
2828 if (is_omit_timespec(&ft->atime)) {
2829 ft->atime = fsp->fsp_name->st.st_ex_atime;
2832 if (is_omit_timespec(&ft->mtime)) {
2833 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2836 if (!is_omit_timespec(&ft->create_time)) {
2837 set_create_timespec_ea(fsp,
2838 ft->create_time);
2841 if ((timespec_compare(&ft->atime,
2842 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2843 (timespec_compare(&ft->mtime,
2844 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2845 result = 0;
2846 goto out;
2849 ts[0] = ft->atime;
2850 ts[1] = ft->mtime;
2851 times = ts;
2852 } else {
2853 times = NULL;
2856 if (!fsp->fsp_flags.is_pathref) {
2857 result = futimens(fsp_get_io_fd(fsp), times);
2858 goto out;
2861 if (fsp->fsp_flags.have_proc_fds) {
2862 int fd = fsp_get_pathref_fd(fsp);
2863 struct sys_proc_fd_path_buf buf;
2865 result = utimensat(AT_FDCWD,
2866 sys_proc_fd_path(fd, &buf),
2867 times,
2870 goto out;
2874 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2875 * path translation mechanism. Fallback to path based call.
2877 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2879 out:
2880 END_PROFILE(syscall_fntimes);
2882 return result;
2886 /*********************************************************************
2887 A version of ftruncate that will write the space on disk if strict
2888 allocate is set.
2889 **********************************************************************/
2891 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2893 off_t space_to_write;
2894 uint64_t space_avail;
2895 uint64_t bsize,dfree,dsize;
2896 int ret;
2897 NTSTATUS status;
2898 SMB_STRUCT_STAT *pst;
2899 bool ok;
2901 ok = vfs_valid_pwrite_range(len, 0);
2902 if (!ok) {
2903 errno = EINVAL;
2904 return -1;
2907 status = vfs_stat_fsp(fsp);
2908 if (!NT_STATUS_IS_OK(status)) {
2909 return -1;
2911 pst = &fsp->fsp_name->st;
2913 #ifdef S_ISFIFO
2914 if (S_ISFIFO(pst->st_ex_mode))
2915 return 0;
2916 #endif
2918 if (pst->st_ex_size == len)
2919 return 0;
2921 /* Shrink - just ftruncate. */
2922 if (pst->st_ex_size > len)
2923 return ftruncate(fsp_get_io_fd(fsp), len);
2925 space_to_write = len - pst->st_ex_size;
2927 /* for allocation try fallocate first. This can fail on some
2928 platforms e.g. when the filesystem doesn't support it and no
2929 emulation is being done by the libc (like on AIX with JFS1). In that
2930 case we do our own emulation. fallocate implementations can
2931 return ENOTSUP or EINVAL in cases like that. */
2932 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2933 if (ret == -1 && errno == ENOSPC) {
2934 return -1;
2936 if (ret == 0) {
2937 return 0;
2939 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2940 "error %d. Falling back to slow manual allocation\n", errno);
2942 /* available disk space is enough or not? */
2943 space_avail =
2944 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2945 /* space_avail is 1k blocks */
2946 if (space_avail == (uint64_t)-1 ||
2947 ((uint64_t)space_to_write/1024 > space_avail) ) {
2948 errno = ENOSPC;
2949 return -1;
2952 /* Write out the real space on disk. */
2953 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2954 if (ret != 0) {
2955 return -1;
2958 return 0;
2961 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2963 int result = -1;
2964 SMB_STRUCT_STAT *pst;
2965 NTSTATUS status;
2966 char c = 0;
2968 START_PROFILE(syscall_ftruncate);
2970 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2971 result = strict_allocate_ftruncate(handle, fsp, len);
2972 END_PROFILE(syscall_ftruncate);
2973 return result;
2976 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2977 ftruncate if the system supports it. Then I discovered that
2978 you can have some filesystems that support ftruncate
2979 expansion and some that don't! On Linux fat can't do
2980 ftruncate extend but ext2 can. */
2982 result = ftruncate(fsp_get_io_fd(fsp), len);
2984 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2985 extend a file with ftruncate. Provide alternate implementation
2986 for this */
2988 /* Do an fstat to see if the file is longer than the requested
2989 size in which case the ftruncate above should have
2990 succeeded or shorter, in which case seek to len - 1 and
2991 write 1 byte of zero */
2992 status = vfs_stat_fsp(fsp);
2993 if (!NT_STATUS_IS_OK(status)) {
2994 goto done;
2997 /* We need to update the files_struct after successful ftruncate */
2998 if (result == 0) {
2999 goto done;
3002 pst = &fsp->fsp_name->st;
3004 #ifdef S_ISFIFO
3005 if (S_ISFIFO(pst->st_ex_mode)) {
3006 result = 0;
3007 goto done;
3009 #endif
3011 if (pst->st_ex_size == len) {
3012 result = 0;
3013 goto done;
3016 if (pst->st_ex_size > len) {
3017 /* the ftruncate should have worked */
3018 goto done;
3021 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3022 goto done;
3025 result = 0;
3027 done:
3029 END_PROFILE(syscall_ftruncate);
3030 return result;
3033 static int vfswrap_fallocate(vfs_handle_struct *handle,
3034 files_struct *fsp,
3035 uint32_t mode,
3036 off_t offset,
3037 off_t len)
3039 int result;
3041 START_PROFILE(syscall_fallocate);
3042 if (mode == 0) {
3043 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3045 * posix_fallocate returns 0 on success, errno on error
3046 * and doesn't set errno. Make it behave like fallocate()
3047 * which returns -1, and sets errno on failure.
3049 if (result != 0) {
3050 errno = result;
3051 result = -1;
3053 } else {
3054 /* sys_fallocate handles filtering of unsupported mode flags */
3055 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3057 END_PROFILE(syscall_fallocate);
3058 return result;
3061 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3063 bool result;
3065 START_PROFILE(syscall_fcntl_lock);
3067 if (fsp->fsp_flags.use_ofd_locks) {
3068 op = map_process_lock_to_ofd_lock(op);
3071 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3072 END_PROFILE(syscall_fcntl_lock);
3073 return result;
3076 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3077 files_struct *fsp,
3078 uint32_t share_access,
3079 uint32_t access_mask)
3081 errno = ENOTSUP;
3082 return -1;
3085 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3086 va_list cmd_arg)
3088 void *argp;
3089 va_list dup_cmd_arg;
3090 int result;
3091 int val;
3093 START_PROFILE(syscall_fcntl);
3095 va_copy(dup_cmd_arg, cmd_arg);
3097 switch(cmd) {
3098 case F_SETLK:
3099 case F_SETLKW:
3100 case F_GETLK:
3101 #if defined(HAVE_OFD_LOCKS)
3102 case F_OFD_SETLK:
3103 case F_OFD_SETLKW:
3104 case F_OFD_GETLK:
3105 #endif
3106 #if defined(HAVE_F_OWNER_EX)
3107 case F_GETOWN_EX:
3108 case F_SETOWN_EX:
3109 #endif
3110 #if defined(HAVE_RW_HINTS)
3111 case F_GET_RW_HINT:
3112 case F_SET_RW_HINT:
3113 case F_GET_FILE_RW_HINT:
3114 case F_SET_FILE_RW_HINT:
3115 #endif
3116 argp = va_arg(dup_cmd_arg, void *);
3117 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3118 break;
3119 default:
3120 val = va_arg(dup_cmd_arg, int);
3121 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3124 va_end(dup_cmd_arg);
3126 END_PROFILE(syscall_fcntl);
3127 return result;
3130 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3132 bool result;
3133 int op = F_GETLK;
3135 START_PROFILE(syscall_fcntl_getlock);
3137 if (fsp->fsp_flags.use_ofd_locks) {
3138 op = map_process_lock_to_ofd_lock(op);
3141 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3142 END_PROFILE(syscall_fcntl_getlock);
3143 return result;
3146 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3147 int leasetype)
3149 int result = -1;
3151 START_PROFILE(syscall_linux_setlease);
3153 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3155 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3156 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3157 #else
3158 errno = ENOSYS;
3159 #endif
3160 END_PROFILE(syscall_linux_setlease);
3161 return result;
3164 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3165 const struct smb_filename *link_target,
3166 struct files_struct *dirfsp,
3167 const struct smb_filename *new_smb_fname)
3169 int result;
3171 START_PROFILE(syscall_symlinkat);
3173 SMB_ASSERT(!is_named_stream(new_smb_fname));
3175 result = symlinkat(link_target->base_name,
3176 fsp_get_pathref_fd(dirfsp),
3177 new_smb_fname->base_name);
3178 END_PROFILE(syscall_symlinkat);
3179 return result;
3182 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3183 const struct files_struct *dirfsp,
3184 const struct smb_filename *smb_fname,
3185 char *buf,
3186 size_t bufsiz)
3188 int result;
3190 START_PROFILE(syscall_readlinkat);
3192 SMB_ASSERT(!is_named_stream(smb_fname));
3194 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3195 smb_fname->base_name,
3196 buf,
3197 bufsiz);
3199 END_PROFILE(syscall_readlinkat);
3200 return result;
3203 static int vfswrap_linkat(vfs_handle_struct *handle,
3204 files_struct *srcfsp,
3205 const struct smb_filename *old_smb_fname,
3206 files_struct *dstfsp,
3207 const struct smb_filename *new_smb_fname,
3208 int flags)
3210 int result;
3212 START_PROFILE(syscall_linkat);
3214 SMB_ASSERT(!is_named_stream(old_smb_fname));
3215 SMB_ASSERT(!is_named_stream(new_smb_fname));
3217 result = linkat(fsp_get_pathref_fd(srcfsp),
3218 old_smb_fname->base_name,
3219 fsp_get_pathref_fd(dstfsp),
3220 new_smb_fname->base_name,
3221 flags);
3223 END_PROFILE(syscall_linkat);
3224 return result;
3227 static int vfswrap_mknodat(vfs_handle_struct *handle,
3228 files_struct *dirfsp,
3229 const struct smb_filename *smb_fname,
3230 mode_t mode,
3231 SMB_DEV_T dev)
3233 int result;
3235 START_PROFILE(syscall_mknodat);
3237 SMB_ASSERT(!is_named_stream(smb_fname));
3239 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3240 smb_fname->base_name,
3241 mode,
3242 dev);
3244 END_PROFILE(syscall_mknodat);
3245 return result;
3248 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3249 TALLOC_CTX *ctx,
3250 const struct smb_filename *smb_fname)
3252 char *result;
3253 struct smb_filename *result_fname = NULL;
3255 START_PROFILE(syscall_realpath);
3256 result = sys_realpath(smb_fname->base_name);
3257 END_PROFILE(syscall_realpath);
3258 if (result) {
3259 result_fname = synthetic_smb_fname(ctx,
3260 result,
3261 NULL,
3262 NULL,
3265 SAFE_FREE(result);
3267 return result_fname;
3270 static int vfswrap_fchflags(vfs_handle_struct *handle,
3271 struct files_struct *fsp,
3272 unsigned int flags)
3274 #ifdef HAVE_FCHFLAGS
3275 int fd = fsp_get_pathref_fd(fsp);
3277 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3279 if (!fsp->fsp_flags.is_pathref) {
3280 return fchflags(fd, flags);
3283 if (fsp->fsp_flags.have_proc_fds) {
3284 struct sys_proc_fd_path_buf buf;
3286 return chflags(sys_proc_fd_path(fd, &buf), flags);
3290 * This is no longer a handle based call.
3292 return chflags(fsp->fsp_name->base_name, flags);
3293 #else
3294 errno = ENOSYS;
3295 return -1;
3296 #endif
3299 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3300 const SMB_STRUCT_STAT *sbuf)
3302 struct file_id key;
3304 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3305 * blob */
3306 ZERO_STRUCT(key);
3308 key.devid = sbuf->st_ex_dev;
3309 key.inode = sbuf->st_ex_ino;
3310 /* key.extid is unused by default. */
3312 return key;
3315 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3316 const SMB_STRUCT_STAT *psbuf)
3318 uint64_t file_id;
3320 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3321 return (uint64_t)psbuf->st_ex_ino;
3324 /* FileIDLow */
3325 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3327 /* FileIDHigh */
3328 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3330 return file_id;
3333 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3334 struct files_struct *fsp,
3335 TALLOC_CTX *mem_ctx,
3336 unsigned int *pnum_streams,
3337 struct stream_struct **pstreams)
3339 struct stream_struct *tmp_streams = NULL;
3340 unsigned int num_streams = *pnum_streams;
3341 struct stream_struct *streams = *pstreams;
3342 NTSTATUS status;
3344 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3346 if (fsp->fsp_flags.is_directory) {
3348 * No default streams on directories
3350 goto done;
3352 status = vfs_stat_fsp(fsp);
3353 if (!NT_STATUS_IS_OK(status)) {
3354 return status;
3357 if (num_streams + 1 < 1) {
3358 /* Integer wrap. */
3359 return NT_STATUS_INVALID_PARAMETER;
3362 tmp_streams = talloc_realloc(mem_ctx,
3363 streams,
3364 struct stream_struct,
3365 num_streams + 1);
3366 if (tmp_streams == NULL) {
3367 return NT_STATUS_NO_MEMORY;
3369 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3370 if (tmp_streams[num_streams].name == NULL) {
3371 return NT_STATUS_NO_MEMORY;
3373 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3374 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3375 handle->conn,
3376 fsp,
3377 &fsp->fsp_name->st);
3378 num_streams += 1;
3380 *pnum_streams = num_streams;
3381 *pstreams = tmp_streams;
3382 done:
3383 return NT_STATUS_OK;
3386 static NTSTATUS vfswrap_get_real_filename_at(
3387 struct vfs_handle_struct *handle,
3388 struct files_struct *dirfsp,
3389 const char *name,
3390 TALLOC_CTX *mem_ctx,
3391 char **found_name)
3394 * Don't fall back to get_real_filename so callers can differentiate
3395 * between a full directory scan and an actual case-insensitive stat.
3397 return NT_STATUS_NOT_SUPPORTED;
3400 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3401 const struct files_struct *dirfsp,
3402 const struct smb_filename *smb_fname)
3404 return handle->conn->connectpath;
3407 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3408 struct byte_range_lock *br_lck,
3409 struct lock_struct *plock)
3411 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3413 /* Note: blr is not used in the default implementation. */
3414 return brl_lock_windows_default(br_lck, plock);
3417 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3418 struct byte_range_lock *br_lck,
3419 const struct lock_struct *plock)
3421 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3423 return brl_unlock_windows_default(br_lck, plock);
3426 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3427 files_struct *fsp,
3428 struct lock_struct *plock)
3430 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3431 plock->lock_type == WRITE_LOCK);
3433 return strict_lock_check_default(fsp, plock);
3436 /* NT ACL operations. */
3438 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3439 files_struct *fsp,
3440 uint32_t security_info,
3441 TALLOC_CTX *mem_ctx,
3442 struct security_descriptor **ppdesc)
3444 NTSTATUS result;
3446 START_PROFILE(fget_nt_acl);
3448 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3450 result = posix_fget_nt_acl(fsp, security_info,
3451 mem_ctx, ppdesc);
3452 END_PROFILE(fget_nt_acl);
3453 return result;
3456 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3458 NTSTATUS result;
3460 START_PROFILE(fset_nt_acl);
3462 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3464 result = set_nt_acl(fsp, security_info_sent, psd);
3465 END_PROFILE(fset_nt_acl);
3466 return result;
3469 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3470 struct smb_filename *file,
3471 struct security_acl *sacl,
3472 uint32_t access_requested,
3473 uint32_t access_denied)
3475 return NT_STATUS_OK; /* Nothing to do here ... */
3478 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3479 files_struct *fsp,
3480 SMB_ACL_TYPE_T type,
3481 TALLOC_CTX *mem_ctx)
3483 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3485 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3488 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3489 files_struct *fsp,
3490 SMB_ACL_TYPE_T type,
3491 SMB_ACL_T theacl)
3493 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3495 return sys_acl_set_fd(handle, fsp, type, theacl);
3498 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3499 files_struct *fsp)
3501 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3503 return sys_acl_delete_def_fd(handle, fsp);
3506 /****************************************************************
3507 Extended attribute operations.
3508 *****************************************************************/
3510 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3511 struct files_struct *fsp,
3512 const char *name,
3513 void *value,
3514 size_t size)
3516 int fd = fsp_get_pathref_fd(fsp);
3518 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3520 if (!fsp->fsp_flags.is_pathref) {
3521 return fgetxattr(fd, name, value, size);
3524 if (fsp->fsp_flags.have_proc_fds) {
3525 struct sys_proc_fd_path_buf buf;
3527 return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3531 * This is no longer a handle based call.
3533 return getxattr(fsp->fsp_name->base_name, name, value, size);
3536 struct vfswrap_getxattrat_state {
3537 struct tevent_context *ev;
3538 struct vfs_handle_struct *handle;
3539 files_struct *dir_fsp;
3540 const struct smb_filename *smb_fname;
3543 * The following variables are talloced off "state" which is protected
3544 * by a destructor and thus are guaranteed to be safe to be used in the
3545 * job function in the worker thread.
3547 char *name;
3548 const char *xattr_name;
3549 uint8_t *xattr_value;
3550 struct security_unix_token *token;
3552 ssize_t xattr_size;
3553 struct vfs_aio_state vfs_aio_state;
3554 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3557 static int vfswrap_getxattrat_state_destructor(
3558 struct vfswrap_getxattrat_state *state)
3560 return -1;
3563 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3564 static void vfswrap_getxattrat_do_async(void *private_data);
3565 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3567 static struct tevent_req *vfswrap_getxattrat_send(
3568 TALLOC_CTX *mem_ctx,
3569 struct tevent_context *ev,
3570 struct vfs_handle_struct *handle,
3571 files_struct *dir_fsp,
3572 const struct smb_filename *smb_fname,
3573 const char *xattr_name,
3574 size_t alloc_hint)
3576 struct tevent_req *req = NULL;
3577 struct tevent_req *subreq = NULL;
3578 struct vfswrap_getxattrat_state *state = NULL;
3579 size_t max_threads = 0;
3580 bool have_per_thread_cwd = false;
3581 bool have_per_thread_creds = false;
3582 bool do_async = false;
3584 SMB_ASSERT(!is_named_stream(smb_fname));
3586 req = tevent_req_create(mem_ctx, &state,
3587 struct vfswrap_getxattrat_state);
3588 if (req == NULL) {
3589 return NULL;
3591 *state = (struct vfswrap_getxattrat_state) {
3592 .ev = ev,
3593 .handle = handle,
3594 .dir_fsp = dir_fsp,
3595 .smb_fname = smb_fname,
3598 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3599 if (max_threads >= 1) {
3601 * We need a non sync threadpool!
3603 have_per_thread_cwd = per_thread_cwd_supported();
3605 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3606 have_per_thread_creds = true;
3607 #endif
3608 if (have_per_thread_cwd && have_per_thread_creds) {
3609 do_async = true;
3612 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3613 state->profile_bytes, 0);
3615 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3616 DBG_ERR("Need a valid directory fd\n");
3617 tevent_req_error(req, EINVAL);
3618 return tevent_req_post(req, ev);
3621 if (alloc_hint > 0) {
3622 state->xattr_value = talloc_zero_array(state,
3623 uint8_t,
3624 alloc_hint);
3625 if (tevent_req_nomem(state->xattr_value, req)) {
3626 return tevent_req_post(req, ev);
3630 if (!do_async) {
3631 vfswrap_getxattrat_do_sync(req);
3632 return tevent_req_post(req, ev);
3636 * Now allocate all parameters from a memory context that won't go away
3637 * no matter what. These parameters will get used in threads and we
3638 * can't reliably cancel threads, so all buffers passed to the threads
3639 * must not be freed before all referencing threads terminate.
3642 state->name = talloc_strdup(state, smb_fname->base_name);
3643 if (tevent_req_nomem(state->name, req)) {
3644 return tevent_req_post(req, ev);
3647 state->xattr_name = talloc_strdup(state, xattr_name);
3648 if (tevent_req_nomem(state->xattr_name, req)) {
3649 return tevent_req_post(req, ev);
3653 * This is a hot codepath so at first glance one might think we should
3654 * somehow optimize away the token allocation and do a
3655 * talloc_reference() or similar black magic instead. But due to the
3656 * talloc_stackframe pool per SMB2 request this should be a simple copy
3657 * without a malloc in most cases.
3659 if (geteuid() == sec_initial_uid()) {
3660 state->token = root_unix_token(state);
3661 } else {
3662 state->token = copy_unix_token(
3663 state,
3664 dir_fsp->conn->session_info->unix_token);
3666 if (tevent_req_nomem(state->token, req)) {
3667 return tevent_req_post(req, ev);
3670 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3672 subreq = pthreadpool_tevent_job_send(
3673 state,
3675 dir_fsp->conn->sconn->pool,
3676 vfswrap_getxattrat_do_async,
3677 state);
3678 if (tevent_req_nomem(subreq, req)) {
3679 return tevent_req_post(req, ev);
3681 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3683 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3685 return req;
3688 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3690 struct vfswrap_getxattrat_state *state = tevent_req_data(
3691 req, struct vfswrap_getxattrat_state);
3693 state->xattr_size = vfswrap_fgetxattr(state->handle,
3694 state->smb_fname->fsp,
3695 state->xattr_name,
3696 state->xattr_value,
3697 talloc_array_length(state->xattr_value));
3698 if (state->xattr_size == -1) {
3699 tevent_req_error(req, errno);
3700 return;
3703 tevent_req_done(req);
3704 return;
3707 static void vfswrap_getxattrat_do_async(void *private_data)
3709 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3710 private_data, struct vfswrap_getxattrat_state);
3711 struct timespec start_time;
3712 struct timespec end_time;
3713 int ret;
3715 PROFILE_TIMESTAMP(&start_time);
3716 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3719 * Here we simulate a getxattrat()
3720 * call using fchdir();getxattr()
3723 per_thread_cwd_activate();
3725 /* Become the correct credential on this thread. */
3726 ret = set_thread_credentials(state->token->uid,
3727 state->token->gid,
3728 (size_t)state->token->ngroups,
3729 state->token->groups);
3730 if (ret != 0) {
3731 state->xattr_size = -1;
3732 state->vfs_aio_state.error = errno;
3733 goto end_profile;
3736 state->xattr_size = vfswrap_fgetxattr(state->handle,
3737 state->smb_fname->fsp,
3738 state->xattr_name,
3739 state->xattr_value,
3740 talloc_array_length(state->xattr_value));
3741 if (state->xattr_size == -1) {
3742 state->vfs_aio_state.error = errno;
3745 end_profile:
3746 PROFILE_TIMESTAMP(&end_time);
3747 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3748 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3751 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3753 struct tevent_req *req = tevent_req_callback_data(
3754 subreq, struct tevent_req);
3755 struct vfswrap_getxattrat_state *state = tevent_req_data(
3756 req, struct vfswrap_getxattrat_state);
3757 int ret;
3758 bool ok;
3761 * Make sure we run as the user again
3763 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3764 SMB_ASSERT(ok);
3766 ret = pthreadpool_tevent_job_recv(subreq);
3767 TALLOC_FREE(subreq);
3768 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3769 talloc_set_destructor(state, NULL);
3770 if (ret != 0) {
3771 if (ret != EAGAIN) {
3772 tevent_req_error(req, ret);
3773 return;
3776 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3777 * means the lower level pthreadpool failed to create a new
3778 * thread. Fallback to sync processing in that case to allow
3779 * some progress for the client.
3781 vfswrap_getxattrat_do_sync(req);
3782 return;
3785 if (state->xattr_size == -1) {
3786 tevent_req_error(req, state->vfs_aio_state.error);
3787 return;
3790 if (state->xattr_value == NULL) {
3792 * The caller only wanted the size.
3794 tevent_req_done(req);
3795 return;
3799 * shrink the buffer to the returned size.
3800 * (can't fail). It means NULL if size is 0.
3802 state->xattr_value = talloc_realloc(state,
3803 state->xattr_value,
3804 uint8_t,
3805 state->xattr_size);
3807 tevent_req_done(req);
3810 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3811 struct vfs_aio_state *aio_state,
3812 TALLOC_CTX *mem_ctx,
3813 uint8_t **xattr_value)
3815 struct vfswrap_getxattrat_state *state = tevent_req_data(
3816 req, struct vfswrap_getxattrat_state);
3817 ssize_t xattr_size;
3819 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3820 tevent_req_received(req);
3821 return -1;
3824 *aio_state = state->vfs_aio_state;
3825 xattr_size = state->xattr_size;
3826 if (xattr_value != NULL) {
3827 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3830 tevent_req_received(req);
3831 return xattr_size;
3834 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3836 int fd = fsp_get_pathref_fd(fsp);
3838 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3840 if (!fsp->fsp_flags.is_pathref) {
3841 return flistxattr(fd, list, size);
3844 if (fsp->fsp_flags.have_proc_fds) {
3845 struct sys_proc_fd_path_buf buf;
3847 return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3851 * This is no longer a handle based call.
3853 return listxattr(fsp->fsp_name->base_name, list, size);
3856 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3858 int fd = fsp_get_pathref_fd(fsp);
3860 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3862 if (!fsp->fsp_flags.is_pathref) {
3863 return fremovexattr(fd, name);
3866 if (fsp->fsp_flags.have_proc_fds) {
3867 struct sys_proc_fd_path_buf buf;
3869 return removexattr(sys_proc_fd_path(fd, &buf), name);
3873 * This is no longer a handle based call.
3875 return removexattr(fsp->fsp_name->base_name, name);
3878 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3880 int fd = fsp_get_pathref_fd(fsp);
3882 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3884 if (!fsp->fsp_flags.is_pathref) {
3885 return fsetxattr(fd, name, value, size, flags);
3888 if (fsp->fsp_flags.have_proc_fds) {
3889 struct sys_proc_fd_path_buf buf;
3891 return setxattr(sys_proc_fd_path(fd, &buf),
3892 name,
3893 value,
3894 size,
3895 flags);
3899 * This is no longer a handle based call.
3901 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3904 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3906 return false;
3909 static bool vfswrap_is_offline(struct connection_struct *conn,
3910 const struct smb_filename *fname)
3912 NTSTATUS status;
3913 char *path;
3914 bool offline = false;
3916 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3917 return false;
3920 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3921 #if defined(ENOTSUP)
3922 errno = ENOTSUP;
3923 #endif
3924 return false;
3927 status = get_full_smb_filename(talloc_tos(), fname, &path);
3928 if (!NT_STATUS_IS_OK(status)) {
3929 errno = map_errno_from_nt_status(status);
3930 return false;
3933 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3935 TALLOC_FREE(path);
3937 return offline;
3940 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3941 struct files_struct *fsp,
3942 TALLOC_CTX *mem_ctx,
3943 DATA_BLOB *cookie)
3945 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3948 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3949 struct files_struct *fsp,
3950 const DATA_BLOB old_cookie,
3951 TALLOC_CTX *mem_ctx,
3952 DATA_BLOB *new_cookie)
3954 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3955 new_cookie);
3958 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3959 struct smb_request *smb1req,
3960 struct smbXsrv_open *op,
3961 const DATA_BLOB old_cookie,
3962 TALLOC_CTX *mem_ctx,
3963 struct files_struct **fsp,
3964 DATA_BLOB *new_cookie)
3966 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3967 old_cookie, mem_ctx,
3968 fsp, new_cookie);
3971 static struct vfs_fn_pointers vfs_default_fns = {
3972 /* Disk operations */
3974 .connect_fn = vfswrap_connect,
3975 .disconnect_fn = vfswrap_disconnect,
3976 .disk_free_fn = vfswrap_disk_free,
3977 .get_quota_fn = vfswrap_get_quota,
3978 .set_quota_fn = vfswrap_set_quota,
3979 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3980 .statvfs_fn = vfswrap_statvfs,
3981 .fs_capabilities_fn = vfswrap_fs_capabilities,
3982 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3983 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3984 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3985 .snap_check_path_fn = vfswrap_snap_check_path,
3986 .snap_create_fn = vfswrap_snap_create,
3987 .snap_delete_fn = vfswrap_snap_delete,
3989 /* Directory operations */
3991 .fdopendir_fn = vfswrap_fdopendir,
3992 .readdir_fn = vfswrap_readdir,
3993 .freaddir_attr_fn = vfswrap_freaddir_attr,
3994 .rewind_dir_fn = vfswrap_rewinddir,
3995 .mkdirat_fn = vfswrap_mkdirat,
3996 .closedir_fn = vfswrap_closedir,
3998 /* File operations */
4000 .openat_fn = vfswrap_openat,
4001 .create_file_fn = vfswrap_create_file,
4002 .close_fn = vfswrap_close,
4003 .pread_fn = vfswrap_pread,
4004 .pread_send_fn = vfswrap_pread_send,
4005 .pread_recv_fn = vfswrap_pread_recv,
4006 .pwrite_fn = vfswrap_pwrite,
4007 .pwrite_send_fn = vfswrap_pwrite_send,
4008 .pwrite_recv_fn = vfswrap_pwrite_recv,
4009 .lseek_fn = vfswrap_lseek,
4010 .sendfile_fn = vfswrap_sendfile,
4011 .recvfile_fn = vfswrap_recvfile,
4012 .renameat_fn = vfswrap_renameat,
4013 .fsync_send_fn = vfswrap_fsync_send,
4014 .fsync_recv_fn = vfswrap_fsync_recv,
4015 .stat_fn = vfswrap_stat,
4016 .fstat_fn = vfswrap_fstat,
4017 .lstat_fn = vfswrap_lstat,
4018 .fstatat_fn = vfswrap_fstatat,
4019 .get_alloc_size_fn = vfswrap_get_alloc_size,
4020 .unlinkat_fn = vfswrap_unlinkat,
4021 .fchmod_fn = vfswrap_fchmod,
4022 .fchown_fn = vfswrap_fchown,
4023 .lchown_fn = vfswrap_lchown,
4024 .chdir_fn = vfswrap_chdir,
4025 .getwd_fn = vfswrap_getwd,
4026 .fntimes_fn = vfswrap_fntimes,
4027 .ftruncate_fn = vfswrap_ftruncate,
4028 .fallocate_fn = vfswrap_fallocate,
4029 .lock_fn = vfswrap_lock,
4030 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4031 .fcntl_fn = vfswrap_fcntl,
4032 .linux_setlease_fn = vfswrap_linux_setlease,
4033 .getlock_fn = vfswrap_getlock,
4034 .symlinkat_fn = vfswrap_symlinkat,
4035 .readlinkat_fn = vfswrap_readlinkat,
4036 .linkat_fn = vfswrap_linkat,
4037 .mknodat_fn = vfswrap_mknodat,
4038 .realpath_fn = vfswrap_realpath,
4039 .fchflags_fn = vfswrap_fchflags,
4040 .file_id_create_fn = vfswrap_file_id_create,
4041 .fs_file_id_fn = vfswrap_fs_file_id,
4042 .fstreaminfo_fn = vfswrap_fstreaminfo,
4043 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4044 .connectpath_fn = vfswrap_connectpath,
4045 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4046 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4047 .strict_lock_check_fn = vfswrap_strict_lock_check,
4048 .translate_name_fn = vfswrap_translate_name,
4049 .parent_pathname_fn = vfswrap_parent_pathname,
4050 .fsctl_fn = vfswrap_fsctl,
4051 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4052 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4053 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4054 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4055 .offload_read_send_fn = vfswrap_offload_read_send,
4056 .offload_read_recv_fn = vfswrap_offload_read_recv,
4057 .offload_write_send_fn = vfswrap_offload_write_send,
4058 .offload_write_recv_fn = vfswrap_offload_write_recv,
4059 .fget_compression_fn = vfswrap_fget_compression,
4060 .set_compression_fn = vfswrap_set_compression,
4062 /* NT ACL operations. */
4064 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4065 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4066 .audit_file_fn = vfswrap_audit_file,
4068 /* POSIX ACL operations. */
4070 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4071 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4072 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4073 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4075 /* EA operations. */
4076 .getxattrat_send_fn = vfswrap_getxattrat_send,
4077 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4078 .fgetxattr_fn = vfswrap_fgetxattr,
4079 .flistxattr_fn = vfswrap_flistxattr,
4080 .fremovexattr_fn = vfswrap_fremovexattr,
4081 .fsetxattr_fn = vfswrap_fsetxattr,
4083 /* aio operations */
4084 .aio_force_fn = vfswrap_aio_force,
4086 /* durable handle operations */
4087 .durable_cookie_fn = vfswrap_durable_cookie,
4088 .durable_disconnect_fn = vfswrap_durable_disconnect,
4089 .durable_reconnect_fn = vfswrap_durable_reconnect,
4092 static_decl_vfs;
4093 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4096 * Here we need to implement every call!
4098 * As this is the end of the vfs module chain.
4100 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4101 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4102 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);