smbd: reject FILE_ATTRIBUTE_TEMPORARY on directories
[Samba.git] / source3 / modules / vfs_default.c
blob48ff174ebbe8dd67cd3998d4a7563af7e687f752
1 /*
2 Unix SMB/CIFS implementation.
3 Wrap disk only vfs functions to sidestep dodgy compilers.
4 Copyright (C) Tim Potter 1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "ntioctl.h"
27 #include "smbprofile.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/lookup_sid.h"
30 #include "source3/include/msdfs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "lib/util/sys_rw.h"
35 #include "lib/pthreadpool/pthreadpool_tevent.h"
36 #include "librpc/gen_ndr/ndr_ioctl.h"
37 #include "offload_token.h"
38 #include "util_reparse.h"
39 #include "lib/util/string_wrappers.h"
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_VFS
44 /* Check for NULL pointer parameters in vfswrap_* functions */
46 /* We don't want to have NULL function pointers lying around. Someone
47 is sure to try and execute them. These stubs are used to prevent
48 this possibility. */
50 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
52 bool bval;
54 handle->conn->have_proc_fds = sys_have_proc_fds();
57 * assume the kernel will support openat2(),
58 * it will be reset on the first ENOSYS.
60 * Note that libreplace will always provide openat2(),
61 * but return -1/errno = ENOSYS...
63 * The option is only there to test the fallback code.
65 bval = lp_parm_bool(SNUM(handle->conn),
66 "vfs_default",
67 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
68 true);
69 if (bval) {
70 handle->conn->open_how_resolve |=
71 VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
74 return 0; /* Return >= 0 for success */
77 static void vfswrap_disconnect(vfs_handle_struct *handle)
81 /* Disk operations */
83 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
84 const struct smb_filename *smb_fname,
85 uint64_t *bsize,
86 uint64_t *dfree,
87 uint64_t *dsize)
89 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
90 return (uint64_t)-1;
93 *bsize = 512;
94 return *dfree / 2;
97 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
98 const struct smb_filename *smb_fname,
99 enum SMB_QUOTA_TYPE qtype,
100 unid_t id,
101 SMB_DISK_QUOTA *qt)
103 #ifdef HAVE_SYS_QUOTAS
104 int result;
106 START_PROFILE(syscall_get_quota);
107 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
108 END_PROFILE(syscall_get_quota);
109 return result;
110 #else
111 errno = ENOSYS;
112 return -1;
113 #endif
116 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
118 #ifdef HAVE_SYS_QUOTAS
119 int result;
121 START_PROFILE(syscall_set_quota);
122 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
123 END_PROFILE(syscall_set_quota);
124 return result;
125 #else
126 errno = ENOSYS;
127 return -1;
128 #endif
131 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
132 struct files_struct *fsp,
133 struct shadow_copy_data *shadow_copy_data,
134 bool labels)
136 errno = ENOSYS;
137 return -1; /* Not implemented. */
140 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
141 const struct smb_filename *smb_fname,
142 struct vfs_statvfs_struct *statbuf)
144 return sys_statvfs(smb_fname->base_name, statbuf);
147 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
148 enum timestamp_set_resolution *p_ts_res)
150 const struct loadparm_substitution *lp_sub =
151 loadparm_s3_global_substitution();
152 connection_struct *conn = handle->conn;
153 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
154 struct smb_filename *smb_fname_cpath = NULL;
155 struct vfs_statvfs_struct statbuf;
156 int ret;
158 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
159 conn->connectpath,
160 NULL,
161 NULL,
164 if (smb_fname_cpath == NULL) {
165 return caps;
168 ZERO_STRUCT(statbuf);
169 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
170 if (ret == 0) {
171 caps = statbuf.FsCapabilities;
174 *p_ts_res = TIMESTAMP_SET_SECONDS;
176 /* Work out what timestamp resolution we can
177 * use when setting a timestamp. */
179 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
180 if (ret == -1) {
181 TALLOC_FREE(smb_fname_cpath);
182 return caps;
185 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
186 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
187 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
188 /* If any of the normal UNIX directory timestamps
189 * have a non-zero tv_nsec component assume
190 * we might be able to set sub-second timestamps.
191 * See what filetime set primitives we have.
193 #if defined(HAVE_UTIMENSAT)
194 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
195 #elif defined(HAVE_UTIMES)
196 /* utimes allows msec timestamps to be set. */
197 *p_ts_res = TIMESTAMP_SET_MSEC;
198 #elif defined(HAVE_UTIME)
199 /* utime only allows sec timestamps to be set. */
200 *p_ts_res = TIMESTAMP_SET_SECONDS;
201 #endif
203 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
204 "resolution of %s "
205 "available on share %s, directory %s\n",
206 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
207 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
208 conn->connectpath ));
210 TALLOC_FREE(smb_fname_cpath);
211 return caps;
214 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
215 struct dfs_GetDFSReferral *r)
217 struct junction_map *junction = NULL;
218 size_t consumedcnt = 0;
219 bool self_referral = false;
220 char *pathnamep = NULL;
221 char *local_dfs_path = NULL;
222 NTSTATUS status;
223 size_t i;
224 uint16_t max_referral_level = r->in.req.max_referral_level;
226 if (DEBUGLVL(10)) {
227 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
230 /* get the junction entry */
231 if (r->in.req.servername == NULL) {
232 return NT_STATUS_NOT_FOUND;
236 * Trim pathname sent by client so it begins with only one backslash.
237 * Two backslashes confuse some dfs clients
240 local_dfs_path = talloc_strdup(r, r->in.req.servername);
241 if (local_dfs_path == NULL) {
242 return NT_STATUS_NO_MEMORY;
244 pathnamep = local_dfs_path;
245 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
246 IS_DIRECTORY_SEP(pathnamep[1])) {
247 pathnamep++;
250 junction = talloc_zero(r, struct junction_map);
251 if (junction == NULL) {
252 return NT_STATUS_NO_MEMORY;
255 /* The following call can change cwd. */
256 status = get_referred_path(r,
257 handle->conn->session_info,
258 pathnamep,
259 handle->conn->sconn->remote_address,
260 handle->conn->sconn->local_address,
261 !handle->conn->sconn->using_smb2,
262 junction, &consumedcnt, &self_referral);
263 if (!NT_STATUS_IS_OK(status)) {
264 struct smb_filename connectpath_fname = {
265 .base_name = handle->conn->connectpath
267 vfs_ChDir(handle->conn, &connectpath_fname);
268 return status;
271 struct smb_filename connectpath_fname = {
272 .base_name = handle->conn->connectpath
274 vfs_ChDir(handle->conn, &connectpath_fname);
277 if (!self_referral) {
278 pathnamep[consumedcnt] = '\0';
280 if (DEBUGLVL(3)) {
281 dbgtext("Path %s to alternate path(s):",
282 pathnamep);
283 for (i=0; i < junction->referral_count; i++) {
284 dbgtext(" %s",
285 junction->referral_list[i].alternate_path);
287 dbgtext(".\n");
291 if (r->in.req.max_referral_level <= 2) {
292 max_referral_level = 2;
294 if (r->in.req.max_referral_level >= 3) {
295 max_referral_level = 3;
298 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
299 if (r->out.resp == NULL) {
300 return NT_STATUS_NO_MEMORY;
303 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
304 r->out.resp->nb_referrals = junction->referral_count;
306 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
307 if (self_referral) {
308 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
311 r->out.resp->referral_entries = talloc_zero_array(r,
312 struct dfs_referral_type,
313 r->out.resp->nb_referrals);
314 if (r->out.resp->referral_entries == NULL) {
315 return NT_STATUS_NO_MEMORY;
318 switch (max_referral_level) {
319 case 2:
320 for(i=0; i < junction->referral_count; i++) {
321 struct referral *ref = &junction->referral_list[i];
322 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
323 struct dfs_referral_type *t =
324 &r->out.resp->referral_entries[i];
325 struct dfs_referral_v2 *v2 = &t->referral.v2;
327 t->version = 2;
328 v2->size = VERSION2_REFERRAL_SIZE;
329 if (self_referral) {
330 v2->server_type = DFS_SERVER_ROOT;
331 } else {
332 v2->server_type = DFS_SERVER_NON_ROOT;
334 v2->entry_flags = 0;
335 v2->proximity = ref->proximity;
336 v2->ttl = ref->ttl;
337 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
338 if (v2->DFS_path == NULL) {
339 return NT_STATUS_NO_MEMORY;
341 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
342 if (v2->DFS_alt_path == NULL) {
343 return NT_STATUS_NO_MEMORY;
345 v2->netw_address = talloc_strdup(mem_ctx,
346 ref->alternate_path);
347 if (v2->netw_address == NULL) {
348 return NT_STATUS_NO_MEMORY;
352 break;
353 case 3:
354 for(i=0; i < junction->referral_count; i++) {
355 struct referral *ref = &junction->referral_list[i];
356 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
357 struct dfs_referral_type *t =
358 &r->out.resp->referral_entries[i];
359 struct dfs_referral_v3 *v3 = &t->referral.v3;
360 struct dfs_normal_referral *r1 = &v3->referrals.r1;
362 t->version = 3;
363 v3->size = VERSION3_REFERRAL_SIZE;
364 if (self_referral) {
365 v3->server_type = DFS_SERVER_ROOT;
366 } else {
367 v3->server_type = DFS_SERVER_NON_ROOT;
369 v3->entry_flags = 0;
370 v3->ttl = ref->ttl;
371 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
372 if (r1->DFS_path == NULL) {
373 return NT_STATUS_NO_MEMORY;
375 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
376 if (r1->DFS_alt_path == NULL) {
377 return NT_STATUS_NO_MEMORY;
379 r1->netw_address = talloc_strdup(mem_ctx,
380 ref->alternate_path);
381 if (r1->netw_address == NULL) {
382 return NT_STATUS_NO_MEMORY;
385 break;
386 default:
387 DEBUG(0,("Invalid dfs referral version: %d\n",
388 max_referral_level));
389 return NT_STATUS_INVALID_LEVEL;
392 if (DEBUGLVL(10)) {
393 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
396 return NT_STATUS_OK;
399 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
400 struct files_struct *dirfsp,
401 const struct smb_filename *smb_fname,
402 const struct referral *reflist,
403 size_t referral_count)
405 TALLOC_CTX *frame = talloc_stackframe();
406 NTSTATUS status = NT_STATUS_NO_MEMORY;
407 int ret;
408 char *msdfs_link = NULL;
410 /* Form the msdfs_link contents */
411 msdfs_link = msdfs_link_string(frame,
412 reflist,
413 referral_count);
414 if (msdfs_link == NULL) {
415 goto out;
418 ret = symlinkat(msdfs_link,
419 fsp_get_pathref_fd(dirfsp),
420 smb_fname->base_name);
421 if (ret == 0) {
422 status = NT_STATUS_OK;
423 } else {
424 status = map_nt_error_from_unix(errno);
427 out:
429 TALLOC_FREE(frame);
430 return status;
434 * Read and return the contents of a DFS redirect given a
435 * pathname. A caller can pass in NULL for ppreflist and
436 * preferral_count but still determine if this was a
437 * DFS redirect point by getting NT_STATUS_OK back
438 * without incurring the overhead of reading and parsing
439 * the referral contents.
442 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
443 TALLOC_CTX *mem_ctx,
444 struct files_struct *dirfsp,
445 struct smb_filename *smb_fname,
446 struct referral **ppreflist,
447 size_t *preferral_count)
449 NTSTATUS status = NT_STATUS_NO_MEMORY;
450 size_t bufsize;
451 char *link_target = NULL;
452 int referral_len;
453 bool ok;
454 #if defined(HAVE_BROKEN_READLINK)
455 char link_target_buf[PATH_MAX];
456 #else
457 char link_target_buf[7];
458 #endif
459 int ret;
461 if (is_named_stream(smb_fname)) {
462 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
463 goto err;
466 if (ppreflist == NULL && preferral_count == NULL) {
468 * We're only checking if this is a DFS
469 * redirect. We don't need to return data.
471 bufsize = sizeof(link_target_buf);
472 link_target = link_target_buf;
473 } else {
474 bufsize = PATH_MAX;
475 link_target = talloc_array(mem_ctx, char, bufsize);
476 if (!link_target) {
477 goto err;
481 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
482 smb_fname->base_name,
483 link_target,
484 bufsize - 1);
485 if (referral_len == -1) {
486 if (errno == EINVAL) {
488 * If the path isn't a link, readlinkat
489 * returns EINVAL. Allow the caller to
490 * detect this.
492 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
493 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
494 } else {
495 status = map_nt_error_from_unix(errno);
496 if (errno == ENOENT) {
497 DBG_NOTICE("Error reading "
498 "msdfs link %s: %s\n",
499 smb_fname->base_name,
500 strerror(errno));
501 } else {
502 DBG_ERR("Error reading "
503 "msdfs link %s: %s\n",
504 smb_fname->base_name,
505 strerror(errno));
508 goto err;
510 link_target[referral_len] = '\0';
512 DBG_INFO("%s -> %s\n",
513 smb_fname->base_name,
514 link_target);
516 if (!strnequal(link_target, "msdfs:", 6)) {
517 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
518 goto err;
521 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
522 smb_fname->base_name,
523 &smb_fname->st,
524 AT_SYMLINK_NOFOLLOW,
525 lp_fake_directory_create_times(SNUM(handle->conn)));
526 if (ret < 0) {
527 status = map_nt_error_from_unix(errno);
528 goto err;
531 if (ppreflist == NULL && preferral_count == NULL) {
532 /* Early return for checking if this is a DFS link. */
533 return NT_STATUS_OK;
536 ok = parse_msdfs_symlink(mem_ctx,
537 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
538 link_target,
539 ppreflist,
540 preferral_count);
542 if (ok) {
543 status = NT_STATUS_OK;
544 } else {
545 status = NT_STATUS_NO_MEMORY;
548 err:
550 if (link_target != link_target_buf) {
551 TALLOC_FREE(link_target);
553 return status;
556 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
557 TALLOC_CTX *mem_ctx,
558 const char *service_path,
559 char **base_volume)
561 return NT_STATUS_NOT_SUPPORTED;
564 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
565 TALLOC_CTX *mem_ctx,
566 const char *base_volume,
567 time_t *tstamp,
568 bool rw,
569 char **base_path,
570 char **snap_path)
572 return NT_STATUS_NOT_SUPPORTED;
575 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
576 TALLOC_CTX *mem_ctx,
577 char *base_path,
578 char *snap_path)
580 return NT_STATUS_NOT_SUPPORTED;
583 /* Directory operations */
585 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
586 files_struct *fsp,
587 const char *mask,
588 uint32_t attr)
590 DIR *result;
592 START_PROFILE(syscall_fdopendir);
593 result = sys_fdopendir(fsp_get_io_fd(fsp));
594 END_PROFILE(syscall_fdopendir);
595 return result;
599 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
600 struct files_struct *dirfsp,
601 DIR *dirp,
602 SMB_STRUCT_STAT *sbuf)
604 struct dirent *result;
605 bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
606 int flags = AT_SYMLINK_NOFOLLOW;
607 SMB_STRUCT_STAT st;
608 int ret;
610 START_PROFILE(syscall_readdir);
612 result = readdir(dirp);
613 END_PROFILE(syscall_readdir);
615 if (sbuf == NULL) {
616 return result;
618 if (result == NULL) {
619 return NULL;
623 * Default Posix readdir() does not give us stat info.
624 * Set to invalid to indicate we didn't return this info.
626 SET_STAT_INVALID(*sbuf);
628 ret = sys_fstatat(dirfd(dirp),
629 result->d_name,
630 &st,
631 flags,
632 fake_ctime);
633 if (ret != 0) {
634 return result;
638 * As this is an optimization, ignore it if we stat'ed a
639 * symlink for non-POSIX context. Make the caller do it again
640 * as we don't know if they wanted the link info, or its
641 * target info.
643 if (S_ISLNK(st.st_ex_mode) &&
644 !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
646 return result;
648 *sbuf = st;
650 return result;
653 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
654 struct files_struct *fsp,
655 TALLOC_CTX *mem_ctx,
656 struct readdir_attr_data **attr_data)
658 return NT_STATUS_NOT_SUPPORTED;
661 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
663 START_PROFILE(syscall_seekdir);
664 seekdir(dirp, offset);
665 END_PROFILE(syscall_seekdir);
668 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
670 long result;
671 START_PROFILE(syscall_telldir);
672 result = telldir(dirp);
673 END_PROFILE(syscall_telldir);
674 return result;
677 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
679 START_PROFILE(syscall_rewinddir);
680 rewinddir(dirp);
681 END_PROFILE(syscall_rewinddir);
684 static int vfswrap_mkdirat(vfs_handle_struct *handle,
685 struct files_struct *dirfsp,
686 const struct smb_filename *smb_fname,
687 mode_t mode)
689 int result;
691 START_PROFILE(syscall_mkdirat);
693 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
695 END_PROFILE(syscall_mkdirat);
696 return result;
699 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
701 int result;
703 START_PROFILE(syscall_closedir);
704 result = closedir(dirp);
705 END_PROFILE(syscall_closedir);
706 return result;
709 /* File operations */
711 static int vfswrap_openat(vfs_handle_struct *handle,
712 const struct files_struct *dirfsp,
713 const struct smb_filename *smb_fname,
714 files_struct *fsp,
715 const struct vfs_open_how *how)
717 int flags = how->flags;
718 mode_t mode = how->mode;
719 bool have_opath = false;
720 bool became_root = false;
721 int result;
723 START_PROFILE(syscall_openat);
725 if (how->resolve & ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
726 errno = ENOSYS;
727 result = -1;
728 goto out;
731 SMB_ASSERT(!is_named_stream(smb_fname));
733 #ifdef O_PATH
734 have_opath = true;
735 if (fsp->fsp_flags.is_pathref) {
736 flags |= O_PATH;
738 if (flags & O_PATH) {
740 * From "man 2 openat":
742 * When O_PATH is specified in flags, flag bits other than
743 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
745 * From "man 2 openat2":
747 * Whereas openat(2) ignores unknown bits in its flags
748 * argument, openat2() returns an error if unknown or
749 * conflicting flags are specified in how.flags.
751 * So we better clear ignored/invalid flags
752 * and only keep the exptected once.
754 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
756 #endif
758 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
759 struct open_how linux_how = {
760 .flags = flags,
761 .mode = mode,
762 .resolve = RESOLVE_NO_SYMLINKS,
765 result = openat2(fsp_get_pathref_fd(dirfsp),
766 smb_fname->base_name,
767 &linux_how,
768 sizeof(linux_how));
769 if (result == -1) {
770 if (errno == ENOSYS) {
772 * The kernel doesn't support
773 * openat2(), so indicate to
774 * the callers that
775 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
776 * would just be a waste of time.
778 fsp->conn->open_how_resolve &=
779 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
781 goto out;
784 goto done;
787 if (fsp->fsp_flags.is_pathref && !have_opath) {
788 become_root();
789 became_root = true;
792 result = openat(fsp_get_pathref_fd(dirfsp),
793 smb_fname->base_name,
794 flags,
795 mode);
797 if (became_root) {
798 unbecome_root();
801 done:
802 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
804 out:
805 END_PROFILE(syscall_openat);
806 return result;
808 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
809 struct smb_request *req,
810 struct files_struct *dirfsp,
811 struct smb_filename *smb_fname,
812 uint32_t access_mask,
813 uint32_t share_access,
814 uint32_t create_disposition,
815 uint32_t create_options,
816 uint32_t file_attributes,
817 uint32_t oplock_request,
818 const struct smb2_lease *lease,
819 uint64_t allocation_size,
820 uint32_t private_flags,
821 struct security_descriptor *sd,
822 struct ea_list *ea_list,
823 files_struct **result,
824 int *pinfo,
825 const struct smb2_create_blobs *in_context_blobs,
826 struct smb2_create_blobs *out_context_blobs)
828 return create_file_default(handle->conn, req, dirfsp, smb_fname,
829 access_mask, share_access,
830 create_disposition, create_options,
831 file_attributes, oplock_request, lease,
832 allocation_size, private_flags,
833 sd, ea_list, result,
834 pinfo, in_context_blobs, out_context_blobs);
837 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
839 int result;
841 START_PROFILE(syscall_close);
842 result = fd_close_posix(fsp);
843 END_PROFILE(syscall_close);
844 return result;
847 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
848 size_t n, off_t offset)
850 ssize_t result;
852 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
853 START_PROFILE_BYTES(syscall_pread, n);
854 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
855 END_PROFILE_BYTES(syscall_pread);
857 if (result == -1 && errno == ESPIPE) {
858 /* Maintain the fiction that pipes can be seeked (sought?) on. */
859 result = sys_read(fsp_get_io_fd(fsp), data, n);
860 fh_set_pos(fsp->fh, 0);
863 #else /* HAVE_PREAD */
864 errno = ENOSYS;
865 result = -1;
866 #endif /* HAVE_PREAD */
868 return result;
871 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
872 size_t n, off_t offset)
874 ssize_t result;
876 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
877 START_PROFILE_BYTES(syscall_pwrite, n);
878 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
879 END_PROFILE_BYTES(syscall_pwrite);
881 if (result == -1 && errno == ESPIPE) {
882 /* Maintain the fiction that pipes can be sought on. */
883 result = sys_write(fsp_get_io_fd(fsp), data, n);
886 #else /* HAVE_PWRITE */
887 errno = ENOSYS;
888 result = -1;
889 #endif /* HAVE_PWRITE */
891 return result;
894 struct vfswrap_pread_state {
895 ssize_t ret;
896 int fd;
897 void *buf;
898 size_t count;
899 off_t offset;
901 struct vfs_aio_state vfs_aio_state;
902 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
905 static void vfs_pread_do(void *private_data);
906 static void vfs_pread_done(struct tevent_req *subreq);
907 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
909 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
910 TALLOC_CTX *mem_ctx,
911 struct tevent_context *ev,
912 struct files_struct *fsp,
913 void *data,
914 size_t n, off_t offset)
916 struct tevent_req *req, *subreq;
917 struct vfswrap_pread_state *state;
919 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
920 if (req == NULL) {
921 return NULL;
924 state->ret = -1;
925 state->fd = fsp_get_io_fd(fsp);
926 state->buf = data;
927 state->count = n;
928 state->offset = offset;
930 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
931 state->profile_bytes, n);
932 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
934 subreq = pthreadpool_tevent_job_send(
935 state, ev, handle->conn->sconn->pool,
936 vfs_pread_do, state);
937 if (tevent_req_nomem(subreq, req)) {
938 return tevent_req_post(req, ev);
940 tevent_req_set_callback(subreq, vfs_pread_done, req);
942 talloc_set_destructor(state, vfs_pread_state_destructor);
944 return req;
947 static void vfs_pread_do(void *private_data)
949 struct vfswrap_pread_state *state = talloc_get_type_abort(
950 private_data, struct vfswrap_pread_state);
951 struct timespec start_time;
952 struct timespec end_time;
954 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
956 PROFILE_TIMESTAMP(&start_time);
958 state->ret = sys_pread_full(state->fd,
959 state->buf,
960 state->count,
961 state->offset);
963 if (state->ret == -1) {
964 state->vfs_aio_state.error = errno;
967 PROFILE_TIMESTAMP(&end_time);
969 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
971 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
974 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
976 return -1;
979 static void vfs_pread_done(struct tevent_req *subreq)
981 struct tevent_req *req = tevent_req_callback_data(
982 subreq, struct tevent_req);
983 struct vfswrap_pread_state *state = tevent_req_data(
984 req, struct vfswrap_pread_state);
985 int ret;
987 ret = pthreadpool_tevent_job_recv(subreq);
988 TALLOC_FREE(subreq);
989 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
990 talloc_set_destructor(state, NULL);
991 if (ret != 0) {
992 if (ret != EAGAIN) {
993 tevent_req_error(req, ret);
994 return;
997 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
998 * means the lower level pthreadpool failed to create a new
999 * thread. Fallback to sync processing in that case to allow
1000 * some progress for the client.
1002 vfs_pread_do(state);
1005 tevent_req_done(req);
1008 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
1009 struct vfs_aio_state *vfs_aio_state)
1011 struct vfswrap_pread_state *state = tevent_req_data(
1012 req, struct vfswrap_pread_state);
1014 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1015 return -1;
1018 *vfs_aio_state = state->vfs_aio_state;
1019 return state->ret;
1022 struct vfswrap_pwrite_state {
1023 ssize_t ret;
1024 int fd;
1025 const void *buf;
1026 size_t count;
1027 off_t offset;
1029 struct vfs_aio_state vfs_aio_state;
1030 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1033 static void vfs_pwrite_do(void *private_data);
1034 static void vfs_pwrite_done(struct tevent_req *subreq);
1035 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
1037 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
1038 TALLOC_CTX *mem_ctx,
1039 struct tevent_context *ev,
1040 struct files_struct *fsp,
1041 const void *data,
1042 size_t n, off_t offset)
1044 struct tevent_req *req, *subreq;
1045 struct vfswrap_pwrite_state *state;
1047 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1048 if (req == NULL) {
1049 return NULL;
1052 state->ret = -1;
1053 state->fd = fsp_get_io_fd(fsp);
1054 state->buf = data;
1055 state->count = n;
1056 state->offset = offset;
1058 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1059 state->profile_bytes, n);
1060 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1062 subreq = pthreadpool_tevent_job_send(
1063 state, ev, handle->conn->sconn->pool,
1064 vfs_pwrite_do, state);
1065 if (tevent_req_nomem(subreq, req)) {
1066 return tevent_req_post(req, ev);
1068 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1070 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1072 return req;
1075 static void vfs_pwrite_do(void *private_data)
1077 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1078 private_data, struct vfswrap_pwrite_state);
1079 struct timespec start_time;
1080 struct timespec end_time;
1082 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1084 PROFILE_TIMESTAMP(&start_time);
1086 state->ret = sys_pwrite_full(state->fd,
1087 state->buf,
1088 state->count,
1089 state->offset);
1091 if (state->ret == -1) {
1092 state->vfs_aio_state.error = errno;
1095 PROFILE_TIMESTAMP(&end_time);
1097 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1099 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1102 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1104 return -1;
1107 static void vfs_pwrite_done(struct tevent_req *subreq)
1109 struct tevent_req *req = tevent_req_callback_data(
1110 subreq, struct tevent_req);
1111 struct vfswrap_pwrite_state *state = tevent_req_data(
1112 req, struct vfswrap_pwrite_state);
1113 int ret;
1115 ret = pthreadpool_tevent_job_recv(subreq);
1116 TALLOC_FREE(subreq);
1117 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1118 talloc_set_destructor(state, NULL);
1119 if (ret != 0) {
1120 if (ret != EAGAIN) {
1121 tevent_req_error(req, ret);
1122 return;
1125 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1126 * means the lower level pthreadpool failed to create a new
1127 * thread. Fallback to sync processing in that case to allow
1128 * some progress for the client.
1130 vfs_pwrite_do(state);
1133 tevent_req_done(req);
1136 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1137 struct vfs_aio_state *vfs_aio_state)
1139 struct vfswrap_pwrite_state *state = tevent_req_data(
1140 req, struct vfswrap_pwrite_state);
1142 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1143 return -1;
1146 *vfs_aio_state = state->vfs_aio_state;
1147 return state->ret;
1150 struct vfswrap_fsync_state {
1151 ssize_t ret;
1152 int fd;
1154 struct vfs_aio_state vfs_aio_state;
1155 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1158 static void vfs_fsync_do(void *private_data);
1159 static void vfs_fsync_done(struct tevent_req *subreq);
1160 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1162 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1163 TALLOC_CTX *mem_ctx,
1164 struct tevent_context *ev,
1165 struct files_struct *fsp)
1167 struct tevent_req *req, *subreq;
1168 struct vfswrap_fsync_state *state;
1170 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1171 if (req == NULL) {
1172 return NULL;
1175 state->ret = -1;
1176 state->fd = fsp_get_io_fd(fsp);
1178 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1179 state->profile_bytes, 0);
1180 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1182 subreq = pthreadpool_tevent_job_send(
1183 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1184 if (tevent_req_nomem(subreq, req)) {
1185 return tevent_req_post(req, ev);
1187 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1189 talloc_set_destructor(state, vfs_fsync_state_destructor);
1191 return req;
1194 static void vfs_fsync_do(void *private_data)
1196 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1197 private_data, struct vfswrap_fsync_state);
1198 struct timespec start_time;
1199 struct timespec end_time;
1201 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1203 PROFILE_TIMESTAMP(&start_time);
1205 do {
1206 state->ret = fsync(state->fd);
1207 } while ((state->ret == -1) && (errno == EINTR));
1209 if (state->ret == -1) {
1210 state->vfs_aio_state.error = errno;
1213 PROFILE_TIMESTAMP(&end_time);
1215 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1217 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1220 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1222 return -1;
1225 static void vfs_fsync_done(struct tevent_req *subreq)
1227 struct tevent_req *req = tevent_req_callback_data(
1228 subreq, struct tevent_req);
1229 struct vfswrap_fsync_state *state = tevent_req_data(
1230 req, struct vfswrap_fsync_state);
1231 int ret;
1233 ret = pthreadpool_tevent_job_recv(subreq);
1234 TALLOC_FREE(subreq);
1235 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1236 talloc_set_destructor(state, NULL);
1237 if (ret != 0) {
1238 if (ret != EAGAIN) {
1239 tevent_req_error(req, ret);
1240 return;
1243 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1244 * means the lower level pthreadpool failed to create a new
1245 * thread. Fallback to sync processing in that case to allow
1246 * some progress for the client.
1248 vfs_fsync_do(state);
1251 tevent_req_done(req);
1254 static int vfswrap_fsync_recv(struct tevent_req *req,
1255 struct vfs_aio_state *vfs_aio_state)
1257 struct vfswrap_fsync_state *state = tevent_req_data(
1258 req, struct vfswrap_fsync_state);
1260 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1261 return -1;
1264 *vfs_aio_state = state->vfs_aio_state;
1265 return state->ret;
1268 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1270 off_t result = 0;
1272 START_PROFILE(syscall_lseek);
1274 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1276 * We want to maintain the fiction that we can seek
1277 * on a fifo for file system purposes. This allows
1278 * people to set up UNIX fifo's that feed data to Windows
1279 * applications. JRA.
1282 if((result == -1) && (errno == ESPIPE)) {
1283 result = 0;
1284 errno = 0;
1287 END_PROFILE(syscall_lseek);
1288 return result;
1291 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1292 off_t offset, size_t n)
1294 ssize_t result;
1296 START_PROFILE_BYTES(syscall_sendfile, n);
1297 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1298 END_PROFILE_BYTES(syscall_sendfile);
1299 return result;
1302 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1303 int fromfd,
1304 files_struct *tofsp,
1305 off_t offset,
1306 size_t n)
1308 ssize_t result;
1310 START_PROFILE_BYTES(syscall_recvfile, n);
1311 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1312 END_PROFILE_BYTES(syscall_recvfile);
1313 return result;
1316 static int vfswrap_renameat(vfs_handle_struct *handle,
1317 files_struct *srcfsp,
1318 const struct smb_filename *smb_fname_src,
1319 files_struct *dstfsp,
1320 const struct smb_filename *smb_fname_dst)
1322 int result = -1;
1324 START_PROFILE(syscall_renameat);
1326 SMB_ASSERT(!is_named_stream(smb_fname_src));
1327 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1329 result = renameat(fsp_get_pathref_fd(srcfsp),
1330 smb_fname_src->base_name,
1331 fsp_get_pathref_fd(dstfsp),
1332 smb_fname_dst->base_name);
1334 END_PROFILE(syscall_renameat);
1335 return result;
1338 static int vfswrap_stat(vfs_handle_struct *handle,
1339 struct smb_filename *smb_fname)
1341 int result = -1;
1343 START_PROFILE(syscall_stat);
1345 SMB_ASSERT(!is_named_stream(smb_fname));
1347 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1348 lp_fake_directory_create_times(SNUM(handle->conn)));
1350 END_PROFILE(syscall_stat);
1351 return result;
1354 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1356 int result;
1358 START_PROFILE(syscall_fstat);
1359 result = sys_fstat(fsp_get_pathref_fd(fsp),
1360 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1361 END_PROFILE(syscall_fstat);
1362 return result;
1365 static int vfswrap_lstat(vfs_handle_struct *handle,
1366 struct smb_filename *smb_fname)
1368 int result = -1;
1370 START_PROFILE(syscall_lstat);
1372 SMB_ASSERT(!is_named_stream(smb_fname));
1374 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1375 lp_fake_directory_create_times(SNUM(handle->conn)));
1377 END_PROFILE(syscall_lstat);
1378 return result;
1381 static int vfswrap_fstatat(
1382 struct vfs_handle_struct *handle,
1383 const struct files_struct *dirfsp,
1384 const struct smb_filename *smb_fname,
1385 SMB_STRUCT_STAT *sbuf,
1386 int flags)
1388 int result = -1;
1390 START_PROFILE(syscall_fstatat);
1392 SMB_ASSERT(!is_named_stream(smb_fname));
1394 result = sys_fstatat(
1395 fsp_get_pathref_fd(dirfsp),
1396 smb_fname->base_name,
1397 sbuf,
1398 flags,
1399 lp_fake_directory_create_times(SNUM(handle->conn)));
1401 END_PROFILE(syscall_fstatat);
1402 return result;
1405 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1406 const char *name,
1407 enum vfs_translate_direction direction,
1408 TALLOC_CTX *mem_ctx,
1409 char **mapped_name)
1411 return NT_STATUS_NONE_MAPPED;
1415 * Return allocated parent directory and basename of path
1417 * Note: if requesting atname, it is returned as talloc child of the
1418 * parent. Freeing the parent is thus sufficient to free both.
1420 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1421 TALLOC_CTX *mem_ctx,
1422 const struct smb_filename *smb_fname_in,
1423 struct smb_filename **parent_dir_out,
1424 struct smb_filename **atname_out)
1426 TALLOC_CTX *frame = talloc_stackframe();
1427 struct smb_filename *parent = NULL;
1428 struct smb_filename *name = NULL;
1429 char *p = NULL;
1431 parent = cp_smb_filename_nostream(frame, smb_fname_in);
1432 if (parent == NULL) {
1433 TALLOC_FREE(frame);
1434 return NT_STATUS_NO_MEMORY;
1436 SET_STAT_INVALID(parent->st);
1438 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1439 if (p == NULL) {
1440 TALLOC_FREE(parent->base_name);
1441 parent->base_name = talloc_strdup(parent, ".");
1442 if (parent->base_name == NULL) {
1443 TALLOC_FREE(frame);
1444 return NT_STATUS_NO_MEMORY;
1446 p = smb_fname_in->base_name;
1447 } else {
1448 *p = '\0';
1449 p++;
1452 if (atname_out == NULL) {
1453 *parent_dir_out = talloc_move(mem_ctx, &parent);
1454 TALLOC_FREE(frame);
1455 return NT_STATUS_OK;
1458 name = cp_smb_filename(frame, smb_fname_in);
1459 if (name == NULL) {
1460 TALLOC_FREE(frame);
1461 return NT_STATUS_NO_MEMORY;
1463 TALLOC_FREE(name->base_name);
1465 name->base_name = talloc_strdup(name, p);
1466 if (name->base_name == NULL) {
1467 TALLOC_FREE(frame);
1468 return NT_STATUS_NO_MEMORY;
1471 *parent_dir_out = talloc_move(mem_ctx, &parent);
1472 *atname_out = talloc_move(*parent_dir_out, &name);
1473 TALLOC_FREE(frame);
1474 return NT_STATUS_OK;
1478 * Implement the default fsctl operation.
1480 static bool vfswrap_logged_ioctl_message = false;
1482 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1483 struct files_struct *fsp,
1484 TALLOC_CTX *ctx,
1485 uint32_t function,
1486 uint16_t req_flags, /* Needed for UNICODE ... */
1487 const uint8_t *_in_data,
1488 uint32_t in_len,
1489 uint8_t **_out_data,
1490 uint32_t max_out_len,
1491 uint32_t *out_len)
1493 const char *in_data = (const char *)_in_data;
1494 char **out_data = (char **)_out_data;
1495 NTSTATUS status;
1497 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1499 switch (function) {
1500 case FSCTL_SET_SPARSE:
1502 bool set_sparse = true;
1504 if (in_len >= 1 && in_data[0] == 0) {
1505 set_sparse = false;
1508 status = file_set_sparse(handle->conn, fsp, set_sparse);
1510 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1511 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1512 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1513 nt_errstr(status)));
1515 return status;
1518 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1520 unsigned char objid[16];
1521 char *return_data = NULL;
1523 /* This should return the object-id on this file.
1524 * I think I'll make this be the inode+dev. JRA.
1527 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1528 fsp_fnum_dbg(fsp)));
1530 *out_len = MIN(max_out_len, 64);
1532 /* Hmmm, will this cause problems if less data asked for? */
1533 return_data = talloc_array(ctx, char, 64);
1534 if (return_data == NULL) {
1535 return NT_STATUS_NO_MEMORY;
1538 /* For backwards compatibility only store the dev/inode. */
1539 push_file_id_16(return_data, &fsp->file_id);
1540 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1541 push_file_id_16(return_data+32, &fsp->file_id);
1542 memset(return_data+48, 0, 16);
1543 *out_data = return_data;
1544 return NT_STATUS_OK;
1547 case FSCTL_GET_REPARSE_POINT:
1549 status = fsctl_get_reparse_point(
1550 fsp, ctx, out_data, max_out_len, out_len);
1551 return status;
1554 case FSCTL_SET_REPARSE_POINT:
1556 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1557 return status;
1560 case FSCTL_DELETE_REPARSE_POINT:
1562 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1563 return status;
1566 case FSCTL_GET_SHADOW_COPY_DATA:
1569 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1570 * and return their volume names. If max_data_count is 16, then it is just
1571 * asking for the number of volumes and length of the combined names.
1573 * pdata is the data allocated by our caller, but that uses
1574 * total_data_count (which is 0 in our case) rather than max_data_count.
1575 * Allocate the correct amount and return the pointer to let
1576 * it be deallocated when we return.
1578 struct shadow_copy_data *shadow_data = NULL;
1579 bool labels = False;
1580 uint32_t labels_data_count = 0;
1581 uint32_t i;
1582 char *cur_pdata = NULL;
1584 if (max_out_len < 16) {
1585 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1586 max_out_len));
1587 return NT_STATUS_INVALID_PARAMETER;
1590 if (max_out_len > 16) {
1591 labels = True;
1594 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1595 if (shadow_data == NULL) {
1596 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1597 return NT_STATUS_NO_MEMORY;
1601 * Call the VFS routine to actually do the work.
1603 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1604 int log_lev = 0;
1605 if (errno == 0) {
1606 /* broken module didn't set errno on error */
1607 status = NT_STATUS_UNSUCCESSFUL;
1608 } else {
1609 status = map_nt_error_from_unix(errno);
1610 if (NT_STATUS_EQUAL(status,
1611 NT_STATUS_NOT_SUPPORTED)) {
1612 log_lev = 5;
1615 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1616 "connectpath %s, failed - %s.\n",
1617 fsp->conn->connectpath,
1618 nt_errstr(status)));
1619 TALLOC_FREE(shadow_data);
1620 return status;
1623 labels_data_count = (shadow_data->num_volumes * 2 *
1624 sizeof(SHADOW_COPY_LABEL)) + 2;
1626 if (!labels) {
1627 *out_len = 16;
1628 } else {
1629 *out_len = 12 + labels_data_count;
1632 if (max_out_len < *out_len) {
1633 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1634 max_out_len, *out_len));
1635 TALLOC_FREE(shadow_data);
1636 return NT_STATUS_BUFFER_TOO_SMALL;
1639 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1640 if (cur_pdata == NULL) {
1641 TALLOC_FREE(shadow_data);
1642 return NT_STATUS_NO_MEMORY;
1645 *out_data = cur_pdata;
1647 /* num_volumes 4 bytes */
1648 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1650 if (labels) {
1651 /* num_labels 4 bytes */
1652 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1655 /* needed_data_count 4 bytes */
1656 SIVAL(cur_pdata, 8, labels_data_count);
1658 cur_pdata += 12;
1660 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1661 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1662 if (labels && shadow_data->labels) {
1663 for (i=0; i<shadow_data->num_volumes; i++) {
1664 size_t len = 0;
1665 status = srvstr_push(cur_pdata, req_flags,
1666 cur_pdata, shadow_data->labels[i],
1667 2 * sizeof(SHADOW_COPY_LABEL),
1668 STR_UNICODE|STR_TERMINATE, &len);
1669 if (!NT_STATUS_IS_OK(status)) {
1670 TALLOC_FREE(*out_data);
1671 TALLOC_FREE(shadow_data);
1672 return status;
1674 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1675 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1679 TALLOC_FREE(shadow_data);
1681 return NT_STATUS_OK;
1684 case FSCTL_FIND_FILES_BY_SID:
1686 /* pretend this succeeded -
1688 * we have to send back a list with all files owned by this SID
1690 * but I have to check that --metze
1692 ssize_t ret;
1693 struct dom_sid sid;
1694 struct dom_sid_buf buf;
1695 uid_t uid;
1696 size_t sid_len;
1698 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1699 fsp_fnum_dbg(fsp)));
1701 if (in_len < 8) {
1702 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1703 return NT_STATUS_INVALID_PARAMETER;
1706 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1708 /* unknown 4 bytes: this is not the length of the sid :-( */
1709 /*unknown = IVAL(pdata,0);*/
1711 ret = sid_parse(_in_data + 4, sid_len, &sid);
1712 if (ret == -1) {
1713 return NT_STATUS_INVALID_PARAMETER;
1715 DEBUGADD(10, ("for SID: %s\n",
1716 dom_sid_str_buf(&sid, &buf)));
1718 if (!sid_to_uid(&sid, &uid)) {
1719 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1720 dom_sid_str_buf(&sid, &buf),
1721 (unsigned long)sid_len));
1722 uid = (-1);
1725 /* we can take a look at the find source :-)
1727 * find ./ -uid $uid -name '*' is what we need here
1730 * and send 4bytes len and then NULL terminated unicode strings
1731 * for each file
1733 * but I don't know how to deal with the paged results
1734 * (maybe we can hang the result anywhere in the fsp struct)
1736 * but I don't know how to deal with the paged results
1737 * (maybe we can hang the result anywhere in the fsp struct)
1739 * we don't send all files at once
1740 * and at the next we should *not* start from the beginning,
1741 * so we have to cache the result
1743 * --metze
1746 /* this works for now... */
1747 return NT_STATUS_OK;
1750 case FSCTL_QUERY_ALLOCATED_RANGES:
1752 /* FIXME: This is just a dummy reply, telling that all of the
1753 * file is allocated. MKS cp needs that.
1754 * Adding the real allocated ranges via FIEMAP on Linux
1755 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1756 * this FSCTL correct for sparse files.
1758 uint64_t offset, length;
1759 char *out_data_tmp = NULL;
1761 if (in_len != 16) {
1762 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1763 in_len));
1764 return NT_STATUS_INVALID_PARAMETER;
1767 if (max_out_len < 16) {
1768 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1769 max_out_len));
1770 return NT_STATUS_INVALID_PARAMETER;
1773 offset = BVAL(in_data,0);
1774 length = BVAL(in_data,8);
1776 if (offset + length < offset) {
1777 /* No 64-bit integer wrap. */
1778 return NT_STATUS_INVALID_PARAMETER;
1781 /* Shouldn't this be SMB_VFS_STAT ... ? */
1782 status = vfs_stat_fsp(fsp);
1783 if (!NT_STATUS_IS_OK(status)) {
1784 return status;
1787 *out_len = 16;
1788 out_data_tmp = talloc_array(ctx, char, *out_len);
1789 if (out_data_tmp == NULL) {
1790 DEBUG(10, ("unable to allocate memory for response\n"));
1791 return NT_STATUS_NO_MEMORY;
1794 if (offset > fsp->fsp_name->st.st_ex_size ||
1795 fsp->fsp_name->st.st_ex_size == 0 ||
1796 length == 0) {
1797 memset(out_data_tmp, 0, *out_len);
1798 } else {
1799 uint64_t end = offset + length;
1800 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1801 SBVAL(out_data_tmp, 0, 0);
1802 SBVAL(out_data_tmp, 8, end);
1805 *out_data = out_data_tmp;
1807 return NT_STATUS_OK;
1810 case FSCTL_IS_VOLUME_DIRTY:
1812 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1813 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1815 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1816 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1818 return NT_STATUS_INVALID_PARAMETER;
1821 default:
1823 * Only print once ... unfortunately there could be lots of
1824 * different FSCTLs that are called.
1826 if (!vfswrap_logged_ioctl_message) {
1827 vfswrap_logged_ioctl_message = true;
1828 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1829 __func__, function));
1833 return NT_STATUS_NOT_SUPPORTED;
1836 static bool vfswrap_is_offline(struct connection_struct *conn,
1837 const struct smb_filename *fname);
1839 struct vfswrap_get_dos_attributes_state {
1840 struct vfs_aio_state aio_state;
1841 connection_struct *conn;
1842 TALLOC_CTX *mem_ctx;
1843 struct tevent_context *ev;
1844 files_struct *dir_fsp;
1845 struct smb_filename *smb_fname;
1846 uint32_t dosmode;
1847 bool as_root;
1850 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1852 static struct tevent_req *vfswrap_get_dos_attributes_send(
1853 TALLOC_CTX *mem_ctx,
1854 struct tevent_context *ev,
1855 struct vfs_handle_struct *handle,
1856 files_struct *dir_fsp,
1857 struct smb_filename *smb_fname)
1859 struct tevent_req *req = NULL;
1860 struct tevent_req *subreq = NULL;
1861 struct vfswrap_get_dos_attributes_state *state = NULL;
1863 SMB_ASSERT(!is_named_stream(smb_fname));
1865 req = tevent_req_create(mem_ctx, &state,
1866 struct vfswrap_get_dos_attributes_state);
1867 if (req == NULL) {
1868 return NULL;
1871 *state = (struct vfswrap_get_dos_attributes_state) {
1872 .conn = dir_fsp->conn,
1873 .mem_ctx = mem_ctx,
1874 .ev = ev,
1875 .dir_fsp = dir_fsp,
1876 .smb_fname = smb_fname,
1879 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1880 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1881 "\"store dos attributes\" is disabled\n",
1882 dir_fsp->conn->connectpath);
1883 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1884 return tevent_req_post(req, ev);
1887 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1889 dir_fsp,
1890 smb_fname,
1891 SAMBA_XATTR_DOS_ATTRIB,
1892 sizeof(fstring));
1893 if (tevent_req_nomem(subreq, req)) {
1894 return tevent_req_post(req, ev);
1896 tevent_req_set_callback(subreq,
1897 vfswrap_get_dos_attributes_getxattr_done,
1898 req);
1900 return req;
1903 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1905 struct tevent_req *req =
1906 tevent_req_callback_data(subreq,
1907 struct tevent_req);
1908 struct vfswrap_get_dos_attributes_state *state =
1909 tevent_req_data(req,
1910 struct vfswrap_get_dos_attributes_state);
1911 ssize_t xattr_size;
1912 DATA_BLOB blob = {0};
1913 char *path = NULL;
1914 char *tofree = NULL;
1915 char pathbuf[PATH_MAX+1];
1916 ssize_t pathlen;
1917 struct smb_filename smb_fname;
1918 bool offline;
1919 NTSTATUS status;
1921 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1922 &state->aio_state,
1923 state,
1924 &blob.data);
1925 TALLOC_FREE(subreq);
1926 if (xattr_size == -1) {
1927 status = map_nt_error_from_unix(state->aio_state.error);
1929 if (state->as_root) {
1930 tevent_req_nterror(req, status);
1931 return;
1933 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1934 tevent_req_nterror(req, status);
1935 return;
1938 state->as_root = true;
1940 become_root();
1941 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1942 state->ev,
1943 state->dir_fsp,
1944 state->smb_fname,
1945 SAMBA_XATTR_DOS_ATTRIB,
1946 sizeof(fstring));
1947 unbecome_root();
1948 if (tevent_req_nomem(subreq, req)) {
1949 return;
1951 tevent_req_set_callback(subreq,
1952 vfswrap_get_dos_attributes_getxattr_done,
1953 req);
1954 return;
1957 blob.length = xattr_size;
1959 status = parse_dos_attribute_blob(state->smb_fname,
1960 blob,
1961 &state->dosmode);
1962 if (!NT_STATUS_IS_OK(status)) {
1963 tevent_req_nterror(req, status);
1964 return;
1967 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1968 state->smb_fname->base_name,
1969 pathbuf,
1970 sizeof(pathbuf),
1971 &path,
1972 &tofree);
1973 if (pathlen == -1) {
1974 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1975 return;
1978 smb_fname = (struct smb_filename) {
1979 .base_name = path,
1980 .st = state->smb_fname->st,
1981 .flags = state->smb_fname->flags,
1982 .twrp = state->smb_fname->twrp,
1985 offline = vfswrap_is_offline(state->conn, &smb_fname);
1986 if (offline) {
1987 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1989 TALLOC_FREE(tofree);
1991 tevent_req_done(req);
1992 return;
1995 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1996 struct vfs_aio_state *aio_state,
1997 uint32_t *dosmode)
1999 struct vfswrap_get_dos_attributes_state *state =
2000 tevent_req_data(req,
2001 struct vfswrap_get_dos_attributes_state);
2002 NTSTATUS status;
2004 if (tevent_req_is_nterror(req, &status)) {
2005 tevent_req_received(req);
2006 return status;
2009 *aio_state = state->aio_state;
2010 *dosmode = state->dosmode;
2011 tevent_req_received(req);
2012 return NT_STATUS_OK;
2015 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
2016 struct files_struct *fsp,
2017 uint32_t *dosmode)
2019 bool offline;
2021 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2023 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
2024 if (offline) {
2025 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
2028 return fget_ea_dos_attribute(fsp, dosmode);
2031 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
2032 struct files_struct *fsp,
2033 uint32_t dosmode)
2035 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2037 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2040 static struct vfs_offload_ctx *vfswrap_offload_ctx;
2042 struct vfswrap_offload_read_state {
2043 DATA_BLOB token;
2046 static struct tevent_req *vfswrap_offload_read_send(
2047 TALLOC_CTX *mem_ctx,
2048 struct tevent_context *ev,
2049 struct vfs_handle_struct *handle,
2050 struct files_struct *fsp,
2051 uint32_t fsctl,
2052 uint32_t ttl,
2053 off_t offset,
2054 size_t to_copy)
2056 struct tevent_req *req = NULL;
2057 struct vfswrap_offload_read_state *state = NULL;
2058 NTSTATUS status;
2060 req = tevent_req_create(mem_ctx, &state,
2061 struct vfswrap_offload_read_state);
2062 if (req == NULL) {
2063 return NULL;
2066 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2067 &vfswrap_offload_ctx);
2068 if (tevent_req_nterror(req, status)) {
2069 return tevent_req_post(req, ev);
2072 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2073 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2074 return tevent_req_post(req, ev);
2077 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2078 &state->token);
2079 if (tevent_req_nterror(req, status)) {
2080 return tevent_req_post(req, ev);
2083 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2084 &state->token);
2085 if (tevent_req_nterror(req, status)) {
2086 return tevent_req_post(req, ev);
2089 tevent_req_done(req);
2090 return tevent_req_post(req, ev);
2093 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2094 struct vfs_handle_struct *handle,
2095 TALLOC_CTX *mem_ctx,
2096 uint32_t *flags,
2097 uint64_t *xferlen,
2098 DATA_BLOB *token)
2100 struct vfswrap_offload_read_state *state = tevent_req_data(
2101 req, struct vfswrap_offload_read_state);
2102 NTSTATUS status;
2104 if (tevent_req_is_nterror(req, &status)) {
2105 tevent_req_received(req);
2106 return status;
2109 *flags = 0;
2110 *xferlen = 0;
2111 token->length = state->token.length;
2112 token->data = talloc_move(mem_ctx, &state->token.data);
2114 tevent_req_received(req);
2115 return NT_STATUS_OK;
2118 struct vfswrap_offload_write_state {
2119 uint8_t *buf;
2120 bool read_lck_locked;
2121 bool write_lck_locked;
2122 DATA_BLOB *token;
2123 struct tevent_context *src_ev;
2124 struct files_struct *src_fsp;
2125 off_t src_off;
2126 struct tevent_context *dst_ev;
2127 struct files_struct *dst_fsp;
2128 off_t dst_off;
2129 off_t to_copy;
2130 off_t remaining;
2131 off_t copied;
2132 size_t next_io_size;
2135 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2136 enum tevent_req_state req_state)
2138 struct vfswrap_offload_write_state *state = tevent_req_data(
2139 req, struct vfswrap_offload_write_state);
2140 bool ok;
2142 if (state->dst_fsp == NULL) {
2143 return;
2146 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2147 SMB_ASSERT(ok);
2148 state->dst_fsp = NULL;
2151 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2152 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2154 static struct tevent_req *vfswrap_offload_write_send(
2155 struct vfs_handle_struct *handle,
2156 TALLOC_CTX *mem_ctx,
2157 struct tevent_context *ev,
2158 uint32_t fsctl,
2159 DATA_BLOB *token,
2160 off_t transfer_offset,
2161 struct files_struct *dest_fsp,
2162 off_t dest_off,
2163 off_t to_copy)
2165 struct tevent_req *req;
2166 struct vfswrap_offload_write_state *state = NULL;
2167 /* off_t is signed! */
2168 off_t max_offset = INT64_MAX - to_copy;
2169 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2170 files_struct *src_fsp = NULL;
2171 NTSTATUS status;
2172 bool ok;
2174 req = tevent_req_create(mem_ctx, &state,
2175 struct vfswrap_offload_write_state);
2176 if (req == NULL) {
2177 return NULL;
2180 *state = (struct vfswrap_offload_write_state) {
2181 .token = token,
2182 .src_off = transfer_offset,
2183 .dst_ev = ev,
2184 .dst_fsp = dest_fsp,
2185 .dst_off = dest_off,
2186 .to_copy = to_copy,
2187 .remaining = to_copy,
2190 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2192 switch (fsctl) {
2193 case FSCTL_SRV_COPYCHUNK:
2194 case FSCTL_SRV_COPYCHUNK_WRITE:
2195 break;
2197 case FSCTL_OFFLOAD_WRITE:
2198 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2199 return tevent_req_post(req, ev);
2201 case FSCTL_DUP_EXTENTS_TO_FILE:
2202 DBG_DEBUG("COW clones not supported by vfs_default\n");
2203 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2204 return tevent_req_post(req, ev);
2206 default:
2207 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2208 return tevent_req_post(req, ev);
2212 * From here on we assume a copy-chunk fsctl
2215 if (to_copy == 0) {
2216 tevent_req_done(req);
2217 return tevent_req_post(req, ev);
2220 if (state->src_off > max_offset) {
2222 * Protect integer checks below.
2224 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2225 return tevent_req_post(req, ev);
2227 if (state->src_off < 0) {
2229 * Protect integer checks below.
2231 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2232 return tevent_req_post(req, ev);
2234 if (state->dst_off > max_offset) {
2236 * Protect integer checks below.
2238 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2239 return tevent_req_post(req, ev);
2241 if (state->dst_off < 0) {
2243 * Protect integer checks below.
2245 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2246 return tevent_req_post(req, ev);
2249 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2250 token, &src_fsp);
2251 if (tevent_req_nterror(req, status)) {
2252 return tevent_req_post(req, ev);
2255 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2257 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2258 if (!NT_STATUS_IS_OK(status)) {
2259 tevent_req_nterror(req, status);
2260 return tevent_req_post(req, ev);
2263 ok = change_to_user_and_service_by_fsp(src_fsp);
2264 if (!ok) {
2265 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2266 return tevent_req_post(req, ev);
2269 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2270 state->src_fsp = src_fsp;
2272 status = vfs_stat_fsp(src_fsp);
2273 if (tevent_req_nterror(req, status)) {
2274 return tevent_req_post(req, ev);
2277 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2279 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2280 * If the SourceOffset or SourceOffset + Length extends beyond
2281 * the end of file, the server SHOULD<240> treat this as a
2282 * STATUS_END_OF_FILE error.
2283 * ...
2284 * <240> Section 3.3.5.15.6: Windows servers will return
2285 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2287 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2288 return tevent_req_post(req, ev);
2291 status = vfswrap_offload_copy_file_range(req);
2292 if (NT_STATUS_IS_OK(status)) {
2293 tevent_req_done(req);
2294 return tevent_req_post(req, ev);
2296 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2297 tevent_req_nterror(req, status);
2298 return tevent_req_post(req, ev);
2301 state->buf = talloc_array(state, uint8_t, num);
2302 if (tevent_req_nomem(state->buf, req)) {
2303 return tevent_req_post(req, ev);
2306 status = vfswrap_offload_write_loop(req);
2307 if (!NT_STATUS_IS_OK(status)) {
2308 tevent_req_nterror(req, status);
2309 return tevent_req_post(req, ev);
2312 return req;
2315 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2317 struct vfswrap_offload_write_state *state = tevent_req_data(
2318 req, struct vfswrap_offload_write_state);
2319 struct lock_struct lck;
2320 ssize_t nwritten;
2321 NTSTATUS status;
2322 bool same_file;
2323 bool ok;
2324 static bool try_copy_file_range = true;
2326 if (!try_copy_file_range) {
2327 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2330 same_file = file_id_equal(&state->src_fsp->file_id,
2331 &state->dst_fsp->file_id);
2332 if (same_file &&
2333 sys_io_ranges_overlap(state->remaining,
2334 state->src_off,
2335 state->remaining,
2336 state->dst_off))
2338 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2341 if (fsp_is_alternate_stream(state->src_fsp) ||
2342 fsp_is_alternate_stream(state->dst_fsp))
2344 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2347 init_strict_lock_struct(state->src_fsp,
2348 state->src_fsp->op->global->open_persistent_id,
2349 state->src_off,
2350 state->remaining,
2351 READ_LOCK,
2352 lp_posix_cifsu_locktype(state->src_fsp),
2353 &lck);
2355 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2356 state->src_fsp,
2357 &lck);
2358 if (!ok) {
2359 return NT_STATUS_FILE_LOCK_CONFLICT;
2362 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2363 if (!ok) {
2364 return NT_STATUS_INTERNAL_ERROR;
2367 init_strict_lock_struct(state->dst_fsp,
2368 state->dst_fsp->op->global->open_persistent_id,
2369 state->dst_off,
2370 state->remaining,
2371 WRITE_LOCK,
2372 lp_posix_cifsu_locktype(state->dst_fsp),
2373 &lck);
2375 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2376 state->dst_fsp,
2377 &lck);
2378 if (!ok) {
2379 return NT_STATUS_FILE_LOCK_CONFLICT;
2382 while (state->remaining > 0) {
2383 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2384 &state->src_off,
2385 fsp_get_io_fd(state->dst_fsp),
2386 &state->dst_off,
2387 state->remaining,
2389 if (nwritten == -1) {
2390 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2391 "n [%jd] failed: %s\n",
2392 fsp_str_dbg(state->src_fsp),
2393 (intmax_t)state->src_off,
2394 fsp_str_dbg(state->dst_fsp),
2395 (intmax_t)state->dst_off,
2396 (intmax_t)state->remaining,
2397 strerror(errno));
2398 switch (errno) {
2399 case EOPNOTSUPP:
2400 case ENOSYS:
2401 try_copy_file_range = false;
2402 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2403 break;
2404 case EXDEV:
2405 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2406 break;
2407 default:
2408 status = map_nt_error_from_unix(errno);
2409 if (NT_STATUS_EQUAL(
2410 status,
2411 NT_STATUS_MORE_PROCESSING_REQUIRED))
2413 /* Avoid triggering the fallback */
2414 status = NT_STATUS_INTERNAL_ERROR;
2416 break;
2418 return status;
2421 if (state->remaining < nwritten) {
2422 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2423 "n [%jd] remaining [%jd]\n",
2424 fsp_str_dbg(state->src_fsp),
2425 fsp_str_dbg(state->dst_fsp),
2426 (intmax_t)nwritten,
2427 (intmax_t)state->remaining);
2428 return NT_STATUS_INTERNAL_ERROR;
2431 if (nwritten == 0) {
2432 break;
2434 state->copied += nwritten;
2435 state->remaining -= nwritten;
2439 * Tell the req cleanup function there's no need to call
2440 * change_to_user_and_service_by_fsp() on the dst handle.
2442 state->dst_fsp = NULL;
2443 return NT_STATUS_OK;
2446 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2448 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2450 struct vfswrap_offload_write_state *state = tevent_req_data(
2451 req, struct vfswrap_offload_write_state);
2452 struct tevent_req *subreq = NULL;
2453 struct lock_struct read_lck;
2454 bool ok;
2457 * This is called under the context of state->src_fsp.
2460 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2462 init_strict_lock_struct(state->src_fsp,
2463 state->src_fsp->op->global->open_persistent_id,
2464 state->src_off,
2465 state->next_io_size,
2466 READ_LOCK,
2467 lp_posix_cifsu_locktype(state->src_fsp),
2468 &read_lck);
2470 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2471 state->src_fsp,
2472 &read_lck);
2473 if (!ok) {
2474 return NT_STATUS_FILE_LOCK_CONFLICT;
2477 subreq = SMB_VFS_PREAD_SEND(state,
2478 state->src_ev,
2479 state->src_fsp,
2480 state->buf,
2481 state->next_io_size,
2482 state->src_off);
2483 if (subreq == NULL) {
2484 return NT_STATUS_NO_MEMORY;
2486 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2488 return NT_STATUS_OK;
2491 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2493 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2495 struct tevent_req *req = tevent_req_callback_data(
2496 subreq, struct tevent_req);
2497 struct vfswrap_offload_write_state *state = tevent_req_data(
2498 req, struct vfswrap_offload_write_state);
2499 struct vfs_aio_state aio_state;
2500 struct lock_struct write_lck;
2501 ssize_t nread;
2502 bool ok;
2504 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2505 TALLOC_FREE(subreq);
2506 if (nread == -1) {
2507 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2508 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2509 return;
2511 if (nread != state->next_io_size) {
2512 DBG_ERR("Short read, only %zd of %zu\n",
2513 nread, state->next_io_size);
2514 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2515 return;
2518 state->src_off += nread;
2520 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2521 if (!ok) {
2522 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2523 return;
2526 init_strict_lock_struct(state->dst_fsp,
2527 state->dst_fsp->op->global->open_persistent_id,
2528 state->dst_off,
2529 state->next_io_size,
2530 WRITE_LOCK,
2531 lp_posix_cifsu_locktype(state->dst_fsp),
2532 &write_lck);
2534 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2535 state->dst_fsp,
2536 &write_lck);
2537 if (!ok) {
2538 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2539 return;
2542 subreq = SMB_VFS_PWRITE_SEND(state,
2543 state->dst_ev,
2544 state->dst_fsp,
2545 state->buf,
2546 state->next_io_size,
2547 state->dst_off);
2548 if (subreq == NULL) {
2549 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2550 return;
2552 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2555 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2557 struct tevent_req *req = tevent_req_callback_data(
2558 subreq, struct tevent_req);
2559 struct vfswrap_offload_write_state *state = tevent_req_data(
2560 req, struct vfswrap_offload_write_state);
2561 struct vfs_aio_state aio_state;
2562 ssize_t nwritten;
2563 NTSTATUS status;
2564 bool ok;
2566 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2567 TALLOC_FREE(subreq);
2568 if (nwritten == -1) {
2569 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2570 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2571 return;
2573 if (nwritten != state->next_io_size) {
2574 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2575 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2576 return;
2579 state->dst_off += nwritten;
2581 if (state->remaining < nwritten) {
2582 /* Paranoia check */
2583 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2584 return;
2586 state->copied += nwritten;
2587 state->remaining -= nwritten;
2588 if (state->remaining == 0) {
2589 tevent_req_done(req);
2590 return;
2593 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2594 if (!ok) {
2595 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2596 return;
2599 status = vfswrap_offload_write_loop(req);
2600 if (!NT_STATUS_IS_OK(status)) {
2601 tevent_req_nterror(req, status);
2602 return;
2605 return;
2608 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2609 struct tevent_req *req,
2610 off_t *copied)
2612 struct vfswrap_offload_write_state *state = tevent_req_data(
2613 req, struct vfswrap_offload_write_state);
2614 NTSTATUS status;
2616 if (tevent_req_is_nterror(req, &status)) {
2617 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2618 *copied = 0;
2619 tevent_req_received(req);
2620 return status;
2623 *copied = state->copied;
2624 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2625 tevent_req_received(req);
2627 return NT_STATUS_OK;
2630 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2631 TALLOC_CTX *mem_ctx,
2632 struct files_struct *fsp,
2633 uint16_t *_compression_fmt)
2635 return NT_STATUS_INVALID_DEVICE_REQUEST;
2638 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2639 TALLOC_CTX *mem_ctx,
2640 struct files_struct *fsp,
2641 uint16_t compression_fmt)
2643 return NT_STATUS_INVALID_DEVICE_REQUEST;
2646 /********************************************************************
2647 Given a stat buffer return the allocated size on disk, taking into
2648 account sparse files.
2649 ********************************************************************/
2650 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2651 struct files_struct *fsp,
2652 const SMB_STRUCT_STAT *sbuf)
2654 uint64_t result;
2656 START_PROFILE(syscall_get_alloc_size);
2658 if(S_ISDIR(sbuf->st_ex_mode)) {
2659 result = 0;
2660 goto out;
2663 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2664 /* The type of st_blocksize is blkcnt_t which *MUST* be
2665 signed (according to POSIX) and can be less than 64-bits.
2666 Ensure when we're converting to 64 bits wide we don't
2667 sign extend. */
2668 #if defined(SIZEOF_BLKCNT_T_8)
2669 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2670 #elif defined(SIZEOF_BLKCNT_T_4)
2672 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2673 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2675 #else
2676 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2677 #endif
2678 if (result == 0) {
2680 * Some file systems do not allocate a block for very
2681 * small files. But for non-empty file should report a
2682 * positive size.
2685 uint64_t filesize = get_file_size_stat(sbuf);
2686 if (filesize > 0) {
2687 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2690 #else
2691 result = get_file_size_stat(sbuf);
2692 #endif
2694 if (fsp && fsp->initial_allocation_size)
2695 result = MAX(result,fsp->initial_allocation_size);
2697 result = smb_roundup(handle->conn, result);
2699 out:
2700 END_PROFILE(syscall_get_alloc_size);
2701 return result;
2704 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2705 struct files_struct *dirfsp,
2706 const struct smb_filename *smb_fname,
2707 int flags)
2709 int result = -1;
2711 START_PROFILE(syscall_unlinkat);
2713 SMB_ASSERT(!is_named_stream(smb_fname));
2715 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2716 smb_fname->base_name,
2717 flags);
2719 END_PROFILE(syscall_unlinkat);
2720 return result;
2723 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2725 int result;
2727 START_PROFILE(syscall_fchmod);
2729 if (!fsp->fsp_flags.is_pathref) {
2730 result = fchmod(fsp_get_io_fd(fsp), mode);
2731 END_PROFILE(syscall_fchmod);
2732 return result;
2735 if (fsp->fsp_flags.have_proc_fds) {
2736 int fd = fsp_get_pathref_fd(fsp);
2737 const char *p = NULL;
2738 char buf[PATH_MAX];
2740 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2741 if (p != NULL) {
2742 result = chmod(p, mode);
2743 } else {
2744 result = -1;
2746 END_PROFILE(syscall_fchmod);
2747 return result;
2751 * This is no longer a handle based call.
2753 result = chmod(fsp->fsp_name->base_name, mode);
2755 END_PROFILE(syscall_fchmod);
2756 return result;
2759 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2761 #ifdef HAVE_FCHOWN
2762 int result;
2764 START_PROFILE(syscall_fchown);
2765 if (!fsp->fsp_flags.is_pathref) {
2766 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2767 END_PROFILE(syscall_fchown);
2768 return result;
2771 if (fsp->fsp_flags.have_proc_fds) {
2772 int fd = fsp_get_pathref_fd(fsp);
2773 const char *p = NULL;
2774 char buf[PATH_MAX];
2776 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2777 if (p != NULL) {
2778 result = chown(p, uid, gid);
2779 } else {
2780 result = -1;
2782 END_PROFILE(syscall_fchown);
2783 return result;
2787 * This is no longer a handle based call.
2789 result = chown(fsp->fsp_name->base_name, uid, gid);
2790 END_PROFILE(syscall_fchown);
2791 return result;
2792 #else
2793 errno = ENOSYS;
2794 return -1;
2795 #endif
2798 static int vfswrap_lchown(vfs_handle_struct *handle,
2799 const struct smb_filename *smb_fname,
2800 uid_t uid,
2801 gid_t gid)
2803 int result;
2805 START_PROFILE(syscall_lchown);
2806 result = lchown(smb_fname->base_name, uid, gid);
2807 END_PROFILE(syscall_lchown);
2808 return result;
2811 static int vfswrap_chdir(vfs_handle_struct *handle,
2812 const struct smb_filename *smb_fname)
2814 int result;
2816 START_PROFILE(syscall_chdir);
2817 result = chdir(smb_fname->base_name);
2818 END_PROFILE(syscall_chdir);
2819 return result;
2822 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2823 TALLOC_CTX *ctx)
2825 char *result;
2826 struct smb_filename *smb_fname = NULL;
2828 START_PROFILE(syscall_getwd);
2829 result = sys_getwd();
2830 END_PROFILE(syscall_getwd);
2832 if (result == NULL) {
2833 return NULL;
2835 smb_fname = synthetic_smb_fname(ctx,
2836 result,
2837 NULL,
2838 NULL,
2842 * sys_getwd() *always* returns malloced memory.
2843 * We must free here to avoid leaks:
2844 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2846 SAFE_FREE(result);
2847 return smb_fname;
2850 /*********************************************************************
2851 nsec timestamp resolution call. Convert down to whatever the underlying
2852 system will support.
2853 **********************************************************************/
2855 static int vfswrap_fntimes(vfs_handle_struct *handle,
2856 files_struct *fsp,
2857 struct smb_file_time *ft)
2859 int result = -1;
2860 struct timespec ts[2];
2861 struct timespec *times = NULL;
2863 START_PROFILE(syscall_fntimes);
2865 if (fsp_is_alternate_stream(fsp)) {
2866 errno = ENOENT;
2867 goto out;
2870 if (ft != NULL) {
2871 if (is_omit_timespec(&ft->atime)) {
2872 ft->atime = fsp->fsp_name->st.st_ex_atime;
2875 if (is_omit_timespec(&ft->mtime)) {
2876 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2879 if (!is_omit_timespec(&ft->create_time)) {
2880 set_create_timespec_ea(fsp,
2881 ft->create_time);
2884 if ((timespec_compare(&ft->atime,
2885 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2886 (timespec_compare(&ft->mtime,
2887 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2888 result = 0;
2889 goto out;
2892 ts[0] = ft->atime;
2893 ts[1] = ft->mtime;
2894 times = ts;
2895 } else {
2896 times = NULL;
2899 if (!fsp->fsp_flags.is_pathref) {
2900 result = futimens(fsp_get_io_fd(fsp), times);
2901 goto out;
2904 if (fsp->fsp_flags.have_proc_fds) {
2905 int fd = fsp_get_pathref_fd(fsp);
2906 const char *p = NULL;
2907 char buf[PATH_MAX];
2909 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2910 if (p != NULL) {
2912 * The dirfd argument of utimensat is ignored when
2913 * pathname is an absolute path
2915 result = utimensat(AT_FDCWD, p, times, 0);
2916 } else {
2917 result = -1;
2920 goto out;
2924 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2925 * path translation mechanism. Fallback to path based call.
2927 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2929 out:
2930 END_PROFILE(syscall_fntimes);
2932 return result;
2936 /*********************************************************************
2937 A version of ftruncate that will write the space on disk if strict
2938 allocate is set.
2939 **********************************************************************/
2941 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2943 off_t space_to_write;
2944 uint64_t space_avail;
2945 uint64_t bsize,dfree,dsize;
2946 int ret;
2947 NTSTATUS status;
2948 SMB_STRUCT_STAT *pst;
2949 bool ok;
2951 ok = vfs_valid_pwrite_range(len, 0);
2952 if (!ok) {
2953 errno = EINVAL;
2954 return -1;
2957 status = vfs_stat_fsp(fsp);
2958 if (!NT_STATUS_IS_OK(status)) {
2959 return -1;
2961 pst = &fsp->fsp_name->st;
2963 #ifdef S_ISFIFO
2964 if (S_ISFIFO(pst->st_ex_mode))
2965 return 0;
2966 #endif
2968 if (pst->st_ex_size == len)
2969 return 0;
2971 /* Shrink - just ftruncate. */
2972 if (pst->st_ex_size > len)
2973 return ftruncate(fsp_get_io_fd(fsp), len);
2975 space_to_write = len - pst->st_ex_size;
2977 /* for allocation try fallocate first. This can fail on some
2978 platforms e.g. when the filesystem doesn't support it and no
2979 emulation is being done by the libc (like on AIX with JFS1). In that
2980 case we do our own emulation. fallocate implementations can
2981 return ENOTSUP or EINVAL in cases like that. */
2982 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2983 if (ret == -1 && errno == ENOSPC) {
2984 return -1;
2986 if (ret == 0) {
2987 return 0;
2989 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2990 "error %d. Falling back to slow manual allocation\n", errno));
2992 /* available disk space is enough or not? */
2993 space_avail =
2994 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2995 /* space_avail is 1k blocks */
2996 if (space_avail == (uint64_t)-1 ||
2997 ((uint64_t)space_to_write/1024 > space_avail) ) {
2998 errno = ENOSPC;
2999 return -1;
3002 /* Write out the real space on disk. */
3003 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
3004 if (ret != 0) {
3005 return -1;
3008 return 0;
3011 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
3013 int result = -1;
3014 SMB_STRUCT_STAT *pst;
3015 NTSTATUS status;
3016 char c = 0;
3018 START_PROFILE(syscall_ftruncate);
3020 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
3021 result = strict_allocate_ftruncate(handle, fsp, len);
3022 END_PROFILE(syscall_ftruncate);
3023 return result;
3026 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
3027 ftruncate if the system supports it. Then I discovered that
3028 you can have some filesystems that support ftruncate
3029 expansion and some that don't! On Linux fat can't do
3030 ftruncate extend but ext2 can. */
3032 result = ftruncate(fsp_get_io_fd(fsp), len);
3034 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
3035 extend a file with ftruncate. Provide alternate implementation
3036 for this */
3038 /* Do an fstat to see if the file is longer than the requested
3039 size in which case the ftruncate above should have
3040 succeeded or shorter, in which case seek to len - 1 and
3041 write 1 byte of zero */
3042 status = vfs_stat_fsp(fsp);
3043 if (!NT_STATUS_IS_OK(status)) {
3044 goto done;
3047 /* We need to update the files_struct after successful ftruncate */
3048 if (result == 0) {
3049 goto done;
3052 pst = &fsp->fsp_name->st;
3054 #ifdef S_ISFIFO
3055 if (S_ISFIFO(pst->st_ex_mode)) {
3056 result = 0;
3057 goto done;
3059 #endif
3061 if (pst->st_ex_size == len) {
3062 result = 0;
3063 goto done;
3066 if (pst->st_ex_size > len) {
3067 /* the ftruncate should have worked */
3068 goto done;
3071 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3072 goto done;
3075 result = 0;
3077 done:
3079 END_PROFILE(syscall_ftruncate);
3080 return result;
3083 static int vfswrap_fallocate(vfs_handle_struct *handle,
3084 files_struct *fsp,
3085 uint32_t mode,
3086 off_t offset,
3087 off_t len)
3089 int result;
3091 START_PROFILE(syscall_fallocate);
3092 if (mode == 0) {
3093 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3095 * posix_fallocate returns 0 on success, errno on error
3096 * and doesn't set errno. Make it behave like fallocate()
3097 * which returns -1, and sets errno on failure.
3099 if (result != 0) {
3100 errno = result;
3101 result = -1;
3103 } else {
3104 /* sys_fallocate handles filtering of unsupported mode flags */
3105 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3107 END_PROFILE(syscall_fallocate);
3108 return result;
3111 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3113 bool result;
3115 START_PROFILE(syscall_fcntl_lock);
3117 if (fsp->fsp_flags.use_ofd_locks) {
3118 op = map_process_lock_to_ofd_lock(op);
3121 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3122 END_PROFILE(syscall_fcntl_lock);
3123 return result;
3126 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3127 files_struct *fsp,
3128 uint32_t share_access,
3129 uint32_t access_mask)
3131 errno = ENOTSUP;
3132 return -1;
3135 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3136 va_list cmd_arg)
3138 void *argp;
3139 va_list dup_cmd_arg;
3140 int result;
3141 int val;
3143 START_PROFILE(syscall_fcntl);
3145 va_copy(dup_cmd_arg, cmd_arg);
3147 switch(cmd) {
3148 case F_SETLK:
3149 case F_SETLKW:
3150 case F_GETLK:
3151 #if defined(HAVE_OFD_LOCKS)
3152 case F_OFD_SETLK:
3153 case F_OFD_SETLKW:
3154 case F_OFD_GETLK:
3155 #endif
3156 #if defined(HAVE_F_OWNER_EX)
3157 case F_GETOWN_EX:
3158 case F_SETOWN_EX:
3159 #endif
3160 #if defined(HAVE_RW_HINTS)
3161 case F_GET_RW_HINT:
3162 case F_SET_RW_HINT:
3163 case F_GET_FILE_RW_HINT:
3164 case F_SET_FILE_RW_HINT:
3165 #endif
3166 argp = va_arg(dup_cmd_arg, void *);
3167 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3168 break;
3169 default:
3170 val = va_arg(dup_cmd_arg, int);
3171 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3174 va_end(dup_cmd_arg);
3176 END_PROFILE(syscall_fcntl);
3177 return result;
3180 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3182 bool result;
3183 int op = F_GETLK;
3185 START_PROFILE(syscall_fcntl_getlock);
3187 if (fsp->fsp_flags.use_ofd_locks) {
3188 op = map_process_lock_to_ofd_lock(op);
3191 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3192 END_PROFILE(syscall_fcntl_getlock);
3193 return result;
3196 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3197 int leasetype)
3199 int result = -1;
3201 START_PROFILE(syscall_linux_setlease);
3203 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3205 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3206 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3207 #else
3208 errno = ENOSYS;
3209 #endif
3210 END_PROFILE(syscall_linux_setlease);
3211 return result;
3214 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3215 const struct smb_filename *link_target,
3216 struct files_struct *dirfsp,
3217 const struct smb_filename *new_smb_fname)
3219 int result;
3221 START_PROFILE(syscall_symlinkat);
3223 SMB_ASSERT(!is_named_stream(new_smb_fname));
3225 result = symlinkat(link_target->base_name,
3226 fsp_get_pathref_fd(dirfsp),
3227 new_smb_fname->base_name);
3228 END_PROFILE(syscall_symlinkat);
3229 return result;
3232 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3233 const struct files_struct *dirfsp,
3234 const struct smb_filename *smb_fname,
3235 char *buf,
3236 size_t bufsiz)
3238 int result;
3240 START_PROFILE(syscall_readlinkat);
3242 SMB_ASSERT(!is_named_stream(smb_fname));
3244 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3245 smb_fname->base_name,
3246 buf,
3247 bufsiz);
3249 END_PROFILE(syscall_readlinkat);
3250 return result;
3253 static int vfswrap_linkat(vfs_handle_struct *handle,
3254 files_struct *srcfsp,
3255 const struct smb_filename *old_smb_fname,
3256 files_struct *dstfsp,
3257 const struct smb_filename *new_smb_fname,
3258 int flags)
3260 int result;
3262 START_PROFILE(syscall_linkat);
3264 SMB_ASSERT(!is_named_stream(old_smb_fname));
3265 SMB_ASSERT(!is_named_stream(new_smb_fname));
3267 result = linkat(fsp_get_pathref_fd(srcfsp),
3268 old_smb_fname->base_name,
3269 fsp_get_pathref_fd(dstfsp),
3270 new_smb_fname->base_name,
3271 flags);
3273 END_PROFILE(syscall_linkat);
3274 return result;
3277 static int vfswrap_mknodat(vfs_handle_struct *handle,
3278 files_struct *dirfsp,
3279 const struct smb_filename *smb_fname,
3280 mode_t mode,
3281 SMB_DEV_T dev)
3283 int result;
3285 START_PROFILE(syscall_mknodat);
3287 SMB_ASSERT(!is_named_stream(smb_fname));
3289 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3290 smb_fname->base_name,
3291 mode,
3292 dev);
3294 END_PROFILE(syscall_mknodat);
3295 return result;
3298 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3299 TALLOC_CTX *ctx,
3300 const struct smb_filename *smb_fname)
3302 char *result;
3303 struct smb_filename *result_fname = NULL;
3305 START_PROFILE(syscall_realpath);
3306 result = sys_realpath(smb_fname->base_name);
3307 END_PROFILE(syscall_realpath);
3308 if (result) {
3309 result_fname = synthetic_smb_fname(ctx,
3310 result,
3311 NULL,
3312 NULL,
3315 SAFE_FREE(result);
3317 return result_fname;
3320 static int vfswrap_fchflags(vfs_handle_struct *handle,
3321 struct files_struct *fsp,
3322 unsigned int flags)
3324 #ifdef HAVE_FCHFLAGS
3325 int fd = fsp_get_pathref_fd(fsp);
3327 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3329 if (!fsp->fsp_flags.is_pathref) {
3330 return fchflags(fd, flags);
3333 if (fsp->fsp_flags.have_proc_fds) {
3334 const char *p = NULL;
3335 char buf[PATH_MAX];
3337 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3338 if (p == NULL) {
3339 return -1;
3342 return chflags(p, flags);
3346 * This is no longer a handle based call.
3348 return chflags(fsp->fsp_name->base_name, flags);
3349 #else
3350 errno = ENOSYS;
3351 return -1;
3352 #endif
3355 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3356 const SMB_STRUCT_STAT *sbuf)
3358 struct file_id key;
3360 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3361 * blob */
3362 ZERO_STRUCT(key);
3364 key.devid = sbuf->st_ex_dev;
3365 key.inode = sbuf->st_ex_ino;
3366 /* key.extid is unused by default. */
3368 return key;
3371 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3372 const SMB_STRUCT_STAT *psbuf)
3374 uint64_t file_id;
3376 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3377 return (uint64_t)psbuf->st_ex_ino;
3380 /* FileIDLow */
3381 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3383 /* FileIDHigh */
3384 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3386 return file_id;
3389 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3390 struct files_struct *fsp,
3391 TALLOC_CTX *mem_ctx,
3392 unsigned int *pnum_streams,
3393 struct stream_struct **pstreams)
3395 struct stream_struct *tmp_streams = NULL;
3396 unsigned int num_streams = *pnum_streams;
3397 struct stream_struct *streams = *pstreams;
3398 NTSTATUS status;
3400 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3402 if (fsp->fsp_flags.is_directory) {
3404 * No default streams on directories
3406 goto done;
3408 status = vfs_stat_fsp(fsp);
3409 if (!NT_STATUS_IS_OK(status)) {
3410 return status;
3413 if (num_streams + 1 < 1) {
3414 /* Integer wrap. */
3415 return NT_STATUS_INVALID_PARAMETER;
3418 tmp_streams = talloc_realloc(mem_ctx,
3419 streams,
3420 struct stream_struct,
3421 num_streams + 1);
3422 if (tmp_streams == NULL) {
3423 return NT_STATUS_NO_MEMORY;
3425 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3426 if (tmp_streams[num_streams].name == NULL) {
3427 return NT_STATUS_NO_MEMORY;
3429 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3430 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3431 handle->conn,
3432 fsp,
3433 &fsp->fsp_name->st);
3434 num_streams += 1;
3436 *pnum_streams = num_streams;
3437 *pstreams = tmp_streams;
3438 done:
3439 return NT_STATUS_OK;
3442 static NTSTATUS vfswrap_get_real_filename_at(
3443 struct vfs_handle_struct *handle,
3444 struct files_struct *dirfsp,
3445 const char *name,
3446 TALLOC_CTX *mem_ctx,
3447 char **found_name)
3450 * Don't fall back to get_real_filename so callers can differentiate
3451 * between a full directory scan and an actual case-insensitive stat.
3453 return NT_STATUS_NOT_SUPPORTED;
3456 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3457 const struct smb_filename *smb_fname)
3459 return handle->conn->connectpath;
3462 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3463 struct byte_range_lock *br_lck,
3464 struct lock_struct *plock)
3466 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3468 /* Note: blr is not used in the default implementation. */
3469 return brl_lock_windows_default(br_lck, plock);
3472 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3473 struct byte_range_lock *br_lck,
3474 const struct lock_struct *plock)
3476 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3478 return brl_unlock_windows_default(br_lck, plock);
3481 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3482 files_struct *fsp,
3483 struct lock_struct *plock)
3485 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3486 plock->lock_type == WRITE_LOCK);
3488 return strict_lock_check_default(fsp, plock);
3491 /* NT ACL operations. */
3493 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3494 files_struct *fsp,
3495 uint32_t security_info,
3496 TALLOC_CTX *mem_ctx,
3497 struct security_descriptor **ppdesc)
3499 NTSTATUS result;
3501 START_PROFILE(fget_nt_acl);
3503 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3505 result = posix_fget_nt_acl(fsp, security_info,
3506 mem_ctx, ppdesc);
3507 END_PROFILE(fget_nt_acl);
3508 return result;
3511 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3513 NTSTATUS result;
3515 START_PROFILE(fset_nt_acl);
3517 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3519 result = set_nt_acl(fsp, security_info_sent, psd);
3520 END_PROFILE(fset_nt_acl);
3521 return result;
3524 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3525 struct smb_filename *file,
3526 struct security_acl *sacl,
3527 uint32_t access_requested,
3528 uint32_t access_denied)
3530 return NT_STATUS_OK; /* Nothing to do here ... */
3533 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3534 files_struct *fsp,
3535 SMB_ACL_TYPE_T type,
3536 TALLOC_CTX *mem_ctx)
3538 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3540 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3543 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3544 files_struct *fsp,
3545 SMB_ACL_TYPE_T type,
3546 SMB_ACL_T theacl)
3548 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3550 return sys_acl_set_fd(handle, fsp, type, theacl);
3553 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3554 files_struct *fsp)
3556 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3558 return sys_acl_delete_def_fd(handle, fsp);
3561 /****************************************************************
3562 Extended attribute operations.
3563 *****************************************************************/
3565 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3566 struct files_struct *fsp,
3567 const char *name,
3568 void *value,
3569 size_t size)
3571 int fd = fsp_get_pathref_fd(fsp);
3573 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3575 if (!fsp->fsp_flags.is_pathref) {
3576 return fgetxattr(fd, name, value, size);
3579 if (fsp->fsp_flags.have_proc_fds) {
3580 const char *p = NULL;
3581 char buf[PATH_MAX];
3583 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3584 if (p == NULL) {
3585 return -1;
3588 return getxattr(p, name, value, size);
3592 * This is no longer a handle based call.
3594 return getxattr(fsp->fsp_name->base_name, name, value, size);
3597 struct vfswrap_getxattrat_state {
3598 struct tevent_context *ev;
3599 struct vfs_handle_struct *handle;
3600 files_struct *dir_fsp;
3601 const struct smb_filename *smb_fname;
3604 * The following variables are talloced off "state" which is protected
3605 * by a destructor and thus are guaranteed to be safe to be used in the
3606 * job function in the worker thread.
3608 char *name;
3609 const char *xattr_name;
3610 uint8_t *xattr_value;
3611 struct security_unix_token *token;
3613 ssize_t xattr_size;
3614 struct vfs_aio_state vfs_aio_state;
3615 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3618 static int vfswrap_getxattrat_state_destructor(
3619 struct vfswrap_getxattrat_state *state)
3621 return -1;
3624 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3625 static void vfswrap_getxattrat_do_async(void *private_data);
3626 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3628 static struct tevent_req *vfswrap_getxattrat_send(
3629 TALLOC_CTX *mem_ctx,
3630 struct tevent_context *ev,
3631 struct vfs_handle_struct *handle,
3632 files_struct *dir_fsp,
3633 const struct smb_filename *smb_fname,
3634 const char *xattr_name,
3635 size_t alloc_hint)
3637 struct tevent_req *req = NULL;
3638 struct tevent_req *subreq = NULL;
3639 struct vfswrap_getxattrat_state *state = NULL;
3640 size_t max_threads = 0;
3641 bool have_per_thread_cwd = false;
3642 bool have_per_thread_creds = false;
3643 bool do_async = false;
3645 SMB_ASSERT(!is_named_stream(smb_fname));
3647 req = tevent_req_create(mem_ctx, &state,
3648 struct vfswrap_getxattrat_state);
3649 if (req == NULL) {
3650 return NULL;
3652 *state = (struct vfswrap_getxattrat_state) {
3653 .ev = ev,
3654 .handle = handle,
3655 .dir_fsp = dir_fsp,
3656 .smb_fname = smb_fname,
3659 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3660 if (max_threads >= 1) {
3662 * We need a non sync threadpool!
3664 have_per_thread_cwd = per_thread_cwd_supported();
3666 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3667 have_per_thread_creds = true;
3668 #endif
3669 if (have_per_thread_cwd && have_per_thread_creds) {
3670 do_async = true;
3673 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3674 state->profile_bytes, 0);
3676 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3677 DBG_ERR("Need a valid directory fd\n");
3678 tevent_req_error(req, EINVAL);
3679 return tevent_req_post(req, ev);
3682 if (alloc_hint > 0) {
3683 state->xattr_value = talloc_zero_array(state,
3684 uint8_t,
3685 alloc_hint);
3686 if (tevent_req_nomem(state->xattr_value, req)) {
3687 return tevent_req_post(req, ev);
3691 if (!do_async) {
3692 vfswrap_getxattrat_do_sync(req);
3693 return tevent_req_post(req, ev);
3697 * Now allocate all parameters from a memory context that won't go away
3698 * no matter what. These paremeters will get used in threads and we
3699 * can't reliably cancel threads, so all buffers passed to the threads
3700 * must not be freed before all referencing threads terminate.
3703 state->name = talloc_strdup(state, smb_fname->base_name);
3704 if (tevent_req_nomem(state->name, req)) {
3705 return tevent_req_post(req, ev);
3708 state->xattr_name = talloc_strdup(state, xattr_name);
3709 if (tevent_req_nomem(state->xattr_name, req)) {
3710 return tevent_req_post(req, ev);
3714 * This is a hot codepath so at first glance one might think we should
3715 * somehow optimize away the token allocation and do a
3716 * talloc_reference() or similar black magic instead. But due to the
3717 * talloc_stackframe pool per SMB2 request this should be a simple copy
3718 * without a malloc in most cases.
3720 if (geteuid() == sec_initial_uid()) {
3721 state->token = root_unix_token(state);
3722 } else {
3723 state->token = copy_unix_token(
3724 state,
3725 dir_fsp->conn->session_info->unix_token);
3727 if (tevent_req_nomem(state->token, req)) {
3728 return tevent_req_post(req, ev);
3731 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3733 subreq = pthreadpool_tevent_job_send(
3734 state,
3736 dir_fsp->conn->sconn->pool,
3737 vfswrap_getxattrat_do_async,
3738 state);
3739 if (tevent_req_nomem(subreq, req)) {
3740 return tevent_req_post(req, ev);
3742 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3744 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3746 return req;
3749 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3751 struct vfswrap_getxattrat_state *state = tevent_req_data(
3752 req, struct vfswrap_getxattrat_state);
3754 state->xattr_size = vfswrap_fgetxattr(state->handle,
3755 state->smb_fname->fsp,
3756 state->xattr_name,
3757 state->xattr_value,
3758 talloc_array_length(state->xattr_value));
3759 if (state->xattr_size == -1) {
3760 tevent_req_error(req, errno);
3761 return;
3764 tevent_req_done(req);
3765 return;
3768 static void vfswrap_getxattrat_do_async(void *private_data)
3770 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3771 private_data, struct vfswrap_getxattrat_state);
3772 struct timespec start_time;
3773 struct timespec end_time;
3774 int ret;
3776 PROFILE_TIMESTAMP(&start_time);
3777 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3780 * Here we simulate a getxattrat()
3781 * call using fchdir();getxattr()
3784 per_thread_cwd_activate();
3786 /* Become the correct credential on this thread. */
3787 ret = set_thread_credentials(state->token->uid,
3788 state->token->gid,
3789 (size_t)state->token->ngroups,
3790 state->token->groups);
3791 if (ret != 0) {
3792 state->xattr_size = -1;
3793 state->vfs_aio_state.error = errno;
3794 goto end_profile;
3797 state->xattr_size = vfswrap_fgetxattr(state->handle,
3798 state->smb_fname->fsp,
3799 state->xattr_name,
3800 state->xattr_value,
3801 talloc_array_length(state->xattr_value));
3802 if (state->xattr_size == -1) {
3803 state->vfs_aio_state.error = errno;
3806 end_profile:
3807 PROFILE_TIMESTAMP(&end_time);
3808 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3809 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3812 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3814 struct tevent_req *req = tevent_req_callback_data(
3815 subreq, struct tevent_req);
3816 struct vfswrap_getxattrat_state *state = tevent_req_data(
3817 req, struct vfswrap_getxattrat_state);
3818 int ret;
3819 bool ok;
3822 * Make sure we run as the user again
3824 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3825 SMB_ASSERT(ok);
3827 ret = pthreadpool_tevent_job_recv(subreq);
3828 TALLOC_FREE(subreq);
3829 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3830 talloc_set_destructor(state, NULL);
3831 if (ret != 0) {
3832 if (ret != EAGAIN) {
3833 tevent_req_error(req, ret);
3834 return;
3837 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3838 * means the lower level pthreadpool failed to create a new
3839 * thread. Fallback to sync processing in that case to allow
3840 * some progress for the client.
3842 vfswrap_getxattrat_do_sync(req);
3843 return;
3846 if (state->xattr_size == -1) {
3847 tevent_req_error(req, state->vfs_aio_state.error);
3848 return;
3851 if (state->xattr_value == NULL) {
3853 * The caller only wanted the size.
3855 tevent_req_done(req);
3856 return;
3860 * shrink the buffer to the returned size.
3861 * (can't fail). It means NULL if size is 0.
3863 state->xattr_value = talloc_realloc(state,
3864 state->xattr_value,
3865 uint8_t,
3866 state->xattr_size);
3868 tevent_req_done(req);
3871 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3872 struct vfs_aio_state *aio_state,
3873 TALLOC_CTX *mem_ctx,
3874 uint8_t **xattr_value)
3876 struct vfswrap_getxattrat_state *state = tevent_req_data(
3877 req, struct vfswrap_getxattrat_state);
3878 ssize_t xattr_size;
3880 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3881 tevent_req_received(req);
3882 return -1;
3885 *aio_state = state->vfs_aio_state;
3886 xattr_size = state->xattr_size;
3887 if (xattr_value != NULL) {
3888 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3891 tevent_req_received(req);
3892 return xattr_size;
3895 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3897 int fd = fsp_get_pathref_fd(fsp);
3899 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3901 if (!fsp->fsp_flags.is_pathref) {
3902 return flistxattr(fd, list, size);
3905 if (fsp->fsp_flags.have_proc_fds) {
3906 const char *p = NULL;
3907 char buf[PATH_MAX];
3909 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3910 if (p == NULL) {
3911 return -1;
3914 return listxattr(p, list, size);
3918 * This is no longer a handle based call.
3920 return listxattr(fsp->fsp_name->base_name, list, size);
3923 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3925 int fd = fsp_get_pathref_fd(fsp);
3927 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3929 if (!fsp->fsp_flags.is_pathref) {
3930 return fremovexattr(fd, name);
3933 if (fsp->fsp_flags.have_proc_fds) {
3934 const char *p = NULL;
3935 char buf[PATH_MAX];
3937 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3938 if (p == NULL) {
3939 return -1;
3942 return removexattr(p, name);
3946 * This is no longer a handle based call.
3948 return removexattr(fsp->fsp_name->base_name, name);
3951 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3953 int fd = fsp_get_pathref_fd(fsp);
3955 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3957 if (!fsp->fsp_flags.is_pathref) {
3958 return fsetxattr(fd, name, value, size, flags);
3961 if (fsp->fsp_flags.have_proc_fds) {
3962 const char *p = NULL;
3963 char buf[PATH_MAX];
3965 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3966 if (p == NULL) {
3967 return -1;
3970 return setxattr(p, name, value, size, flags);
3974 * This is no longer a handle based call.
3976 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3979 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3981 return false;
3984 static bool vfswrap_is_offline(struct connection_struct *conn,
3985 const struct smb_filename *fname)
3987 NTSTATUS status;
3988 char *path;
3989 bool offline = false;
3991 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3992 return false;
3995 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3996 #if defined(ENOTSUP)
3997 errno = ENOTSUP;
3998 #endif
3999 return false;
4002 status = get_full_smb_filename(talloc_tos(), fname, &path);
4003 if (!NT_STATUS_IS_OK(status)) {
4004 errno = map_errno_from_nt_status(status);
4005 return false;
4008 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
4010 TALLOC_FREE(path);
4012 return offline;
4015 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
4016 struct files_struct *fsp,
4017 TALLOC_CTX *mem_ctx,
4018 DATA_BLOB *cookie)
4020 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
4023 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
4024 struct files_struct *fsp,
4025 const DATA_BLOB old_cookie,
4026 TALLOC_CTX *mem_ctx,
4027 DATA_BLOB *new_cookie)
4029 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
4030 new_cookie);
4033 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
4034 struct smb_request *smb1req,
4035 struct smbXsrv_open *op,
4036 const DATA_BLOB old_cookie,
4037 TALLOC_CTX *mem_ctx,
4038 struct files_struct **fsp,
4039 DATA_BLOB *new_cookie)
4041 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
4042 old_cookie, mem_ctx,
4043 fsp, new_cookie);
4046 static struct vfs_fn_pointers vfs_default_fns = {
4047 /* Disk operations */
4049 .connect_fn = vfswrap_connect,
4050 .disconnect_fn = vfswrap_disconnect,
4051 .disk_free_fn = vfswrap_disk_free,
4052 .get_quota_fn = vfswrap_get_quota,
4053 .set_quota_fn = vfswrap_set_quota,
4054 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
4055 .statvfs_fn = vfswrap_statvfs,
4056 .fs_capabilities_fn = vfswrap_fs_capabilities,
4057 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
4058 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
4059 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
4060 .snap_check_path_fn = vfswrap_snap_check_path,
4061 .snap_create_fn = vfswrap_snap_create,
4062 .snap_delete_fn = vfswrap_snap_delete,
4064 /* Directory operations */
4066 .fdopendir_fn = vfswrap_fdopendir,
4067 .readdir_fn = vfswrap_readdir,
4068 .freaddir_attr_fn = vfswrap_freaddir_attr,
4069 .seekdir_fn = vfswrap_seekdir,
4070 .telldir_fn = vfswrap_telldir,
4071 .rewind_dir_fn = vfswrap_rewinddir,
4072 .mkdirat_fn = vfswrap_mkdirat,
4073 .closedir_fn = vfswrap_closedir,
4075 /* File operations */
4077 .openat_fn = vfswrap_openat,
4078 .create_file_fn = vfswrap_create_file,
4079 .close_fn = vfswrap_close,
4080 .pread_fn = vfswrap_pread,
4081 .pread_send_fn = vfswrap_pread_send,
4082 .pread_recv_fn = vfswrap_pread_recv,
4083 .pwrite_fn = vfswrap_pwrite,
4084 .pwrite_send_fn = vfswrap_pwrite_send,
4085 .pwrite_recv_fn = vfswrap_pwrite_recv,
4086 .lseek_fn = vfswrap_lseek,
4087 .sendfile_fn = vfswrap_sendfile,
4088 .recvfile_fn = vfswrap_recvfile,
4089 .renameat_fn = vfswrap_renameat,
4090 .fsync_send_fn = vfswrap_fsync_send,
4091 .fsync_recv_fn = vfswrap_fsync_recv,
4092 .stat_fn = vfswrap_stat,
4093 .fstat_fn = vfswrap_fstat,
4094 .lstat_fn = vfswrap_lstat,
4095 .fstatat_fn = vfswrap_fstatat,
4096 .get_alloc_size_fn = vfswrap_get_alloc_size,
4097 .unlinkat_fn = vfswrap_unlinkat,
4098 .fchmod_fn = vfswrap_fchmod,
4099 .fchown_fn = vfswrap_fchown,
4100 .lchown_fn = vfswrap_lchown,
4101 .chdir_fn = vfswrap_chdir,
4102 .getwd_fn = vfswrap_getwd,
4103 .fntimes_fn = vfswrap_fntimes,
4104 .ftruncate_fn = vfswrap_ftruncate,
4105 .fallocate_fn = vfswrap_fallocate,
4106 .lock_fn = vfswrap_lock,
4107 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4108 .fcntl_fn = vfswrap_fcntl,
4109 .linux_setlease_fn = vfswrap_linux_setlease,
4110 .getlock_fn = vfswrap_getlock,
4111 .symlinkat_fn = vfswrap_symlinkat,
4112 .readlinkat_fn = vfswrap_readlinkat,
4113 .linkat_fn = vfswrap_linkat,
4114 .mknodat_fn = vfswrap_mknodat,
4115 .realpath_fn = vfswrap_realpath,
4116 .fchflags_fn = vfswrap_fchflags,
4117 .file_id_create_fn = vfswrap_file_id_create,
4118 .fs_file_id_fn = vfswrap_fs_file_id,
4119 .fstreaminfo_fn = vfswrap_fstreaminfo,
4120 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4121 .connectpath_fn = vfswrap_connectpath,
4122 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4123 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4124 .strict_lock_check_fn = vfswrap_strict_lock_check,
4125 .translate_name_fn = vfswrap_translate_name,
4126 .parent_pathname_fn = vfswrap_parent_pathname,
4127 .fsctl_fn = vfswrap_fsctl,
4128 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4129 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4130 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4131 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4132 .offload_read_send_fn = vfswrap_offload_read_send,
4133 .offload_read_recv_fn = vfswrap_offload_read_recv,
4134 .offload_write_send_fn = vfswrap_offload_write_send,
4135 .offload_write_recv_fn = vfswrap_offload_write_recv,
4136 .fget_compression_fn = vfswrap_fget_compression,
4137 .set_compression_fn = vfswrap_set_compression,
4139 /* NT ACL operations. */
4141 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4142 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4143 .audit_file_fn = vfswrap_audit_file,
4145 /* POSIX ACL operations. */
4147 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4148 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4149 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4150 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4152 /* EA operations. */
4153 .getxattrat_send_fn = vfswrap_getxattrat_send,
4154 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4155 .fgetxattr_fn = vfswrap_fgetxattr,
4156 .flistxattr_fn = vfswrap_flistxattr,
4157 .fremovexattr_fn = vfswrap_fremovexattr,
4158 .fsetxattr_fn = vfswrap_fsetxattr,
4160 /* aio operations */
4161 .aio_force_fn = vfswrap_aio_force,
4163 /* durable handle operations */
4164 .durable_cookie_fn = vfswrap_durable_cookie,
4165 .durable_disconnect_fn = vfswrap_durable_disconnect,
4166 .durable_reconnect_fn = vfswrap_durable_reconnect,
4169 static_decl_vfs;
4170 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4173 * Here we need to implement every call!
4175 * As this is the end of the vfs module chain.
4177 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4178 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4179 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);