CVE-2023-0614 ldb: Centralise checking for inaccessible matches
[Samba.git] / source3 / modules / vfs_default.c
blob0be634ce4c24154b34451d79b31cf6d80a055394
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 handle->conn->have_proc_fds = sys_have_proc_fds();
53 return 0; /* Return >= 0 for success */
56 static void vfswrap_disconnect(vfs_handle_struct *handle)
60 /* Disk operations */
62 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
63 const struct smb_filename *smb_fname,
64 uint64_t *bsize,
65 uint64_t *dfree,
66 uint64_t *dsize)
68 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
69 return (uint64_t)-1;
72 *bsize = 512;
73 return *dfree / 2;
76 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
77 const struct smb_filename *smb_fname,
78 enum SMB_QUOTA_TYPE qtype,
79 unid_t id,
80 SMB_DISK_QUOTA *qt)
82 #ifdef HAVE_SYS_QUOTAS
83 int result;
85 START_PROFILE(syscall_get_quota);
86 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
87 END_PROFILE(syscall_get_quota);
88 return result;
89 #else
90 errno = ENOSYS;
91 return -1;
92 #endif
95 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
97 #ifdef HAVE_SYS_QUOTAS
98 int result;
100 START_PROFILE(syscall_set_quota);
101 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
102 END_PROFILE(syscall_set_quota);
103 return result;
104 #else
105 errno = ENOSYS;
106 return -1;
107 #endif
110 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
111 struct files_struct *fsp,
112 struct shadow_copy_data *shadow_copy_data,
113 bool labels)
115 errno = ENOSYS;
116 return -1; /* Not implemented. */
119 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
120 const struct smb_filename *smb_fname,
121 vfs_statvfs_struct *statbuf)
123 return sys_statvfs(smb_fname->base_name, statbuf);
126 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
127 enum timestamp_set_resolution *p_ts_res)
129 const struct loadparm_substitution *lp_sub =
130 loadparm_s3_global_substitution();
131 connection_struct *conn = handle->conn;
132 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
133 struct smb_filename *smb_fname_cpath = NULL;
134 struct vfs_statvfs_struct statbuf;
135 int ret;
137 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
138 conn->connectpath,
139 NULL,
140 NULL,
143 if (smb_fname_cpath == NULL) {
144 return caps;
147 ZERO_STRUCT(statbuf);
148 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
149 if (ret == 0) {
150 caps = statbuf.FsCapabilities;
153 *p_ts_res = TIMESTAMP_SET_SECONDS;
155 /* Work out what timestamp resolution we can
156 * use when setting a timestamp. */
158 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
159 if (ret == -1) {
160 TALLOC_FREE(smb_fname_cpath);
161 return caps;
164 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
165 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
166 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
167 /* If any of the normal UNIX directory timestamps
168 * have a non-zero tv_nsec component assume
169 * we might be able to set sub-second timestamps.
170 * See what filetime set primitives we have.
172 #if defined(HAVE_UTIMENSAT)
173 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
174 #elif defined(HAVE_UTIMES)
175 /* utimes allows msec timestamps to be set. */
176 *p_ts_res = TIMESTAMP_SET_MSEC;
177 #elif defined(HAVE_UTIME)
178 /* utime only allows sec timestamps to be set. */
179 *p_ts_res = TIMESTAMP_SET_SECONDS;
180 #endif
182 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
183 "resolution of %s "
184 "available on share %s, directory %s\n",
185 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
186 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
187 conn->connectpath ));
189 TALLOC_FREE(smb_fname_cpath);
190 return caps;
193 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
194 struct dfs_GetDFSReferral *r)
196 struct junction_map *junction = NULL;
197 int consumedcnt = 0;
198 bool self_referral = false;
199 char *pathnamep = NULL;
200 char *local_dfs_path = NULL;
201 NTSTATUS status;
202 size_t i;
203 uint16_t max_referral_level = r->in.req.max_referral_level;
205 if (DEBUGLVL(10)) {
206 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
209 /* get the junction entry */
210 if (r->in.req.servername == NULL) {
211 return NT_STATUS_NOT_FOUND;
215 * Trim pathname sent by client so it begins with only one backslash.
216 * Two backslashes confuse some dfs clients
219 local_dfs_path = talloc_strdup(r, r->in.req.servername);
220 if (local_dfs_path == NULL) {
221 return NT_STATUS_NO_MEMORY;
223 pathnamep = local_dfs_path;
224 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
225 IS_DIRECTORY_SEP(pathnamep[1])) {
226 pathnamep++;
229 junction = talloc_zero(r, struct junction_map);
230 if (junction == NULL) {
231 return NT_STATUS_NO_MEMORY;
234 /* The following call can change cwd. */
235 status = get_referred_path(r,
236 handle->conn->session_info,
237 pathnamep,
238 handle->conn->sconn->remote_address,
239 handle->conn->sconn->local_address,
240 !handle->conn->sconn->using_smb2,
241 junction, &consumedcnt, &self_referral);
242 if (!NT_STATUS_IS_OK(status)) {
243 struct smb_filename connectpath_fname = {
244 .base_name = handle->conn->connectpath
246 vfs_ChDir(handle->conn, &connectpath_fname);
247 return status;
250 struct smb_filename connectpath_fname = {
251 .base_name = handle->conn->connectpath
253 vfs_ChDir(handle->conn, &connectpath_fname);
256 if (!self_referral) {
257 pathnamep[consumedcnt] = '\0';
259 if (DEBUGLVL(3)) {
260 dbgtext("Path %s to alternate path(s):",
261 pathnamep);
262 for (i=0; i < junction->referral_count; i++) {
263 dbgtext(" %s",
264 junction->referral_list[i].alternate_path);
266 dbgtext(".\n");
270 if (r->in.req.max_referral_level <= 2) {
271 max_referral_level = 2;
273 if (r->in.req.max_referral_level >= 3) {
274 max_referral_level = 3;
277 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
278 if (r->out.resp == NULL) {
279 return NT_STATUS_NO_MEMORY;
282 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
283 r->out.resp->nb_referrals = junction->referral_count;
285 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
286 if (self_referral) {
287 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
290 r->out.resp->referral_entries = talloc_zero_array(r,
291 struct dfs_referral_type,
292 r->out.resp->nb_referrals);
293 if (r->out.resp->referral_entries == NULL) {
294 return NT_STATUS_NO_MEMORY;
297 switch (max_referral_level) {
298 case 2:
299 for(i=0; i < junction->referral_count; i++) {
300 struct referral *ref = &junction->referral_list[i];
301 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
302 struct dfs_referral_type *t =
303 &r->out.resp->referral_entries[i];
304 struct dfs_referral_v2 *v2 = &t->referral.v2;
306 t->version = 2;
307 v2->size = VERSION2_REFERRAL_SIZE;
308 if (self_referral) {
309 v2->server_type = DFS_SERVER_ROOT;
310 } else {
311 v2->server_type = DFS_SERVER_NON_ROOT;
313 v2->entry_flags = 0;
314 v2->proximity = ref->proximity;
315 v2->ttl = ref->ttl;
316 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
317 if (v2->DFS_path == NULL) {
318 return NT_STATUS_NO_MEMORY;
320 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
321 if (v2->DFS_alt_path == NULL) {
322 return NT_STATUS_NO_MEMORY;
324 v2->netw_address = talloc_strdup(mem_ctx,
325 ref->alternate_path);
326 if (v2->netw_address == NULL) {
327 return NT_STATUS_NO_MEMORY;
331 break;
332 case 3:
333 for(i=0; i < junction->referral_count; i++) {
334 struct referral *ref = &junction->referral_list[i];
335 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
336 struct dfs_referral_type *t =
337 &r->out.resp->referral_entries[i];
338 struct dfs_referral_v3 *v3 = &t->referral.v3;
339 struct dfs_normal_referral *r1 = &v3->referrals.r1;
341 t->version = 3;
342 v3->size = VERSION3_REFERRAL_SIZE;
343 if (self_referral) {
344 v3->server_type = DFS_SERVER_ROOT;
345 } else {
346 v3->server_type = DFS_SERVER_NON_ROOT;
348 v3->entry_flags = 0;
349 v3->ttl = ref->ttl;
350 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
351 if (r1->DFS_path == NULL) {
352 return NT_STATUS_NO_MEMORY;
354 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
355 if (r1->DFS_alt_path == NULL) {
356 return NT_STATUS_NO_MEMORY;
358 r1->netw_address = talloc_strdup(mem_ctx,
359 ref->alternate_path);
360 if (r1->netw_address == NULL) {
361 return NT_STATUS_NO_MEMORY;
364 break;
365 default:
366 DEBUG(0,("Invalid dfs referral version: %d\n",
367 max_referral_level));
368 return NT_STATUS_INVALID_LEVEL;
371 if (DEBUGLVL(10)) {
372 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
375 return NT_STATUS_OK;
378 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
379 struct files_struct *dirfsp,
380 const struct smb_filename *smb_fname,
381 const struct referral *reflist,
382 size_t referral_count)
384 TALLOC_CTX *frame = talloc_stackframe();
385 NTSTATUS status = NT_STATUS_NO_MEMORY;
386 int ret;
387 char *msdfs_link = NULL;
389 /* Form the msdfs_link contents */
390 msdfs_link = msdfs_link_string(frame,
391 reflist,
392 referral_count);
393 if (msdfs_link == NULL) {
394 goto out;
397 ret = symlinkat(msdfs_link,
398 fsp_get_pathref_fd(dirfsp),
399 smb_fname->base_name);
400 if (ret == 0) {
401 status = NT_STATUS_OK;
402 } else {
403 status = map_nt_error_from_unix(errno);
406 out:
408 TALLOC_FREE(frame);
409 return status;
413 * Read and return the contents of a DFS redirect given a
414 * pathname. A caller can pass in NULL for ppreflist and
415 * preferral_count but still determine if this was a
416 * DFS redirect point by getting NT_STATUS_OK back
417 * without incurring the overhead of reading and parsing
418 * the referral contents.
421 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
422 TALLOC_CTX *mem_ctx,
423 struct files_struct *dirfsp,
424 struct smb_filename *smb_fname,
425 struct referral **ppreflist,
426 size_t *preferral_count)
428 NTSTATUS status = NT_STATUS_NO_MEMORY;
429 size_t bufsize;
430 char *link_target = NULL;
431 int referral_len;
432 bool ok;
433 #if defined(HAVE_BROKEN_READLINK)
434 char link_target_buf[PATH_MAX];
435 #else
436 char link_target_buf[7];
437 #endif
438 int ret;
440 if (is_named_stream(smb_fname)) {
441 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
442 goto err;
445 if (ppreflist == NULL && preferral_count == NULL) {
447 * We're only checking if this is a DFS
448 * redirect. We don't need to return data.
450 bufsize = sizeof(link_target_buf);
451 link_target = link_target_buf;
452 } else {
453 bufsize = PATH_MAX;
454 link_target = talloc_array(mem_ctx, char, bufsize);
455 if (!link_target) {
456 goto err;
460 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
461 smb_fname->base_name,
462 link_target,
463 bufsize - 1);
464 if (referral_len == -1) {
465 if (errno == EINVAL) {
467 * If the path isn't a link, readlinkat
468 * returns EINVAL. Allow the caller to
469 * detect this.
471 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
472 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
473 } else {
474 status = map_nt_error_from_unix(errno);
475 if (errno == ENOENT) {
476 DBG_NOTICE("Error reading "
477 "msdfs link %s: %s\n",
478 smb_fname->base_name,
479 strerror(errno));
480 } else {
481 DBG_ERR("Error reading "
482 "msdfs link %s: %s\n",
483 smb_fname->base_name,
484 strerror(errno));
487 goto err;
489 link_target[referral_len] = '\0';
491 DBG_INFO("%s -> %s\n",
492 smb_fname->base_name,
493 link_target);
495 if (!strnequal(link_target, "msdfs:", 6)) {
496 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
497 goto err;
500 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
501 smb_fname->base_name,
502 &smb_fname->st,
503 AT_SYMLINK_NOFOLLOW,
504 lp_fake_directory_create_times(SNUM(handle->conn)));
505 if (ret < 0) {
506 status = map_nt_error_from_unix(errno);
507 goto err;
510 if (ppreflist == NULL && preferral_count == NULL) {
511 /* Early return for checking if this is a DFS link. */
512 return NT_STATUS_OK;
515 ok = parse_msdfs_symlink(mem_ctx,
516 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
517 link_target,
518 ppreflist,
519 preferral_count);
521 if (ok) {
522 status = NT_STATUS_OK;
523 } else {
524 status = NT_STATUS_NO_MEMORY;
527 err:
529 if (link_target != link_target_buf) {
530 TALLOC_FREE(link_target);
532 return status;
535 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
536 TALLOC_CTX *mem_ctx,
537 const char *service_path,
538 char **base_volume)
540 return NT_STATUS_NOT_SUPPORTED;
543 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
544 TALLOC_CTX *mem_ctx,
545 const char *base_volume,
546 time_t *tstamp,
547 bool rw,
548 char **base_path,
549 char **snap_path)
551 return NT_STATUS_NOT_SUPPORTED;
554 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
555 TALLOC_CTX *mem_ctx,
556 char *base_path,
557 char *snap_path)
559 return NT_STATUS_NOT_SUPPORTED;
562 /* Directory operations */
564 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
565 files_struct *fsp,
566 const char *mask,
567 uint32_t attr)
569 DIR *result;
571 START_PROFILE(syscall_fdopendir);
572 result = sys_fdopendir(fsp_get_io_fd(fsp));
573 END_PROFILE(syscall_fdopendir);
574 return result;
578 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
579 struct files_struct *dirfsp,
580 DIR *dirp,
581 SMB_STRUCT_STAT *sbuf)
583 struct dirent *result;
584 bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
585 int flags = AT_SYMLINK_NOFOLLOW;
586 SMB_STRUCT_STAT st;
587 int ret;
589 START_PROFILE(syscall_readdir);
591 result = readdir(dirp);
592 END_PROFILE(syscall_readdir);
594 if (sbuf == NULL) {
595 return result;
597 if (result == NULL) {
598 return NULL;
602 * Default Posix readdir() does not give us stat info.
603 * Set to invalid to indicate we didn't return this info.
605 SET_STAT_INVALID(*sbuf);
607 ret = sys_fstatat(dirfd(dirp),
608 result->d_name,
609 &st,
610 flags,
611 fake_ctime);
612 if (ret != 0) {
613 return result;
617 * As this is an optimization, ignore it if we stat'ed a
618 * symlink for non-POSIX context. Make the caller do it again
619 * as we don't know if they wanted the link info, or its
620 * target info.
622 if (S_ISLNK(st.st_ex_mode) &&
623 !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
625 return result;
627 *sbuf = st;
629 return result;
632 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
633 struct files_struct *fsp,
634 TALLOC_CTX *mem_ctx,
635 struct readdir_attr_data **attr_data)
637 return NT_STATUS_NOT_SUPPORTED;
640 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
642 START_PROFILE(syscall_seekdir);
643 seekdir(dirp, offset);
644 END_PROFILE(syscall_seekdir);
647 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
649 long result;
650 START_PROFILE(syscall_telldir);
651 result = telldir(dirp);
652 END_PROFILE(syscall_telldir);
653 return result;
656 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
658 START_PROFILE(syscall_rewinddir);
659 rewinddir(dirp);
660 END_PROFILE(syscall_rewinddir);
663 static int vfswrap_mkdirat(vfs_handle_struct *handle,
664 struct files_struct *dirfsp,
665 const struct smb_filename *smb_fname,
666 mode_t mode)
668 int result;
670 START_PROFILE(syscall_mkdirat);
672 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
674 END_PROFILE(syscall_mkdirat);
675 return result;
678 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
680 int result;
682 START_PROFILE(syscall_closedir);
683 result = closedir(dirp);
684 END_PROFILE(syscall_closedir);
685 return result;
688 /* File operations */
690 static int vfswrap_openat(vfs_handle_struct *handle,
691 const struct files_struct *dirfsp,
692 const struct smb_filename *smb_fname,
693 files_struct *fsp,
694 int flags,
695 mode_t mode)
697 bool have_opath = false;
698 bool became_root = false;
699 int result;
701 START_PROFILE(syscall_openat);
703 SMB_ASSERT(!is_named_stream(smb_fname));
705 #ifdef O_PATH
706 have_opath = true;
707 if (fsp->fsp_flags.is_pathref) {
708 flags |= O_PATH;
710 #endif
712 if (fsp->fsp_flags.is_pathref && !have_opath) {
713 become_root();
714 became_root = true;
717 result = openat(fsp_get_pathref_fd(dirfsp),
718 smb_fname->base_name,
719 flags,
720 mode);
722 if (became_root) {
723 unbecome_root();
726 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
728 END_PROFILE(syscall_openat);
729 return result;
731 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
732 struct smb_request *req,
733 struct smb_filename *smb_fname,
734 uint32_t access_mask,
735 uint32_t share_access,
736 uint32_t create_disposition,
737 uint32_t create_options,
738 uint32_t file_attributes,
739 uint32_t oplock_request,
740 const struct smb2_lease *lease,
741 uint64_t allocation_size,
742 uint32_t private_flags,
743 struct security_descriptor *sd,
744 struct ea_list *ea_list,
745 files_struct **result,
746 int *pinfo,
747 const struct smb2_create_blobs *in_context_blobs,
748 struct smb2_create_blobs *out_context_blobs)
750 return create_file_default(handle->conn, req, smb_fname,
751 access_mask, share_access,
752 create_disposition, create_options,
753 file_attributes, oplock_request, lease,
754 allocation_size, private_flags,
755 sd, ea_list, result,
756 pinfo, in_context_blobs, out_context_blobs);
759 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
761 int result;
763 START_PROFILE(syscall_close);
764 result = fd_close_posix(fsp);
765 END_PROFILE(syscall_close);
766 return result;
769 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
770 size_t n, off_t offset)
772 ssize_t result;
774 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
775 START_PROFILE_BYTES(syscall_pread, n);
776 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
777 END_PROFILE_BYTES(syscall_pread);
779 if (result == -1 && errno == ESPIPE) {
780 /* Maintain the fiction that pipes can be seeked (sought?) on. */
781 result = sys_read(fsp_get_io_fd(fsp), data, n);
782 fh_set_pos(fsp->fh, 0);
785 #else /* HAVE_PREAD */
786 errno = ENOSYS;
787 result = -1;
788 #endif /* HAVE_PREAD */
790 return result;
793 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
794 size_t n, off_t offset)
796 ssize_t result;
798 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
799 START_PROFILE_BYTES(syscall_pwrite, n);
800 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
801 END_PROFILE_BYTES(syscall_pwrite);
803 if (result == -1 && errno == ESPIPE) {
804 /* Maintain the fiction that pipes can be sought on. */
805 result = sys_write(fsp_get_io_fd(fsp), data, n);
808 #else /* HAVE_PWRITE */
809 errno = ENOSYS;
810 result = -1;
811 #endif /* HAVE_PWRITE */
813 return result;
816 struct vfswrap_pread_state {
817 ssize_t ret;
818 int fd;
819 void *buf;
820 size_t count;
821 off_t offset;
823 struct vfs_aio_state vfs_aio_state;
824 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
827 static void vfs_pread_do(void *private_data);
828 static void vfs_pread_done(struct tevent_req *subreq);
829 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
831 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
832 TALLOC_CTX *mem_ctx,
833 struct tevent_context *ev,
834 struct files_struct *fsp,
835 void *data,
836 size_t n, off_t offset)
838 struct tevent_req *req, *subreq;
839 struct vfswrap_pread_state *state;
841 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
842 if (req == NULL) {
843 return NULL;
846 state->ret = -1;
847 state->fd = fsp_get_io_fd(fsp);
848 state->buf = data;
849 state->count = n;
850 state->offset = offset;
852 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
853 state->profile_bytes, n);
854 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
856 subreq = pthreadpool_tevent_job_send(
857 state, ev, handle->conn->sconn->pool,
858 vfs_pread_do, state);
859 if (tevent_req_nomem(subreq, req)) {
860 return tevent_req_post(req, ev);
862 tevent_req_set_callback(subreq, vfs_pread_done, req);
864 talloc_set_destructor(state, vfs_pread_state_destructor);
866 return req;
869 static void vfs_pread_do(void *private_data)
871 struct vfswrap_pread_state *state = talloc_get_type_abort(
872 private_data, struct vfswrap_pread_state);
873 struct timespec start_time;
874 struct timespec end_time;
876 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
878 PROFILE_TIMESTAMP(&start_time);
880 state->ret = sys_pread_full(state->fd,
881 state->buf,
882 state->count,
883 state->offset);
885 if (state->ret == -1) {
886 state->vfs_aio_state.error = errno;
889 PROFILE_TIMESTAMP(&end_time);
891 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
893 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
896 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
898 return -1;
901 static void vfs_pread_done(struct tevent_req *subreq)
903 struct tevent_req *req = tevent_req_callback_data(
904 subreq, struct tevent_req);
905 struct vfswrap_pread_state *state = tevent_req_data(
906 req, struct vfswrap_pread_state);
907 int ret;
909 ret = pthreadpool_tevent_job_recv(subreq);
910 TALLOC_FREE(subreq);
911 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
912 talloc_set_destructor(state, NULL);
913 if (ret != 0) {
914 if (ret != EAGAIN) {
915 tevent_req_error(req, ret);
916 return;
919 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
920 * means the lower level pthreadpool failed to create a new
921 * thread. Fallback to sync processing in that case to allow
922 * some progress for the client.
924 vfs_pread_do(state);
927 tevent_req_done(req);
930 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
931 struct vfs_aio_state *vfs_aio_state)
933 struct vfswrap_pread_state *state = tevent_req_data(
934 req, struct vfswrap_pread_state);
936 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
937 return -1;
940 *vfs_aio_state = state->vfs_aio_state;
941 return state->ret;
944 struct vfswrap_pwrite_state {
945 ssize_t ret;
946 int fd;
947 const void *buf;
948 size_t count;
949 off_t offset;
951 struct vfs_aio_state vfs_aio_state;
952 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
955 static void vfs_pwrite_do(void *private_data);
956 static void vfs_pwrite_done(struct tevent_req *subreq);
957 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
959 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
960 TALLOC_CTX *mem_ctx,
961 struct tevent_context *ev,
962 struct files_struct *fsp,
963 const void *data,
964 size_t n, off_t offset)
966 struct tevent_req *req, *subreq;
967 struct vfswrap_pwrite_state *state;
969 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
970 if (req == NULL) {
971 return NULL;
974 state->ret = -1;
975 state->fd = fsp_get_io_fd(fsp);
976 state->buf = data;
977 state->count = n;
978 state->offset = offset;
980 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
981 state->profile_bytes, n);
982 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
984 subreq = pthreadpool_tevent_job_send(
985 state, ev, handle->conn->sconn->pool,
986 vfs_pwrite_do, state);
987 if (tevent_req_nomem(subreq, req)) {
988 return tevent_req_post(req, ev);
990 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
992 talloc_set_destructor(state, vfs_pwrite_state_destructor);
994 return req;
997 static void vfs_pwrite_do(void *private_data)
999 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1000 private_data, struct vfswrap_pwrite_state);
1001 struct timespec start_time;
1002 struct timespec end_time;
1004 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1006 PROFILE_TIMESTAMP(&start_time);
1008 state->ret = sys_pwrite_full(state->fd,
1009 state->buf,
1010 state->count,
1011 state->offset);
1013 if (state->ret == -1) {
1014 state->vfs_aio_state.error = errno;
1017 PROFILE_TIMESTAMP(&end_time);
1019 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1021 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1024 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1026 return -1;
1029 static void vfs_pwrite_done(struct tevent_req *subreq)
1031 struct tevent_req *req = tevent_req_callback_data(
1032 subreq, struct tevent_req);
1033 struct vfswrap_pwrite_state *state = tevent_req_data(
1034 req, struct vfswrap_pwrite_state);
1035 int ret;
1037 ret = pthreadpool_tevent_job_recv(subreq);
1038 TALLOC_FREE(subreq);
1039 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1040 talloc_set_destructor(state, NULL);
1041 if (ret != 0) {
1042 if (ret != EAGAIN) {
1043 tevent_req_error(req, ret);
1044 return;
1047 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1048 * means the lower level pthreadpool failed to create a new
1049 * thread. Fallback to sync processing in that case to allow
1050 * some progress for the client.
1052 vfs_pwrite_do(state);
1055 tevent_req_done(req);
1058 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1059 struct vfs_aio_state *vfs_aio_state)
1061 struct vfswrap_pwrite_state *state = tevent_req_data(
1062 req, struct vfswrap_pwrite_state);
1064 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1065 return -1;
1068 *vfs_aio_state = state->vfs_aio_state;
1069 return state->ret;
1072 struct vfswrap_fsync_state {
1073 ssize_t ret;
1074 int fd;
1076 struct vfs_aio_state vfs_aio_state;
1077 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1080 static void vfs_fsync_do(void *private_data);
1081 static void vfs_fsync_done(struct tevent_req *subreq);
1082 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1084 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1085 TALLOC_CTX *mem_ctx,
1086 struct tevent_context *ev,
1087 struct files_struct *fsp)
1089 struct tevent_req *req, *subreq;
1090 struct vfswrap_fsync_state *state;
1092 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1093 if (req == NULL) {
1094 return NULL;
1097 state->ret = -1;
1098 state->fd = fsp_get_io_fd(fsp);
1100 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1101 state->profile_bytes, 0);
1102 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1104 subreq = pthreadpool_tevent_job_send(
1105 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1106 if (tevent_req_nomem(subreq, req)) {
1107 return tevent_req_post(req, ev);
1109 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1111 talloc_set_destructor(state, vfs_fsync_state_destructor);
1113 return req;
1116 static void vfs_fsync_do(void *private_data)
1118 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1119 private_data, struct vfswrap_fsync_state);
1120 struct timespec start_time;
1121 struct timespec end_time;
1123 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1125 PROFILE_TIMESTAMP(&start_time);
1127 do {
1128 state->ret = fsync(state->fd);
1129 } while ((state->ret == -1) && (errno == EINTR));
1131 if (state->ret == -1) {
1132 state->vfs_aio_state.error = errno;
1135 PROFILE_TIMESTAMP(&end_time);
1137 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1139 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1142 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1144 return -1;
1147 static void vfs_fsync_done(struct tevent_req *subreq)
1149 struct tevent_req *req = tevent_req_callback_data(
1150 subreq, struct tevent_req);
1151 struct vfswrap_fsync_state *state = tevent_req_data(
1152 req, struct vfswrap_fsync_state);
1153 int ret;
1155 ret = pthreadpool_tevent_job_recv(subreq);
1156 TALLOC_FREE(subreq);
1157 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1158 talloc_set_destructor(state, NULL);
1159 if (ret != 0) {
1160 if (ret != EAGAIN) {
1161 tevent_req_error(req, ret);
1162 return;
1165 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1166 * means the lower level pthreadpool failed to create a new
1167 * thread. Fallback to sync processing in that case to allow
1168 * some progress for the client.
1170 vfs_fsync_do(state);
1173 tevent_req_done(req);
1176 static int vfswrap_fsync_recv(struct tevent_req *req,
1177 struct vfs_aio_state *vfs_aio_state)
1179 struct vfswrap_fsync_state *state = tevent_req_data(
1180 req, struct vfswrap_fsync_state);
1182 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1183 return -1;
1186 *vfs_aio_state = state->vfs_aio_state;
1187 return state->ret;
1190 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1192 off_t result = 0;
1194 START_PROFILE(syscall_lseek);
1196 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1198 * We want to maintain the fiction that we can seek
1199 * on a fifo for file system purposes. This allows
1200 * people to set up UNIX fifo's that feed data to Windows
1201 * applications. JRA.
1204 if((result == -1) && (errno == ESPIPE)) {
1205 result = 0;
1206 errno = 0;
1209 END_PROFILE(syscall_lseek);
1210 return result;
1213 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1214 off_t offset, size_t n)
1216 ssize_t result;
1218 START_PROFILE_BYTES(syscall_sendfile, n);
1219 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1220 END_PROFILE_BYTES(syscall_sendfile);
1221 return result;
1224 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1225 int fromfd,
1226 files_struct *tofsp,
1227 off_t offset,
1228 size_t n)
1230 ssize_t result;
1232 START_PROFILE_BYTES(syscall_recvfile, n);
1233 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1234 END_PROFILE_BYTES(syscall_recvfile);
1235 return result;
1238 static int vfswrap_renameat(vfs_handle_struct *handle,
1239 files_struct *srcfsp,
1240 const struct smb_filename *smb_fname_src,
1241 files_struct *dstfsp,
1242 const struct smb_filename *smb_fname_dst)
1244 int result = -1;
1246 START_PROFILE(syscall_renameat);
1248 SMB_ASSERT(!is_named_stream(smb_fname_src));
1249 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1251 result = renameat(fsp_get_pathref_fd(srcfsp),
1252 smb_fname_src->base_name,
1253 fsp_get_pathref_fd(dstfsp),
1254 smb_fname_dst->base_name);
1256 END_PROFILE(syscall_renameat);
1257 return result;
1260 static int vfswrap_stat(vfs_handle_struct *handle,
1261 struct smb_filename *smb_fname)
1263 int result = -1;
1265 START_PROFILE(syscall_stat);
1267 SMB_ASSERT(!is_named_stream(smb_fname));
1269 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1270 lp_fake_directory_create_times(SNUM(handle->conn)));
1272 END_PROFILE(syscall_stat);
1273 return result;
1276 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1278 int result;
1280 START_PROFILE(syscall_fstat);
1281 result = sys_fstat(fsp_get_pathref_fd(fsp),
1282 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1283 END_PROFILE(syscall_fstat);
1284 return result;
1287 static int vfswrap_lstat(vfs_handle_struct *handle,
1288 struct smb_filename *smb_fname)
1290 int result = -1;
1292 START_PROFILE(syscall_lstat);
1294 SMB_ASSERT(!is_named_stream(smb_fname));
1296 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1297 lp_fake_directory_create_times(SNUM(handle->conn)));
1299 END_PROFILE(syscall_lstat);
1300 return result;
1303 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1304 const char *name,
1305 enum vfs_translate_direction direction,
1306 TALLOC_CTX *mem_ctx,
1307 char **mapped_name)
1309 return NT_STATUS_NONE_MAPPED;
1313 * Return allocated parent directory and basename of path
1315 * Note: if requesting name, it is returned as talloc child of the
1316 * parent. Freeing the parent is thus sufficient to free both.
1318 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1319 TALLOC_CTX *mem_ctx,
1320 const struct smb_filename *smb_fname_in,
1321 struct smb_filename **parent_dir_out,
1322 struct smb_filename **atname_out)
1324 TALLOC_CTX *frame = talloc_stackframe();
1325 struct smb_filename *parent = NULL;
1326 struct smb_filename *name = NULL;
1327 char *p = NULL;
1329 parent = cp_smb_filename_nostream(frame, smb_fname_in);
1330 if (parent == NULL) {
1331 TALLOC_FREE(frame);
1332 return NT_STATUS_NO_MEMORY;
1334 SET_STAT_INVALID(parent->st);
1336 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1337 if (p == NULL) {
1338 TALLOC_FREE(parent->base_name);
1339 parent->base_name = talloc_strdup(parent, ".");
1340 if (parent->base_name == NULL) {
1341 TALLOC_FREE(frame);
1342 return NT_STATUS_NO_MEMORY;
1344 p = smb_fname_in->base_name;
1345 } else {
1346 *p = '\0';
1347 p++;
1350 if (atname_out == NULL) {
1351 *parent_dir_out = talloc_move(mem_ctx, &parent);
1352 TALLOC_FREE(frame);
1353 return NT_STATUS_OK;
1356 name = cp_smb_filename(frame, smb_fname_in);
1357 if (name == NULL) {
1358 TALLOC_FREE(frame);
1359 return NT_STATUS_NO_MEMORY;
1361 TALLOC_FREE(name->base_name);
1363 name->base_name = talloc_strdup(name, p);
1364 if (name->base_name == NULL) {
1365 TALLOC_FREE(frame);
1366 return NT_STATUS_NO_MEMORY;
1369 *parent_dir_out = talloc_move(mem_ctx, &parent);
1370 *atname_out = talloc_move(*parent_dir_out, &name);
1371 TALLOC_FREE(frame);
1372 return NT_STATUS_OK;
1376 * Implement the default fsctl operation.
1378 static bool vfswrap_logged_ioctl_message = false;
1380 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1381 struct files_struct *fsp,
1382 TALLOC_CTX *ctx,
1383 uint32_t function,
1384 uint16_t req_flags, /* Needed for UNICODE ... */
1385 const uint8_t *_in_data,
1386 uint32_t in_len,
1387 uint8_t **_out_data,
1388 uint32_t max_out_len,
1389 uint32_t *out_len)
1391 const char *in_data = (const char *)_in_data;
1392 char **out_data = (char **)_out_data;
1393 NTSTATUS status;
1396 * Currently all fsctls operate on the base
1397 * file if given an alternate data stream.
1398 * Revisit this if we implement fsctls later
1399 * that need access to the ADS handle.
1401 fsp = metadata_fsp(fsp);
1403 switch (function) {
1404 case FSCTL_SET_SPARSE:
1406 bool set_sparse = true;
1408 if (in_len >= 1 && in_data[0] == 0) {
1409 set_sparse = false;
1412 status = file_set_sparse(handle->conn, fsp, set_sparse);
1414 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1415 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1416 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1417 nt_errstr(status)));
1419 return status;
1422 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1424 unsigned char objid[16];
1425 char *return_data = NULL;
1427 /* This should return the object-id on this file.
1428 * I think I'll make this be the inode+dev. JRA.
1431 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1432 fsp_fnum_dbg(fsp)));
1434 *out_len = MIN(max_out_len, 64);
1436 /* Hmmm, will this cause problems if less data asked for? */
1437 return_data = talloc_array(ctx, char, 64);
1438 if (return_data == NULL) {
1439 return NT_STATUS_NO_MEMORY;
1442 /* For backwards compatibility only store the dev/inode. */
1443 push_file_id_16(return_data, &fsp->file_id);
1444 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1445 push_file_id_16(return_data+32, &fsp->file_id);
1446 memset(return_data+48, 0, 16);
1447 *out_data = return_data;
1448 return NT_STATUS_OK;
1451 case FSCTL_GET_REPARSE_POINT:
1453 status = fsctl_get_reparse_point(
1454 fsp, ctx, out_data, max_out_len, out_len);
1455 return status;
1458 case FSCTL_SET_REPARSE_POINT:
1460 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1461 return status;
1464 case FSCTL_DELETE_REPARSE_POINT:
1466 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1467 return status;
1470 case FSCTL_GET_SHADOW_COPY_DATA:
1473 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1474 * and return their volume names. If max_data_count is 16, then it is just
1475 * asking for the number of volumes and length of the combined names.
1477 * pdata is the data allocated by our caller, but that uses
1478 * total_data_count (which is 0 in our case) rather than max_data_count.
1479 * Allocate the correct amount and return the pointer to let
1480 * it be deallocated when we return.
1482 struct shadow_copy_data *shadow_data = NULL;
1483 bool labels = False;
1484 uint32_t labels_data_count = 0;
1485 uint32_t i;
1486 char *cur_pdata = NULL;
1488 if (max_out_len < 16) {
1489 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1490 max_out_len));
1491 return NT_STATUS_INVALID_PARAMETER;
1494 if (max_out_len > 16) {
1495 labels = True;
1498 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1499 if (shadow_data == NULL) {
1500 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1501 return NT_STATUS_NO_MEMORY;
1505 * Call the VFS routine to actually do the work.
1507 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1508 int log_lev = 0;
1509 if (errno == 0) {
1510 /* broken module didn't set errno on error */
1511 status = NT_STATUS_UNSUCCESSFUL;
1512 } else {
1513 status = map_nt_error_from_unix(errno);
1514 if (NT_STATUS_EQUAL(status,
1515 NT_STATUS_NOT_SUPPORTED)) {
1516 log_lev = 5;
1519 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1520 "connectpath %s, failed - %s.\n",
1521 fsp->conn->connectpath,
1522 nt_errstr(status)));
1523 TALLOC_FREE(shadow_data);
1524 return status;
1527 labels_data_count = (shadow_data->num_volumes * 2 *
1528 sizeof(SHADOW_COPY_LABEL)) + 2;
1530 if (!labels) {
1531 *out_len = 16;
1532 } else {
1533 *out_len = 12 + labels_data_count;
1536 if (max_out_len < *out_len) {
1537 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1538 max_out_len, *out_len));
1539 TALLOC_FREE(shadow_data);
1540 return NT_STATUS_BUFFER_TOO_SMALL;
1543 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1544 if (cur_pdata == NULL) {
1545 TALLOC_FREE(shadow_data);
1546 return NT_STATUS_NO_MEMORY;
1549 *out_data = cur_pdata;
1551 /* num_volumes 4 bytes */
1552 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1554 if (labels) {
1555 /* num_labels 4 bytes */
1556 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1559 /* needed_data_count 4 bytes */
1560 SIVAL(cur_pdata, 8, labels_data_count);
1562 cur_pdata += 12;
1564 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1565 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1566 if (labels && shadow_data->labels) {
1567 for (i=0; i<shadow_data->num_volumes; i++) {
1568 size_t len = 0;
1569 status = srvstr_push(cur_pdata, req_flags,
1570 cur_pdata, shadow_data->labels[i],
1571 2 * sizeof(SHADOW_COPY_LABEL),
1572 STR_UNICODE|STR_TERMINATE, &len);
1573 if (!NT_STATUS_IS_OK(status)) {
1574 TALLOC_FREE(*out_data);
1575 TALLOC_FREE(shadow_data);
1576 return status;
1578 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1579 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1583 TALLOC_FREE(shadow_data);
1585 return NT_STATUS_OK;
1588 case FSCTL_FIND_FILES_BY_SID:
1590 /* pretend this succeeded -
1592 * we have to send back a list with all files owned by this SID
1594 * but I have to check that --metze
1596 ssize_t ret;
1597 struct dom_sid sid;
1598 struct dom_sid_buf buf;
1599 uid_t uid;
1600 size_t sid_len;
1602 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1603 fsp_fnum_dbg(fsp)));
1605 if (in_len < 8) {
1606 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1607 return NT_STATUS_INVALID_PARAMETER;
1610 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1612 /* unknown 4 bytes: this is not the length of the sid :-( */
1613 /*unknown = IVAL(pdata,0);*/
1615 ret = sid_parse(_in_data + 4, sid_len, &sid);
1616 if (ret == -1) {
1617 return NT_STATUS_INVALID_PARAMETER;
1619 DEBUGADD(10, ("for SID: %s\n",
1620 dom_sid_str_buf(&sid, &buf)));
1622 if (!sid_to_uid(&sid, &uid)) {
1623 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1624 dom_sid_str_buf(&sid, &buf),
1625 (unsigned long)sid_len));
1626 uid = (-1);
1629 /* we can take a look at the find source :-)
1631 * find ./ -uid $uid -name '*' is what we need here
1634 * and send 4bytes len and then NULL terminated unicode strings
1635 * for each file
1637 * but I don't know how to deal with the paged results
1638 * (maybe we can hang the result anywhere in the fsp struct)
1640 * but I don't know how to deal with the paged results
1641 * (maybe we can hang the result anywhere in the fsp struct)
1643 * we don't send all files at once
1644 * and at the next we should *not* start from the beginning,
1645 * so we have to cache the result
1647 * --metze
1650 /* this works for now... */
1651 return NT_STATUS_OK;
1654 case FSCTL_QUERY_ALLOCATED_RANGES:
1656 /* FIXME: This is just a dummy reply, telling that all of the
1657 * file is allocated. MKS cp needs that.
1658 * Adding the real allocated ranges via FIEMAP on Linux
1659 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1660 * this FSCTL correct for sparse files.
1662 uint64_t offset, length;
1663 char *out_data_tmp = NULL;
1665 if (in_len != 16) {
1666 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1667 in_len));
1668 return NT_STATUS_INVALID_PARAMETER;
1671 if (max_out_len < 16) {
1672 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1673 max_out_len));
1674 return NT_STATUS_INVALID_PARAMETER;
1677 offset = BVAL(in_data,0);
1678 length = BVAL(in_data,8);
1680 if (offset + length < offset) {
1681 /* No 64-bit integer wrap. */
1682 return NT_STATUS_INVALID_PARAMETER;
1685 /* Shouldn't this be SMB_VFS_STAT ... ? */
1686 status = vfs_stat_fsp(fsp);
1687 if (!NT_STATUS_IS_OK(status)) {
1688 return status;
1691 *out_len = 16;
1692 out_data_tmp = talloc_array(ctx, char, *out_len);
1693 if (out_data_tmp == NULL) {
1694 DEBUG(10, ("unable to allocate memory for response\n"));
1695 return NT_STATUS_NO_MEMORY;
1698 if (offset > fsp->fsp_name->st.st_ex_size ||
1699 fsp->fsp_name->st.st_ex_size == 0 ||
1700 length == 0) {
1701 memset(out_data_tmp, 0, *out_len);
1702 } else {
1703 uint64_t end = offset + length;
1704 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1705 SBVAL(out_data_tmp, 0, 0);
1706 SBVAL(out_data_tmp, 8, end);
1709 *out_data = out_data_tmp;
1711 return NT_STATUS_OK;
1714 case FSCTL_IS_VOLUME_DIRTY:
1716 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1717 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1719 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1720 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1722 return NT_STATUS_INVALID_PARAMETER;
1725 default:
1727 * Only print once ... unfortunately there could be lots of
1728 * different FSCTLs that are called.
1730 if (!vfswrap_logged_ioctl_message) {
1731 vfswrap_logged_ioctl_message = true;
1732 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1733 __func__, function));
1737 return NT_STATUS_NOT_SUPPORTED;
1740 static bool vfswrap_is_offline(struct connection_struct *conn,
1741 const struct smb_filename *fname);
1743 struct vfswrap_get_dos_attributes_state {
1744 struct vfs_aio_state aio_state;
1745 connection_struct *conn;
1746 TALLOC_CTX *mem_ctx;
1747 struct tevent_context *ev;
1748 files_struct *dir_fsp;
1749 struct smb_filename *smb_fname;
1750 uint32_t dosmode;
1751 bool as_root;
1754 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1756 static struct tevent_req *vfswrap_get_dos_attributes_send(
1757 TALLOC_CTX *mem_ctx,
1758 struct tevent_context *ev,
1759 struct vfs_handle_struct *handle,
1760 files_struct *dir_fsp,
1761 struct smb_filename *smb_fname)
1763 struct tevent_req *req = NULL;
1764 struct tevent_req *subreq = NULL;
1765 struct vfswrap_get_dos_attributes_state *state = NULL;
1767 SMB_ASSERT(!is_named_stream(smb_fname));
1769 req = tevent_req_create(mem_ctx, &state,
1770 struct vfswrap_get_dos_attributes_state);
1771 if (req == NULL) {
1772 return NULL;
1775 *state = (struct vfswrap_get_dos_attributes_state) {
1776 .conn = dir_fsp->conn,
1777 .mem_ctx = mem_ctx,
1778 .ev = ev,
1779 .dir_fsp = dir_fsp,
1780 .smb_fname = smb_fname,
1783 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1784 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1785 "\"store dos attributes\" is disabled\n",
1786 dir_fsp->conn->connectpath);
1787 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1788 return tevent_req_post(req, ev);
1791 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1793 dir_fsp,
1794 smb_fname,
1795 SAMBA_XATTR_DOS_ATTRIB,
1796 sizeof(fstring));
1797 if (tevent_req_nomem(subreq, req)) {
1798 return tevent_req_post(req, ev);
1800 tevent_req_set_callback(subreq,
1801 vfswrap_get_dos_attributes_getxattr_done,
1802 req);
1804 return req;
1807 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1809 struct tevent_req *req =
1810 tevent_req_callback_data(subreq,
1811 struct tevent_req);
1812 struct vfswrap_get_dos_attributes_state *state =
1813 tevent_req_data(req,
1814 struct vfswrap_get_dos_attributes_state);
1815 ssize_t xattr_size;
1816 DATA_BLOB blob = {0};
1817 char *path = NULL;
1818 char *tofree = NULL;
1819 char pathbuf[PATH_MAX+1];
1820 ssize_t pathlen;
1821 struct smb_filename smb_fname;
1822 bool offline;
1823 NTSTATUS status;
1825 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1826 &state->aio_state,
1827 state,
1828 &blob.data);
1829 TALLOC_FREE(subreq);
1830 if (xattr_size == -1) {
1831 status = map_nt_error_from_unix(state->aio_state.error);
1833 if (state->as_root) {
1834 tevent_req_nterror(req, status);
1835 return;
1837 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1838 tevent_req_nterror(req, status);
1839 return;
1842 state->as_root = true;
1844 become_root();
1845 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1846 state->ev,
1847 state->dir_fsp,
1848 state->smb_fname,
1849 SAMBA_XATTR_DOS_ATTRIB,
1850 sizeof(fstring));
1851 unbecome_root();
1852 if (tevent_req_nomem(subreq, req)) {
1853 return;
1855 tevent_req_set_callback(subreq,
1856 vfswrap_get_dos_attributes_getxattr_done,
1857 req);
1858 return;
1861 blob.length = xattr_size;
1863 status = parse_dos_attribute_blob(state->smb_fname,
1864 blob,
1865 &state->dosmode);
1866 if (!NT_STATUS_IS_OK(status)) {
1867 tevent_req_nterror(req, status);
1868 return;
1871 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1872 state->smb_fname->base_name,
1873 pathbuf,
1874 sizeof(pathbuf),
1875 &path,
1876 &tofree);
1877 if (pathlen == -1) {
1878 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1879 return;
1882 smb_fname = (struct smb_filename) {
1883 .base_name = path,
1884 .st = state->smb_fname->st,
1885 .flags = state->smb_fname->flags,
1886 .twrp = state->smb_fname->twrp,
1889 offline = vfswrap_is_offline(state->conn, &smb_fname);
1890 if (offline) {
1891 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1893 TALLOC_FREE(tofree);
1895 tevent_req_done(req);
1896 return;
1899 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1900 struct vfs_aio_state *aio_state,
1901 uint32_t *dosmode)
1903 struct vfswrap_get_dos_attributes_state *state =
1904 tevent_req_data(req,
1905 struct vfswrap_get_dos_attributes_state);
1906 NTSTATUS status;
1908 if (tevent_req_is_nterror(req, &status)) {
1909 tevent_req_received(req);
1910 return status;
1913 *aio_state = state->aio_state;
1914 *dosmode = state->dosmode;
1915 tevent_req_received(req);
1916 return NT_STATUS_OK;
1919 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1920 struct files_struct *fsp,
1921 uint32_t *dosmode)
1923 bool offline;
1925 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1927 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1928 if (offline) {
1929 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1932 return fget_ea_dos_attribute(fsp, dosmode);
1935 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1936 struct files_struct *fsp,
1937 uint32_t dosmode)
1939 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1941 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1944 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1946 struct vfswrap_offload_read_state {
1947 DATA_BLOB token;
1950 static struct tevent_req *vfswrap_offload_read_send(
1951 TALLOC_CTX *mem_ctx,
1952 struct tevent_context *ev,
1953 struct vfs_handle_struct *handle,
1954 struct files_struct *fsp,
1955 uint32_t fsctl,
1956 uint32_t ttl,
1957 off_t offset,
1958 size_t to_copy)
1960 struct tevent_req *req = NULL;
1961 struct vfswrap_offload_read_state *state = NULL;
1962 NTSTATUS status;
1964 req = tevent_req_create(mem_ctx, &state,
1965 struct vfswrap_offload_read_state);
1966 if (req == NULL) {
1967 return NULL;
1970 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
1971 &vfswrap_offload_ctx);
1972 if (tevent_req_nterror(req, status)) {
1973 return tevent_req_post(req, ev);
1976 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
1977 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
1978 return tevent_req_post(req, ev);
1981 status = vfs_offload_token_create_blob(state, fsp, fsctl,
1982 &state->token);
1983 if (tevent_req_nterror(req, status)) {
1984 return tevent_req_post(req, ev);
1987 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
1988 &state->token);
1989 if (tevent_req_nterror(req, status)) {
1990 return tevent_req_post(req, ev);
1993 tevent_req_done(req);
1994 return tevent_req_post(req, ev);
1997 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
1998 struct vfs_handle_struct *handle,
1999 TALLOC_CTX *mem_ctx,
2000 uint32_t *flags,
2001 uint64_t *xferlen,
2002 DATA_BLOB *token)
2004 struct vfswrap_offload_read_state *state = tevent_req_data(
2005 req, struct vfswrap_offload_read_state);
2006 NTSTATUS status;
2008 if (tevent_req_is_nterror(req, &status)) {
2009 tevent_req_received(req);
2010 return status;
2013 *flags = 0;
2014 *xferlen = 0;
2015 token->length = state->token.length;
2016 token->data = talloc_move(mem_ctx, &state->token.data);
2018 tevent_req_received(req);
2019 return NT_STATUS_OK;
2022 struct vfswrap_offload_write_state {
2023 uint8_t *buf;
2024 bool read_lck_locked;
2025 bool write_lck_locked;
2026 DATA_BLOB *token;
2027 struct tevent_context *src_ev;
2028 struct files_struct *src_fsp;
2029 off_t src_off;
2030 struct tevent_context *dst_ev;
2031 struct files_struct *dst_fsp;
2032 off_t dst_off;
2033 off_t to_copy;
2034 off_t remaining;
2035 off_t copied;
2036 size_t next_io_size;
2039 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2040 enum tevent_req_state req_state)
2042 struct vfswrap_offload_write_state *state = tevent_req_data(
2043 req, struct vfswrap_offload_write_state);
2044 bool ok;
2046 if (state->dst_fsp == NULL) {
2047 return;
2050 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2051 SMB_ASSERT(ok);
2052 state->dst_fsp = NULL;
2055 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2056 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2058 static struct tevent_req *vfswrap_offload_write_send(
2059 struct vfs_handle_struct *handle,
2060 TALLOC_CTX *mem_ctx,
2061 struct tevent_context *ev,
2062 uint32_t fsctl,
2063 DATA_BLOB *token,
2064 off_t transfer_offset,
2065 struct files_struct *dest_fsp,
2066 off_t dest_off,
2067 off_t to_copy)
2069 struct tevent_req *req;
2070 struct vfswrap_offload_write_state *state = NULL;
2071 /* off_t is signed! */
2072 off_t max_offset = INT64_MAX - to_copy;
2073 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2074 files_struct *src_fsp = NULL;
2075 NTSTATUS status;
2076 bool ok;
2078 req = tevent_req_create(mem_ctx, &state,
2079 struct vfswrap_offload_write_state);
2080 if (req == NULL) {
2081 return NULL;
2084 *state = (struct vfswrap_offload_write_state) {
2085 .token = token,
2086 .src_off = transfer_offset,
2087 .dst_ev = ev,
2088 .dst_fsp = dest_fsp,
2089 .dst_off = dest_off,
2090 .to_copy = to_copy,
2091 .remaining = to_copy,
2094 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2096 switch (fsctl) {
2097 case FSCTL_SRV_COPYCHUNK:
2098 case FSCTL_SRV_COPYCHUNK_WRITE:
2099 break;
2101 case FSCTL_OFFLOAD_WRITE:
2102 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2103 return tevent_req_post(req, ev);
2105 case FSCTL_DUP_EXTENTS_TO_FILE:
2106 DBG_DEBUG("COW clones not supported by vfs_default\n");
2107 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2108 return tevent_req_post(req, ev);
2110 default:
2111 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2112 return tevent_req_post(req, ev);
2116 * From here on we assume a copy-chunk fsctl
2119 if (to_copy == 0) {
2120 tevent_req_done(req);
2121 return tevent_req_post(req, ev);
2124 if (state->src_off > max_offset) {
2126 * Protect integer checks below.
2128 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2129 return tevent_req_post(req, ev);
2131 if (state->src_off < 0) {
2133 * Protect integer checks below.
2135 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2136 return tevent_req_post(req, ev);
2138 if (state->dst_off > max_offset) {
2140 * Protect integer checks below.
2142 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2143 return tevent_req_post(req, ev);
2145 if (state->dst_off < 0) {
2147 * Protect integer checks below.
2149 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2150 return tevent_req_post(req, ev);
2153 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2154 token, &src_fsp);
2155 if (tevent_req_nterror(req, status)) {
2156 return tevent_req_post(req, ev);
2159 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2161 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 tevent_req_nterror(req, status);
2164 return tevent_req_post(req, ev);
2167 ok = change_to_user_and_service_by_fsp(src_fsp);
2168 if (!ok) {
2169 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2170 return tevent_req_post(req, ev);
2173 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2174 state->src_fsp = src_fsp;
2176 status = vfs_stat_fsp(src_fsp);
2177 if (tevent_req_nterror(req, status)) {
2178 return tevent_req_post(req, ev);
2181 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2183 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2184 * If the SourceOffset or SourceOffset + Length extends beyond
2185 * the end of file, the server SHOULD<240> treat this as a
2186 * STATUS_END_OF_FILE error.
2187 * ...
2188 * <240> Section 3.3.5.15.6: Windows servers will return
2189 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2191 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2192 return tevent_req_post(req, ev);
2195 status = vfswrap_offload_copy_file_range(req);
2196 if (NT_STATUS_IS_OK(status)) {
2197 tevent_req_done(req);
2198 return tevent_req_post(req, ev);
2200 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2201 tevent_req_nterror(req, status);
2202 return tevent_req_post(req, ev);
2205 state->buf = talloc_array(state, uint8_t, num);
2206 if (tevent_req_nomem(state->buf, req)) {
2207 return tevent_req_post(req, ev);
2210 status = vfswrap_offload_write_loop(req);
2211 if (!NT_STATUS_IS_OK(status)) {
2212 tevent_req_nterror(req, status);
2213 return tevent_req_post(req, ev);
2216 return req;
2219 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2221 struct vfswrap_offload_write_state *state = tevent_req_data(
2222 req, struct vfswrap_offload_write_state);
2223 struct lock_struct lck;
2224 ssize_t nwritten;
2225 NTSTATUS status;
2226 bool same_file;
2227 bool ok;
2228 static bool try_copy_file_range = true;
2230 if (!try_copy_file_range) {
2231 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2234 same_file = file_id_equal(&state->src_fsp->file_id,
2235 &state->dst_fsp->file_id);
2236 if (same_file &&
2237 sys_io_ranges_overlap(state->remaining,
2238 state->src_off,
2239 state->remaining,
2240 state->dst_off))
2242 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2245 if (is_named_stream(state->src_fsp->fsp_name) ||
2246 is_named_stream(state->dst_fsp->fsp_name))
2248 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2251 init_strict_lock_struct(state->src_fsp,
2252 state->src_fsp->op->global->open_persistent_id,
2253 state->src_off,
2254 state->remaining,
2255 READ_LOCK,
2256 lp_posix_cifsu_locktype(state->src_fsp),
2257 &lck);
2259 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2260 state->src_fsp,
2261 &lck);
2262 if (!ok) {
2263 return NT_STATUS_FILE_LOCK_CONFLICT;
2266 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2267 if (!ok) {
2268 return NT_STATUS_INTERNAL_ERROR;
2271 init_strict_lock_struct(state->dst_fsp,
2272 state->dst_fsp->op->global->open_persistent_id,
2273 state->dst_off,
2274 state->remaining,
2275 WRITE_LOCK,
2276 lp_posix_cifsu_locktype(state->dst_fsp),
2277 &lck);
2279 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2280 state->dst_fsp,
2281 &lck);
2282 if (!ok) {
2283 return NT_STATUS_FILE_LOCK_CONFLICT;
2286 while (state->remaining > 0) {
2287 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2288 &state->src_off,
2289 fsp_get_io_fd(state->dst_fsp),
2290 &state->dst_off,
2291 state->remaining,
2293 if (nwritten == -1) {
2294 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2295 "n [%jd] failed: %s\n",
2296 fsp_str_dbg(state->src_fsp),
2297 (intmax_t)state->src_off,
2298 fsp_str_dbg(state->dst_fsp),
2299 (intmax_t)state->dst_off,
2300 (intmax_t)state->remaining,
2301 strerror(errno));
2302 switch (errno) {
2303 case EOPNOTSUPP:
2304 case ENOSYS:
2305 try_copy_file_range = false;
2306 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2307 break;
2308 case EXDEV:
2309 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2310 break;
2311 default:
2312 status = map_nt_error_from_unix(errno);
2313 if (NT_STATUS_EQUAL(
2314 status,
2315 NT_STATUS_MORE_PROCESSING_REQUIRED))
2317 /* Avoid triggering the fallback */
2318 status = NT_STATUS_INTERNAL_ERROR;
2320 break;
2322 return status;
2325 if (state->remaining < nwritten) {
2326 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2327 "n [%jd] remaining [%jd]\n",
2328 fsp_str_dbg(state->src_fsp),
2329 fsp_str_dbg(state->dst_fsp),
2330 (intmax_t)nwritten,
2331 (intmax_t)state->remaining);
2332 return NT_STATUS_INTERNAL_ERROR;
2335 if (nwritten == 0) {
2336 break;
2338 state->copied += nwritten;
2339 state->remaining -= nwritten;
2343 * Tell the req cleanup function there's no need to call
2344 * change_to_user_and_service_by_fsp() on the dst handle.
2346 state->dst_fsp = NULL;
2347 return NT_STATUS_OK;
2350 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2352 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2354 struct vfswrap_offload_write_state *state = tevent_req_data(
2355 req, struct vfswrap_offload_write_state);
2356 struct tevent_req *subreq = NULL;
2357 struct lock_struct read_lck;
2358 bool ok;
2361 * This is called under the context of state->src_fsp.
2364 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2366 init_strict_lock_struct(state->src_fsp,
2367 state->src_fsp->op->global->open_persistent_id,
2368 state->src_off,
2369 state->next_io_size,
2370 READ_LOCK,
2371 lp_posix_cifsu_locktype(state->src_fsp),
2372 &read_lck);
2374 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2375 state->src_fsp,
2376 &read_lck);
2377 if (!ok) {
2378 return NT_STATUS_FILE_LOCK_CONFLICT;
2381 subreq = SMB_VFS_PREAD_SEND(state,
2382 state->src_ev,
2383 state->src_fsp,
2384 state->buf,
2385 state->next_io_size,
2386 state->src_off);
2387 if (subreq == NULL) {
2388 return NT_STATUS_NO_MEMORY;
2390 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2392 return NT_STATUS_OK;
2395 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2397 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2399 struct tevent_req *req = tevent_req_callback_data(
2400 subreq, struct tevent_req);
2401 struct vfswrap_offload_write_state *state = tevent_req_data(
2402 req, struct vfswrap_offload_write_state);
2403 struct vfs_aio_state aio_state;
2404 struct lock_struct write_lck;
2405 ssize_t nread;
2406 bool ok;
2408 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2409 TALLOC_FREE(subreq);
2410 if (nread == -1) {
2411 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2412 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2413 return;
2415 if (nread != state->next_io_size) {
2416 DBG_ERR("Short read, only %zd of %zu\n",
2417 nread, state->next_io_size);
2418 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2419 return;
2422 state->src_off += nread;
2424 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2425 if (!ok) {
2426 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2427 return;
2430 init_strict_lock_struct(state->dst_fsp,
2431 state->dst_fsp->op->global->open_persistent_id,
2432 state->dst_off,
2433 state->next_io_size,
2434 WRITE_LOCK,
2435 lp_posix_cifsu_locktype(state->dst_fsp),
2436 &write_lck);
2438 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2439 state->dst_fsp,
2440 &write_lck);
2441 if (!ok) {
2442 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2443 return;
2446 subreq = SMB_VFS_PWRITE_SEND(state,
2447 state->dst_ev,
2448 state->dst_fsp,
2449 state->buf,
2450 state->next_io_size,
2451 state->dst_off);
2452 if (subreq == NULL) {
2453 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2454 return;
2456 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2459 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2461 struct tevent_req *req = tevent_req_callback_data(
2462 subreq, struct tevent_req);
2463 struct vfswrap_offload_write_state *state = tevent_req_data(
2464 req, struct vfswrap_offload_write_state);
2465 struct vfs_aio_state aio_state;
2466 ssize_t nwritten;
2467 NTSTATUS status;
2468 bool ok;
2470 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2471 TALLOC_FREE(subreq);
2472 if (nwritten == -1) {
2473 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2474 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2475 return;
2477 if (nwritten != state->next_io_size) {
2478 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2479 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2480 return;
2483 state->dst_off += nwritten;
2485 if (state->remaining < nwritten) {
2486 /* Paranoia check */
2487 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2488 return;
2490 state->copied += nwritten;
2491 state->remaining -= nwritten;
2492 if (state->remaining == 0) {
2493 tevent_req_done(req);
2494 return;
2497 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2498 if (!ok) {
2499 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2500 return;
2503 status = vfswrap_offload_write_loop(req);
2504 if (!NT_STATUS_IS_OK(status)) {
2505 tevent_req_nterror(req, status);
2506 return;
2509 return;
2512 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2513 struct tevent_req *req,
2514 off_t *copied)
2516 struct vfswrap_offload_write_state *state = tevent_req_data(
2517 req, struct vfswrap_offload_write_state);
2518 NTSTATUS status;
2520 if (tevent_req_is_nterror(req, &status)) {
2521 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2522 *copied = 0;
2523 tevent_req_received(req);
2524 return status;
2527 *copied = state->copied;
2528 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2529 tevent_req_received(req);
2531 return NT_STATUS_OK;
2534 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2535 TALLOC_CTX *mem_ctx,
2536 struct files_struct *fsp,
2537 uint16_t *_compression_fmt)
2539 return NT_STATUS_INVALID_DEVICE_REQUEST;
2542 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2543 TALLOC_CTX *mem_ctx,
2544 struct files_struct *fsp,
2545 uint16_t compression_fmt)
2547 return NT_STATUS_INVALID_DEVICE_REQUEST;
2550 /********************************************************************
2551 Given a stat buffer return the allocated size on disk, taking into
2552 account sparse files.
2553 ********************************************************************/
2554 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2555 struct files_struct *fsp,
2556 const SMB_STRUCT_STAT *sbuf)
2558 uint64_t result;
2560 START_PROFILE(syscall_get_alloc_size);
2562 if(S_ISDIR(sbuf->st_ex_mode)) {
2563 result = 0;
2564 goto out;
2567 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2568 /* The type of st_blocksize is blkcnt_t which *MUST* be
2569 signed (according to POSIX) and can be less than 64-bits.
2570 Ensure when we're converting to 64 bits wide we don't
2571 sign extend. */
2572 #if defined(SIZEOF_BLKCNT_T_8)
2573 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2574 #elif defined(SIZEOF_BLKCNT_T_4)
2576 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2577 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2579 #else
2580 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2581 #endif
2582 if (result == 0) {
2584 * Some file systems do not allocate a block for very
2585 * small files. But for non-empty file should report a
2586 * positive size.
2589 uint64_t filesize = get_file_size_stat(sbuf);
2590 if (filesize > 0) {
2591 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2594 #else
2595 result = get_file_size_stat(sbuf);
2596 #endif
2598 if (fsp && fsp->initial_allocation_size)
2599 result = MAX(result,fsp->initial_allocation_size);
2601 result = smb_roundup(handle->conn, result);
2603 out:
2604 END_PROFILE(syscall_get_alloc_size);
2605 return result;
2608 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2609 struct files_struct *dirfsp,
2610 const struct smb_filename *smb_fname,
2611 int flags)
2613 int result = -1;
2615 START_PROFILE(syscall_unlinkat);
2617 SMB_ASSERT(!is_named_stream(smb_fname));
2619 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2620 smb_fname->base_name,
2621 flags);
2623 END_PROFILE(syscall_unlinkat);
2624 return result;
2627 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2629 int result;
2631 START_PROFILE(syscall_fchmod);
2633 if (!fsp->fsp_flags.is_pathref) {
2634 result = fchmod(fsp_get_io_fd(fsp), mode);
2635 END_PROFILE(syscall_fchmod);
2636 return result;
2639 if (fsp->fsp_flags.have_proc_fds) {
2640 int fd = fsp_get_pathref_fd(fsp);
2641 const char *p = NULL;
2642 char buf[PATH_MAX];
2644 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2645 if (p != NULL) {
2646 result = chmod(p, mode);
2647 } else {
2648 result = -1;
2650 END_PROFILE(syscall_fchmod);
2651 return result;
2655 * This is no longer a handle based call.
2657 result = chmod(fsp->fsp_name->base_name, mode);
2659 END_PROFILE(syscall_fchmod);
2660 return result;
2663 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2665 #ifdef HAVE_FCHOWN
2666 int result;
2668 START_PROFILE(syscall_fchown);
2669 if (!fsp->fsp_flags.is_pathref) {
2670 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2671 END_PROFILE(syscall_fchown);
2672 return result;
2675 if (fsp->fsp_flags.have_proc_fds) {
2676 int fd = fsp_get_pathref_fd(fsp);
2677 const char *p = NULL;
2678 char buf[PATH_MAX];
2680 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2681 if (p != NULL) {
2682 result = chown(p, uid, gid);
2683 } else {
2684 result = -1;
2686 END_PROFILE(syscall_fchown);
2687 return result;
2691 * This is no longer a handle based call.
2693 result = chown(fsp->fsp_name->base_name, uid, gid);
2694 END_PROFILE(syscall_fchown);
2695 return result;
2696 #else
2697 errno = ENOSYS;
2698 return -1;
2699 #endif
2702 static int vfswrap_lchown(vfs_handle_struct *handle,
2703 const struct smb_filename *smb_fname,
2704 uid_t uid,
2705 gid_t gid)
2707 int result;
2709 START_PROFILE(syscall_lchown);
2710 result = lchown(smb_fname->base_name, uid, gid);
2711 END_PROFILE(syscall_lchown);
2712 return result;
2715 static int vfswrap_chdir(vfs_handle_struct *handle,
2716 const struct smb_filename *smb_fname)
2718 int result;
2720 START_PROFILE(syscall_chdir);
2721 result = chdir(smb_fname->base_name);
2722 END_PROFILE(syscall_chdir);
2723 return result;
2726 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2727 TALLOC_CTX *ctx)
2729 char *result;
2730 struct smb_filename *smb_fname = NULL;
2732 START_PROFILE(syscall_getwd);
2733 result = sys_getwd();
2734 END_PROFILE(syscall_getwd);
2736 if (result == NULL) {
2737 return NULL;
2739 smb_fname = synthetic_smb_fname(ctx,
2740 result,
2741 NULL,
2742 NULL,
2746 * sys_getwd() *always* returns malloced memory.
2747 * We must free here to avoid leaks:
2748 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2750 SAFE_FREE(result);
2751 return smb_fname;
2754 /*********************************************************************
2755 nsec timestamp resolution call. Convert down to whatever the underlying
2756 system will support.
2757 **********************************************************************/
2759 static int vfswrap_fntimes(vfs_handle_struct *handle,
2760 files_struct *fsp,
2761 struct smb_file_time *ft)
2763 int result = -1;
2764 struct timespec ts[2];
2765 struct timespec *times = NULL;
2767 START_PROFILE(syscall_fntimes);
2769 if (is_named_stream(fsp->fsp_name)) {
2770 errno = ENOENT;
2771 goto out;
2774 if (ft != NULL) {
2775 if (is_omit_timespec(&ft->atime)) {
2776 ft->atime = fsp->fsp_name->st.st_ex_atime;
2779 if (is_omit_timespec(&ft->mtime)) {
2780 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2783 if (!is_omit_timespec(&ft->create_time)) {
2784 set_create_timespec_ea(fsp,
2785 ft->create_time);
2788 if ((timespec_compare(&ft->atime,
2789 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2790 (timespec_compare(&ft->mtime,
2791 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2792 result = 0;
2793 goto out;
2796 ts[0] = ft->atime;
2797 ts[1] = ft->mtime;
2798 times = ts;
2799 } else {
2800 times = NULL;
2803 if (!fsp->fsp_flags.is_pathref) {
2804 result = futimens(fsp_get_io_fd(fsp), times);
2805 goto out;
2808 if (fsp->fsp_flags.have_proc_fds) {
2809 int fd = fsp_get_pathref_fd(fsp);
2810 const char *p = NULL;
2811 char buf[PATH_MAX];
2813 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2814 if (p != NULL) {
2816 * The dirfd argument of utimensat is ignored when
2817 * pathname is an absolute path
2819 result = utimensat(AT_FDCWD, p, times, 0);
2820 } else {
2821 result = -1;
2824 goto out;
2828 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2829 * path translation mechanism. Fallback to path based call.
2831 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2833 out:
2834 END_PROFILE(syscall_fntimes);
2836 return result;
2840 /*********************************************************************
2841 A version of ftruncate that will write the space on disk if strict
2842 allocate is set.
2843 **********************************************************************/
2845 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2847 off_t space_to_write;
2848 uint64_t space_avail;
2849 uint64_t bsize,dfree,dsize;
2850 int ret;
2851 NTSTATUS status;
2852 SMB_STRUCT_STAT *pst;
2853 bool ok;
2855 ok = vfs_valid_pwrite_range(len, 0);
2856 if (!ok) {
2857 errno = EINVAL;
2858 return -1;
2861 status = vfs_stat_fsp(fsp);
2862 if (!NT_STATUS_IS_OK(status)) {
2863 return -1;
2865 pst = &fsp->fsp_name->st;
2867 #ifdef S_ISFIFO
2868 if (S_ISFIFO(pst->st_ex_mode))
2869 return 0;
2870 #endif
2872 if (pst->st_ex_size == len)
2873 return 0;
2875 /* Shrink - just ftruncate. */
2876 if (pst->st_ex_size > len)
2877 return ftruncate(fsp_get_io_fd(fsp), len);
2879 space_to_write = len - pst->st_ex_size;
2881 /* for allocation try fallocate first. This can fail on some
2882 platforms e.g. when the filesystem doesn't support it and no
2883 emulation is being done by the libc (like on AIX with JFS1). In that
2884 case we do our own emulation. fallocate implementations can
2885 return ENOTSUP or EINVAL in cases like that. */
2886 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2887 if (ret == -1 && errno == ENOSPC) {
2888 return -1;
2890 if (ret == 0) {
2891 return 0;
2893 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2894 "error %d. Falling back to slow manual allocation\n", errno));
2896 /* available disk space is enough or not? */
2897 space_avail =
2898 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2899 /* space_avail is 1k blocks */
2900 if (space_avail == (uint64_t)-1 ||
2901 ((uint64_t)space_to_write/1024 > space_avail) ) {
2902 errno = ENOSPC;
2903 return -1;
2906 /* Write out the real space on disk. */
2907 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2908 if (ret != 0) {
2909 return -1;
2912 return 0;
2915 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2917 int result = -1;
2918 SMB_STRUCT_STAT *pst;
2919 NTSTATUS status;
2920 char c = 0;
2922 START_PROFILE(syscall_ftruncate);
2924 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2925 result = strict_allocate_ftruncate(handle, fsp, len);
2926 END_PROFILE(syscall_ftruncate);
2927 return result;
2930 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2931 ftruncate if the system supports it. Then I discovered that
2932 you can have some filesystems that support ftruncate
2933 expansion and some that don't! On Linux fat can't do
2934 ftruncate extend but ext2 can. */
2936 result = ftruncate(fsp_get_io_fd(fsp), len);
2938 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2939 extend a file with ftruncate. Provide alternate implementation
2940 for this */
2942 /* Do an fstat to see if the file is longer than the requested
2943 size in which case the ftruncate above should have
2944 succeeded or shorter, in which case seek to len - 1 and
2945 write 1 byte of zero */
2946 status = vfs_stat_fsp(fsp);
2947 if (!NT_STATUS_IS_OK(status)) {
2948 goto done;
2951 /* We need to update the files_struct after successful ftruncate */
2952 if (result == 0) {
2953 goto done;
2956 pst = &fsp->fsp_name->st;
2958 #ifdef S_ISFIFO
2959 if (S_ISFIFO(pst->st_ex_mode)) {
2960 result = 0;
2961 goto done;
2963 #endif
2965 if (pst->st_ex_size == len) {
2966 result = 0;
2967 goto done;
2970 if (pst->st_ex_size > len) {
2971 /* the ftruncate should have worked */
2972 goto done;
2975 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
2976 goto done;
2979 result = 0;
2981 done:
2983 END_PROFILE(syscall_ftruncate);
2984 return result;
2987 static int vfswrap_fallocate(vfs_handle_struct *handle,
2988 files_struct *fsp,
2989 uint32_t mode,
2990 off_t offset,
2991 off_t len)
2993 int result;
2995 START_PROFILE(syscall_fallocate);
2996 if (mode == 0) {
2997 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
2999 * posix_fallocate returns 0 on success, errno on error
3000 * and doesn't set errno. Make it behave like fallocate()
3001 * which returns -1, and sets errno on failure.
3003 if (result != 0) {
3004 errno = result;
3005 result = -1;
3007 } else {
3008 /* sys_fallocate handles filtering of unsupported mode flags */
3009 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3011 END_PROFILE(syscall_fallocate);
3012 return result;
3015 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3017 bool result;
3019 START_PROFILE(syscall_fcntl_lock);
3021 if (fsp->fsp_flags.use_ofd_locks) {
3022 op = map_process_lock_to_ofd_lock(op);
3025 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3026 END_PROFILE(syscall_fcntl_lock);
3027 return result;
3030 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3031 files_struct *fsp,
3032 uint32_t share_access,
3033 uint32_t access_mask)
3035 errno = ENOTSUP;
3036 return -1;
3039 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3040 va_list cmd_arg)
3042 void *argp;
3043 va_list dup_cmd_arg;
3044 int result;
3045 int val;
3047 START_PROFILE(syscall_fcntl);
3049 va_copy(dup_cmd_arg, cmd_arg);
3051 switch(cmd) {
3052 case F_SETLK:
3053 case F_SETLKW:
3054 case F_GETLK:
3055 #if defined(HAVE_OFD_LOCKS)
3056 case F_OFD_SETLK:
3057 case F_OFD_SETLKW:
3058 case F_OFD_GETLK:
3059 #endif
3060 #if defined(HAVE_F_OWNER_EX)
3061 case F_GETOWN_EX:
3062 case F_SETOWN_EX:
3063 #endif
3064 #if defined(HAVE_RW_HINTS)
3065 case F_GET_RW_HINT:
3066 case F_SET_RW_HINT:
3067 case F_GET_FILE_RW_HINT:
3068 case F_SET_FILE_RW_HINT:
3069 #endif
3070 argp = va_arg(dup_cmd_arg, void *);
3071 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3072 break;
3073 default:
3074 val = va_arg(dup_cmd_arg, int);
3075 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3078 va_end(dup_cmd_arg);
3080 END_PROFILE(syscall_fcntl);
3081 return result;
3084 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3086 bool result;
3087 int op = F_GETLK;
3089 START_PROFILE(syscall_fcntl_getlock);
3091 if (fsp->fsp_flags.use_ofd_locks) {
3092 op = map_process_lock_to_ofd_lock(op);
3095 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3096 END_PROFILE(syscall_fcntl_getlock);
3097 return result;
3100 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3101 int leasetype)
3103 int result = -1;
3105 START_PROFILE(syscall_linux_setlease);
3107 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3109 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3110 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3111 #else
3112 errno = ENOSYS;
3113 #endif
3114 END_PROFILE(syscall_linux_setlease);
3115 return result;
3118 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3119 const struct smb_filename *link_target,
3120 struct files_struct *dirfsp,
3121 const struct smb_filename *new_smb_fname)
3123 int result;
3125 START_PROFILE(syscall_symlinkat);
3127 SMB_ASSERT(!is_named_stream(new_smb_fname));
3129 result = symlinkat(link_target->base_name,
3130 fsp_get_pathref_fd(dirfsp),
3131 new_smb_fname->base_name);
3132 END_PROFILE(syscall_symlinkat);
3133 return result;
3136 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3137 const struct files_struct *dirfsp,
3138 const struct smb_filename *smb_fname,
3139 char *buf,
3140 size_t bufsiz)
3142 int result;
3144 START_PROFILE(syscall_readlinkat);
3146 SMB_ASSERT(!is_named_stream(smb_fname));
3148 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3149 smb_fname->base_name,
3150 buf,
3151 bufsiz);
3153 END_PROFILE(syscall_readlinkat);
3154 return result;
3157 static int vfswrap_linkat(vfs_handle_struct *handle,
3158 files_struct *srcfsp,
3159 const struct smb_filename *old_smb_fname,
3160 files_struct *dstfsp,
3161 const struct smb_filename *new_smb_fname,
3162 int flags)
3164 int result;
3166 START_PROFILE(syscall_linkat);
3168 SMB_ASSERT(!is_named_stream(old_smb_fname));
3169 SMB_ASSERT(!is_named_stream(new_smb_fname));
3171 result = linkat(fsp_get_pathref_fd(srcfsp),
3172 old_smb_fname->base_name,
3173 fsp_get_pathref_fd(dstfsp),
3174 new_smb_fname->base_name,
3175 flags);
3177 END_PROFILE(syscall_linkat);
3178 return result;
3181 static int vfswrap_mknodat(vfs_handle_struct *handle,
3182 files_struct *dirfsp,
3183 const struct smb_filename *smb_fname,
3184 mode_t mode,
3185 SMB_DEV_T dev)
3187 int result;
3189 START_PROFILE(syscall_mknodat);
3191 SMB_ASSERT(!is_named_stream(smb_fname));
3193 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3194 smb_fname->base_name,
3195 mode,
3196 dev);
3198 END_PROFILE(syscall_mknodat);
3199 return result;
3202 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3203 TALLOC_CTX *ctx,
3204 const struct smb_filename *smb_fname)
3206 char *result;
3207 struct smb_filename *result_fname = NULL;
3209 START_PROFILE(syscall_realpath);
3210 result = sys_realpath(smb_fname->base_name);
3211 END_PROFILE(syscall_realpath);
3212 if (result) {
3213 result_fname = synthetic_smb_fname(ctx,
3214 result,
3215 NULL,
3216 NULL,
3219 SAFE_FREE(result);
3221 return result_fname;
3224 static int vfswrap_fchflags(vfs_handle_struct *handle,
3225 struct files_struct *fsp,
3226 unsigned int flags)
3228 #ifdef HAVE_FCHFLAGS
3229 int fd = fsp_get_pathref_fd(fsp);
3231 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3233 if (!fsp->fsp_flags.is_pathref) {
3234 return fchflags(fd, flags);
3237 if (fsp->fsp_flags.have_proc_fds) {
3238 const char *p = NULL;
3239 char buf[PATH_MAX];
3241 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3242 if (p == NULL) {
3243 return -1;
3246 return chflags(p, flags);
3250 * This is no longer a handle based call.
3252 return chflags(fsp->fsp_name->base_name, flags);
3253 #else
3254 errno = ENOSYS;
3255 return -1;
3256 #endif
3259 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3260 const SMB_STRUCT_STAT *sbuf)
3262 struct file_id key;
3264 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3265 * blob */
3266 ZERO_STRUCT(key);
3268 key.devid = sbuf->st_ex_dev;
3269 key.inode = sbuf->st_ex_ino;
3270 /* key.extid is unused by default. */
3272 return key;
3275 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3276 const SMB_STRUCT_STAT *psbuf)
3278 uint64_t file_id;
3280 if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
3281 return psbuf->st_ex_file_id;
3284 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3285 return (uint64_t)psbuf->st_ex_ino;
3288 /* FileIDLow */
3289 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3291 /* FileIDHigh */
3292 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3294 return file_id;
3297 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3298 struct files_struct *fsp,
3299 TALLOC_CTX *mem_ctx,
3300 unsigned int *pnum_streams,
3301 struct stream_struct **pstreams)
3303 struct stream_struct *tmp_streams = NULL;
3304 unsigned int num_streams = *pnum_streams;
3305 struct stream_struct *streams = *pstreams;
3306 NTSTATUS status;
3308 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3310 if (fsp->fsp_flags.is_directory) {
3312 * No default streams on directories
3314 goto done;
3316 status = vfs_stat_fsp(fsp);
3317 if (!NT_STATUS_IS_OK(status)) {
3318 return status;
3321 if (num_streams + 1 < 1) {
3322 /* Integer wrap. */
3323 return NT_STATUS_INVALID_PARAMETER;
3326 tmp_streams = talloc_realloc(mem_ctx,
3327 streams,
3328 struct stream_struct,
3329 num_streams + 1);
3330 if (tmp_streams == NULL) {
3331 return NT_STATUS_NO_MEMORY;
3333 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3334 if (tmp_streams[num_streams].name == NULL) {
3335 return NT_STATUS_NO_MEMORY;
3337 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3338 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3339 handle->conn,
3340 fsp,
3341 &fsp->fsp_name->st);
3342 num_streams += 1;
3344 *pnum_streams = num_streams;
3345 *pstreams = tmp_streams;
3346 done:
3347 return NT_STATUS_OK;
3350 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
3351 const struct smb_filename *path,
3352 const char *name,
3353 TALLOC_CTX *mem_ctx,
3354 char **found_name)
3357 * Don't fall back to get_real_filename so callers can differentiate
3358 * between a full directory scan and an actual case-insensitive stat.
3360 errno = EOPNOTSUPP;
3361 return -1;
3364 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3365 const struct smb_filename *smb_fname)
3367 return handle->conn->connectpath;
3370 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3371 struct byte_range_lock *br_lck,
3372 struct lock_struct *plock)
3374 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3376 /* Note: blr is not used in the default implementation. */
3377 return brl_lock_windows_default(br_lck, plock);
3380 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3381 struct byte_range_lock *br_lck,
3382 const struct lock_struct *plock)
3384 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3386 return brl_unlock_windows_default(br_lck, plock);
3389 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3390 files_struct *fsp,
3391 struct lock_struct *plock)
3393 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3394 plock->lock_type == WRITE_LOCK);
3396 return strict_lock_check_default(fsp, plock);
3399 /* NT ACL operations. */
3401 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3402 files_struct *fsp,
3403 uint32_t security_info,
3404 TALLOC_CTX *mem_ctx,
3405 struct security_descriptor **ppdesc)
3407 NTSTATUS result;
3409 START_PROFILE(fget_nt_acl);
3411 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3413 result = posix_fget_nt_acl(fsp, security_info,
3414 mem_ctx, ppdesc);
3415 END_PROFILE(fget_nt_acl);
3416 return result;
3419 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3421 NTSTATUS result;
3423 START_PROFILE(fset_nt_acl);
3425 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3427 result = set_nt_acl(fsp, security_info_sent, psd);
3428 END_PROFILE(fset_nt_acl);
3429 return result;
3432 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3433 struct smb_filename *file,
3434 struct security_acl *sacl,
3435 uint32_t access_requested,
3436 uint32_t access_denied)
3438 return NT_STATUS_OK; /* Nothing to do here ... */
3441 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3442 files_struct *fsp,
3443 SMB_ACL_TYPE_T type,
3444 TALLOC_CTX *mem_ctx)
3446 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3448 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3451 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3452 files_struct *fsp,
3453 SMB_ACL_TYPE_T type,
3454 SMB_ACL_T theacl)
3456 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3458 return sys_acl_set_fd(handle, fsp, type, theacl);
3461 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3462 files_struct *fsp)
3464 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3466 return sys_acl_delete_def_fd(handle, fsp);
3469 /****************************************************************
3470 Extended attribute operations.
3471 *****************************************************************/
3473 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3474 struct files_struct *fsp,
3475 const char *name,
3476 void *value,
3477 size_t size)
3479 int fd = fsp_get_pathref_fd(fsp);
3481 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3483 if (!fsp->fsp_flags.is_pathref) {
3484 return fgetxattr(fd, name, value, size);
3487 if (fsp->fsp_flags.have_proc_fds) {
3488 const char *p = NULL;
3489 char buf[PATH_MAX];
3491 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3492 if (p == NULL) {
3493 return -1;
3496 return getxattr(p, name, value, size);
3500 * This is no longer a handle based call.
3502 return getxattr(fsp->fsp_name->base_name, name, value, size);
3505 struct vfswrap_getxattrat_state {
3506 struct tevent_context *ev;
3507 struct vfs_handle_struct *handle;
3508 files_struct *dir_fsp;
3509 const struct smb_filename *smb_fname;
3512 * The following variables are talloced off "state" which is protected
3513 * by a destructor and thus are guaranteed to be safe to be used in the
3514 * job function in the worker thread.
3516 char *name;
3517 const char *xattr_name;
3518 uint8_t *xattr_value;
3519 struct security_unix_token *token;
3521 ssize_t xattr_size;
3522 struct vfs_aio_state vfs_aio_state;
3523 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3526 static int vfswrap_getxattrat_state_destructor(
3527 struct vfswrap_getxattrat_state *state)
3529 return -1;
3532 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3533 static void vfswrap_getxattrat_do_async(void *private_data);
3534 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3536 static struct tevent_req *vfswrap_getxattrat_send(
3537 TALLOC_CTX *mem_ctx,
3538 struct tevent_context *ev,
3539 struct vfs_handle_struct *handle,
3540 files_struct *dir_fsp,
3541 const struct smb_filename *smb_fname,
3542 const char *xattr_name,
3543 size_t alloc_hint)
3545 struct tevent_req *req = NULL;
3546 struct tevent_req *subreq = NULL;
3547 struct vfswrap_getxattrat_state *state = NULL;
3548 size_t max_threads = 0;
3549 bool have_per_thread_cwd = false;
3550 bool have_per_thread_creds = false;
3551 bool do_async = false;
3553 SMB_ASSERT(!is_named_stream(smb_fname));
3555 req = tevent_req_create(mem_ctx, &state,
3556 struct vfswrap_getxattrat_state);
3557 if (req == NULL) {
3558 return NULL;
3560 *state = (struct vfswrap_getxattrat_state) {
3561 .ev = ev,
3562 .handle = handle,
3563 .dir_fsp = dir_fsp,
3564 .smb_fname = smb_fname,
3567 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3568 if (max_threads >= 1) {
3570 * We need a non sync threadpool!
3572 have_per_thread_cwd = per_thread_cwd_supported();
3574 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3575 have_per_thread_creds = true;
3576 #endif
3577 if (have_per_thread_cwd && have_per_thread_creds) {
3578 do_async = true;
3581 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3582 state->profile_bytes, 0);
3584 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3585 DBG_ERR("Need a valid directory fd\n");
3586 tevent_req_error(req, EINVAL);
3587 return tevent_req_post(req, ev);
3590 if (alloc_hint > 0) {
3591 state->xattr_value = talloc_zero_array(state,
3592 uint8_t,
3593 alloc_hint);
3594 if (tevent_req_nomem(state->xattr_value, req)) {
3595 return tevent_req_post(req, ev);
3599 if (!do_async) {
3600 vfswrap_getxattrat_do_sync(req);
3601 return tevent_req_post(req, ev);
3605 * Now allocate all parameters from a memory context that won't go away
3606 * no matter what. These paremeters will get used in threads and we
3607 * can't reliably cancel threads, so all buffers passed to the threads
3608 * must not be freed before all referencing threads terminate.
3611 state->name = talloc_strdup(state, smb_fname->base_name);
3612 if (tevent_req_nomem(state->name, req)) {
3613 return tevent_req_post(req, ev);
3616 state->xattr_name = talloc_strdup(state, xattr_name);
3617 if (tevent_req_nomem(state->xattr_name, req)) {
3618 return tevent_req_post(req, ev);
3622 * This is a hot codepath so at first glance one might think we should
3623 * somehow optimize away the token allocation and do a
3624 * talloc_reference() or similar black magic instead. But due to the
3625 * talloc_stackframe pool per SMB2 request this should be a simple copy
3626 * without a malloc in most cases.
3628 if (geteuid() == sec_initial_uid()) {
3629 state->token = root_unix_token(state);
3630 } else {
3631 state->token = copy_unix_token(
3632 state,
3633 dir_fsp->conn->session_info->unix_token);
3635 if (tevent_req_nomem(state->token, req)) {
3636 return tevent_req_post(req, ev);
3639 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3641 subreq = pthreadpool_tevent_job_send(
3642 state,
3644 dir_fsp->conn->sconn->pool,
3645 vfswrap_getxattrat_do_async,
3646 state);
3647 if (tevent_req_nomem(subreq, req)) {
3648 return tevent_req_post(req, ev);
3650 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3652 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3654 return req;
3657 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3659 struct vfswrap_getxattrat_state *state = tevent_req_data(
3660 req, struct vfswrap_getxattrat_state);
3662 state->xattr_size = vfswrap_fgetxattr(state->handle,
3663 state->smb_fname->fsp,
3664 state->xattr_name,
3665 state->xattr_value,
3666 talloc_array_length(state->xattr_value));
3667 if (state->xattr_size == -1) {
3668 tevent_req_error(req, errno);
3669 return;
3672 tevent_req_done(req);
3673 return;
3676 static void vfswrap_getxattrat_do_async(void *private_data)
3678 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3679 private_data, struct vfswrap_getxattrat_state);
3680 struct timespec start_time;
3681 struct timespec end_time;
3682 int ret;
3684 PROFILE_TIMESTAMP(&start_time);
3685 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3688 * Here we simulate a getxattrat()
3689 * call using fchdir();getxattr()
3692 per_thread_cwd_activate();
3694 /* Become the correct credential on this thread. */
3695 ret = set_thread_credentials(state->token->uid,
3696 state->token->gid,
3697 (size_t)state->token->ngroups,
3698 state->token->groups);
3699 if (ret != 0) {
3700 state->xattr_size = -1;
3701 state->vfs_aio_state.error = errno;
3702 goto end_profile;
3705 state->xattr_size = vfswrap_fgetxattr(state->handle,
3706 state->smb_fname->fsp,
3707 state->xattr_name,
3708 state->xattr_value,
3709 talloc_array_length(state->xattr_value));
3710 if (state->xattr_size == -1) {
3711 state->vfs_aio_state.error = errno;
3714 end_profile:
3715 PROFILE_TIMESTAMP(&end_time);
3716 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3717 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3720 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3722 struct tevent_req *req = tevent_req_callback_data(
3723 subreq, struct tevent_req);
3724 struct vfswrap_getxattrat_state *state = tevent_req_data(
3725 req, struct vfswrap_getxattrat_state);
3726 int ret;
3727 bool ok;
3730 * Make sure we run as the user again
3732 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3733 SMB_ASSERT(ok);
3735 ret = pthreadpool_tevent_job_recv(subreq);
3736 TALLOC_FREE(subreq);
3737 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3738 talloc_set_destructor(state, NULL);
3739 if (ret != 0) {
3740 if (ret != EAGAIN) {
3741 tevent_req_error(req, ret);
3742 return;
3745 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3746 * means the lower level pthreadpool failed to create a new
3747 * thread. Fallback to sync processing in that case to allow
3748 * some progress for the client.
3750 vfswrap_getxattrat_do_sync(req);
3751 return;
3754 if (state->xattr_size == -1) {
3755 tevent_req_error(req, state->vfs_aio_state.error);
3756 return;
3759 if (state->xattr_value == NULL) {
3761 * The caller only wanted the size.
3763 tevent_req_done(req);
3764 return;
3768 * shrink the buffer to the returned size.
3769 * (can't fail). It means NULL if size is 0.
3771 state->xattr_value = talloc_realloc(state,
3772 state->xattr_value,
3773 uint8_t,
3774 state->xattr_size);
3776 tevent_req_done(req);
3779 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3780 struct vfs_aio_state *aio_state,
3781 TALLOC_CTX *mem_ctx,
3782 uint8_t **xattr_value)
3784 struct vfswrap_getxattrat_state *state = tevent_req_data(
3785 req, struct vfswrap_getxattrat_state);
3786 ssize_t xattr_size;
3788 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3789 tevent_req_received(req);
3790 return -1;
3793 *aio_state = state->vfs_aio_state;
3794 xattr_size = state->xattr_size;
3795 if (xattr_value != NULL) {
3796 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3799 tevent_req_received(req);
3800 return xattr_size;
3803 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3805 int fd = fsp_get_pathref_fd(fsp);
3807 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3809 if (!fsp->fsp_flags.is_pathref) {
3810 return flistxattr(fd, list, size);
3813 if (fsp->fsp_flags.have_proc_fds) {
3814 const char *p = NULL;
3815 char buf[PATH_MAX];
3817 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3818 if (p == NULL) {
3819 return -1;
3822 return listxattr(p, list, size);
3826 * This is no longer a handle based call.
3828 return listxattr(fsp->fsp_name->base_name, list, size);
3831 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3833 int fd = fsp_get_pathref_fd(fsp);
3835 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3837 if (!fsp->fsp_flags.is_pathref) {
3838 return fremovexattr(fd, name);
3841 if (fsp->fsp_flags.have_proc_fds) {
3842 const char *p = NULL;
3843 char buf[PATH_MAX];
3845 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3846 if (p == NULL) {
3847 return -1;
3850 return removexattr(p, name);
3854 * This is no longer a handle based call.
3856 return removexattr(fsp->fsp_name->base_name, name);
3859 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3861 int fd = fsp_get_pathref_fd(fsp);
3863 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3865 if (!fsp->fsp_flags.is_pathref) {
3866 return fsetxattr(fd, name, value, size, flags);
3869 if (fsp->fsp_flags.have_proc_fds) {
3870 const char *p = NULL;
3871 char buf[PATH_MAX];
3873 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3874 if (p == NULL) {
3875 return -1;
3878 return setxattr(p, name, value, size, flags);
3882 * This is no longer a handle based call.
3884 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3887 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3889 return false;
3892 static bool vfswrap_is_offline(struct connection_struct *conn,
3893 const struct smb_filename *fname)
3895 NTSTATUS status;
3896 char *path;
3897 bool offline = false;
3899 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3900 return false;
3903 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3904 #if defined(ENOTSUP)
3905 errno = ENOTSUP;
3906 #endif
3907 return false;
3910 status = get_full_smb_filename(talloc_tos(), fname, &path);
3911 if (!NT_STATUS_IS_OK(status)) {
3912 errno = map_errno_from_nt_status(status);
3913 return false;
3916 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3918 TALLOC_FREE(path);
3920 return offline;
3923 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3924 struct files_struct *fsp,
3925 TALLOC_CTX *mem_ctx,
3926 DATA_BLOB *cookie)
3928 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3931 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3932 struct files_struct *fsp,
3933 const DATA_BLOB old_cookie,
3934 TALLOC_CTX *mem_ctx,
3935 DATA_BLOB *new_cookie)
3937 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3938 new_cookie);
3941 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3942 struct smb_request *smb1req,
3943 struct smbXsrv_open *op,
3944 const DATA_BLOB old_cookie,
3945 TALLOC_CTX *mem_ctx,
3946 struct files_struct **fsp,
3947 DATA_BLOB *new_cookie)
3949 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3950 old_cookie, mem_ctx,
3951 fsp, new_cookie);
3954 static struct vfs_fn_pointers vfs_default_fns = {
3955 /* Disk operations */
3957 .connect_fn = vfswrap_connect,
3958 .disconnect_fn = vfswrap_disconnect,
3959 .disk_free_fn = vfswrap_disk_free,
3960 .get_quota_fn = vfswrap_get_quota,
3961 .set_quota_fn = vfswrap_set_quota,
3962 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3963 .statvfs_fn = vfswrap_statvfs,
3964 .fs_capabilities_fn = vfswrap_fs_capabilities,
3965 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3966 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3967 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3968 .snap_check_path_fn = vfswrap_snap_check_path,
3969 .snap_create_fn = vfswrap_snap_create,
3970 .snap_delete_fn = vfswrap_snap_delete,
3972 /* Directory operations */
3974 .fdopendir_fn = vfswrap_fdopendir,
3975 .readdir_fn = vfswrap_readdir,
3976 .freaddir_attr_fn = vfswrap_freaddir_attr,
3977 .seekdir_fn = vfswrap_seekdir,
3978 .telldir_fn = vfswrap_telldir,
3979 .rewind_dir_fn = vfswrap_rewinddir,
3980 .mkdirat_fn = vfswrap_mkdirat,
3981 .closedir_fn = vfswrap_closedir,
3983 /* File operations */
3985 .openat_fn = vfswrap_openat,
3986 .create_file_fn = vfswrap_create_file,
3987 .close_fn = vfswrap_close,
3988 .pread_fn = vfswrap_pread,
3989 .pread_send_fn = vfswrap_pread_send,
3990 .pread_recv_fn = vfswrap_pread_recv,
3991 .pwrite_fn = vfswrap_pwrite,
3992 .pwrite_send_fn = vfswrap_pwrite_send,
3993 .pwrite_recv_fn = vfswrap_pwrite_recv,
3994 .lseek_fn = vfswrap_lseek,
3995 .sendfile_fn = vfswrap_sendfile,
3996 .recvfile_fn = vfswrap_recvfile,
3997 .renameat_fn = vfswrap_renameat,
3998 .fsync_send_fn = vfswrap_fsync_send,
3999 .fsync_recv_fn = vfswrap_fsync_recv,
4000 .stat_fn = vfswrap_stat,
4001 .fstat_fn = vfswrap_fstat,
4002 .lstat_fn = vfswrap_lstat,
4003 .get_alloc_size_fn = vfswrap_get_alloc_size,
4004 .unlinkat_fn = vfswrap_unlinkat,
4005 .fchmod_fn = vfswrap_fchmod,
4006 .fchown_fn = vfswrap_fchown,
4007 .lchown_fn = vfswrap_lchown,
4008 .chdir_fn = vfswrap_chdir,
4009 .getwd_fn = vfswrap_getwd,
4010 .fntimes_fn = vfswrap_fntimes,
4011 .ftruncate_fn = vfswrap_ftruncate,
4012 .fallocate_fn = vfswrap_fallocate,
4013 .lock_fn = vfswrap_lock,
4014 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4015 .fcntl_fn = vfswrap_fcntl,
4016 .linux_setlease_fn = vfswrap_linux_setlease,
4017 .getlock_fn = vfswrap_getlock,
4018 .symlinkat_fn = vfswrap_symlinkat,
4019 .readlinkat_fn = vfswrap_readlinkat,
4020 .linkat_fn = vfswrap_linkat,
4021 .mknodat_fn = vfswrap_mknodat,
4022 .realpath_fn = vfswrap_realpath,
4023 .fchflags_fn = vfswrap_fchflags,
4024 .file_id_create_fn = vfswrap_file_id_create,
4025 .fs_file_id_fn = vfswrap_fs_file_id,
4026 .fstreaminfo_fn = vfswrap_fstreaminfo,
4027 .get_real_filename_fn = vfswrap_get_real_filename,
4028 .connectpath_fn = vfswrap_connectpath,
4029 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4030 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4031 .strict_lock_check_fn = vfswrap_strict_lock_check,
4032 .translate_name_fn = vfswrap_translate_name,
4033 .parent_pathname_fn = vfswrap_parent_pathname,
4034 .fsctl_fn = vfswrap_fsctl,
4035 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4036 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4037 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4038 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4039 .offload_read_send_fn = vfswrap_offload_read_send,
4040 .offload_read_recv_fn = vfswrap_offload_read_recv,
4041 .offload_write_send_fn = vfswrap_offload_write_send,
4042 .offload_write_recv_fn = vfswrap_offload_write_recv,
4043 .fget_compression_fn = vfswrap_fget_compression,
4044 .set_compression_fn = vfswrap_set_compression,
4046 /* NT ACL operations. */
4048 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4049 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4050 .audit_file_fn = vfswrap_audit_file,
4052 /* POSIX ACL operations. */
4054 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4055 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4056 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4057 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4059 /* EA operations. */
4060 .getxattrat_send_fn = vfswrap_getxattrat_send,
4061 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4062 .fgetxattr_fn = vfswrap_fgetxattr,
4063 .flistxattr_fn = vfswrap_flistxattr,
4064 .fremovexattr_fn = vfswrap_fremovexattr,
4065 .fsetxattr_fn = vfswrap_fsetxattr,
4067 /* aio operations */
4068 .aio_force_fn = vfswrap_aio_force,
4070 /* durable handle operations */
4071 .durable_cookie_fn = vfswrap_durable_cookie,
4072 .durable_disconnect_fn = vfswrap_durable_disconnect,
4073 .durable_reconnect_fn = vfswrap_durable_reconnect,
4076 static_decl_vfs;
4077 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4080 * Here we need to implement every call!
4082 * As this is the end of the vfs module chain.
4084 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4085 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4086 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);