WHATSNEW: Add release notes for Samba 4.13.14.
[Samba.git] / source3 / modules / vfs_default.c
blobcf5e1cbc296c25e67ccde38a72eed208cc9892f9
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"
40 #undef DBGC_CLASS
41 #define DBGC_CLASS DBGC_VFS
43 /* Check for NULL pointer parameters in vfswrap_* functions */
45 /* We don't want to have NULL function pointers lying around. Someone
46 is sure to try and execute them. These stubs are used to prevent
47 this possibility. */
49 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
51 return 0; /* Return >= 0 for success */
54 static void vfswrap_disconnect(vfs_handle_struct *handle)
58 /* Disk operations */
60 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
61 const struct smb_filename *smb_fname,
62 uint64_t *bsize,
63 uint64_t *dfree,
64 uint64_t *dsize)
66 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
67 return (uint64_t)-1;
70 *bsize = 512;
71 return *dfree / 2;
74 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
75 const struct smb_filename *smb_fname,
76 enum SMB_QUOTA_TYPE qtype,
77 unid_t id,
78 SMB_DISK_QUOTA *qt)
80 #ifdef HAVE_SYS_QUOTAS
81 int result;
83 START_PROFILE(syscall_get_quota);
84 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
85 END_PROFILE(syscall_get_quota);
86 return result;
87 #else
88 errno = ENOSYS;
89 return -1;
90 #endif
93 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
95 #ifdef HAVE_SYS_QUOTAS
96 int result;
98 START_PROFILE(syscall_set_quota);
99 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
100 END_PROFILE(syscall_set_quota);
101 return result;
102 #else
103 errno = ENOSYS;
104 return -1;
105 #endif
108 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
109 struct files_struct *fsp,
110 struct shadow_copy_data *shadow_copy_data,
111 bool labels)
113 errno = ENOSYS;
114 return -1; /* Not implemented. */
117 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
118 const struct smb_filename *smb_fname,
119 vfs_statvfs_struct *statbuf)
121 return sys_statvfs(smb_fname->base_name, statbuf);
124 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
125 enum timestamp_set_resolution *p_ts_res)
127 const struct loadparm_substitution *lp_sub =
128 loadparm_s3_global_substitution();
129 connection_struct *conn = handle->conn;
130 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
131 struct smb_filename *smb_fname_cpath = NULL;
132 struct vfs_statvfs_struct statbuf;
133 int ret;
135 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
136 conn->connectpath,
137 NULL,
138 NULL,
141 if (smb_fname_cpath == NULL) {
142 return caps;
145 ZERO_STRUCT(statbuf);
146 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
147 if (ret == 0) {
148 caps = statbuf.FsCapabilities;
151 *p_ts_res = TIMESTAMP_SET_SECONDS;
153 /* Work out what timestamp resolution we can
154 * use when setting a timestamp. */
156 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
157 if (ret == -1) {
158 TALLOC_FREE(smb_fname_cpath);
159 return caps;
162 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
163 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
164 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
165 /* If any of the normal UNIX directory timestamps
166 * have a non-zero tv_nsec component assume
167 * we might be able to set sub-second timestamps.
168 * See what filetime set primitives we have.
170 #if defined(HAVE_UTIMENSAT)
171 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
172 #elif defined(HAVE_UTIMES)
173 /* utimes allows msec timestamps to be set. */
174 *p_ts_res = TIMESTAMP_SET_MSEC;
175 #elif defined(HAVE_UTIME)
176 /* utime only allows sec timestamps to be set. */
177 *p_ts_res = TIMESTAMP_SET_SECONDS;
178 #endif
180 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
181 "resolution of %s "
182 "available on share %s, directory %s\n",
183 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
184 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
185 conn->connectpath ));
187 TALLOC_FREE(smb_fname_cpath);
188 return caps;
191 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
192 struct dfs_GetDFSReferral *r)
194 struct junction_map *junction = NULL;
195 int consumedcnt = 0;
196 bool self_referral = false;
197 char *pathnamep = NULL;
198 char *local_dfs_path = NULL;
199 NTSTATUS status;
200 size_t i;
201 uint16_t max_referral_level = r->in.req.max_referral_level;
203 if (DEBUGLVL(10)) {
204 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
207 /* get the junction entry */
208 if (r->in.req.servername == NULL) {
209 return NT_STATUS_NOT_FOUND;
213 * Trim pathname sent by client so it begins with only one backslash.
214 * Two backslashes confuse some dfs clients
217 local_dfs_path = talloc_strdup(r, r->in.req.servername);
218 if (local_dfs_path == NULL) {
219 return NT_STATUS_NO_MEMORY;
221 pathnamep = local_dfs_path;
222 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
223 IS_DIRECTORY_SEP(pathnamep[1])) {
224 pathnamep++;
227 junction = talloc_zero(r, struct junction_map);
228 if (junction == NULL) {
229 return NT_STATUS_NO_MEMORY;
232 /* The following call can change cwd. */
233 status = get_referred_path(r,
234 handle->conn->session_info,
235 pathnamep,
236 handle->conn->sconn->remote_address,
237 handle->conn->sconn->local_address,
238 !handle->conn->sconn->using_smb2,
239 junction, &consumedcnt, &self_referral);
240 if (!NT_STATUS_IS_OK(status)) {
241 struct smb_filename connectpath_fname = {
242 .base_name = handle->conn->connectpath
244 vfs_ChDir(handle->conn, &connectpath_fname);
245 return status;
248 struct smb_filename connectpath_fname = {
249 .base_name = handle->conn->connectpath
251 vfs_ChDir(handle->conn, &connectpath_fname);
254 if (!self_referral) {
255 pathnamep[consumedcnt] = '\0';
257 if (DEBUGLVL(3)) {
258 dbgtext("Path %s to alternate path(s):",
259 pathnamep);
260 for (i=0; i < junction->referral_count; i++) {
261 dbgtext(" %s",
262 junction->referral_list[i].alternate_path);
264 dbgtext(".\n");
268 if (r->in.req.max_referral_level <= 2) {
269 max_referral_level = 2;
271 if (r->in.req.max_referral_level >= 3) {
272 max_referral_level = 3;
275 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
276 if (r->out.resp == NULL) {
277 return NT_STATUS_NO_MEMORY;
280 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
281 r->out.resp->nb_referrals = junction->referral_count;
283 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
284 if (self_referral) {
285 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
288 r->out.resp->referral_entries = talloc_zero_array(r,
289 struct dfs_referral_type,
290 r->out.resp->nb_referrals);
291 if (r->out.resp->referral_entries == NULL) {
292 return NT_STATUS_NO_MEMORY;
295 switch (max_referral_level) {
296 case 2:
297 for(i=0; i < junction->referral_count; i++) {
298 struct referral *ref = &junction->referral_list[i];
299 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
300 struct dfs_referral_type *t =
301 &r->out.resp->referral_entries[i];
302 struct dfs_referral_v2 *v2 = &t->referral.v2;
304 t->version = 2;
305 v2->size = VERSION2_REFERRAL_SIZE;
306 if (self_referral) {
307 v2->server_type = DFS_SERVER_ROOT;
308 } else {
309 v2->server_type = DFS_SERVER_NON_ROOT;
311 v2->entry_flags = 0;
312 v2->proximity = ref->proximity;
313 v2->ttl = ref->ttl;
314 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
315 if (v2->DFS_path == NULL) {
316 return NT_STATUS_NO_MEMORY;
318 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
319 if (v2->DFS_alt_path == NULL) {
320 return NT_STATUS_NO_MEMORY;
322 v2->netw_address = talloc_strdup(mem_ctx,
323 ref->alternate_path);
324 if (v2->netw_address == NULL) {
325 return NT_STATUS_NO_MEMORY;
329 break;
330 case 3:
331 for(i=0; i < junction->referral_count; i++) {
332 struct referral *ref = &junction->referral_list[i];
333 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
334 struct dfs_referral_type *t =
335 &r->out.resp->referral_entries[i];
336 struct dfs_referral_v3 *v3 = &t->referral.v3;
337 struct dfs_normal_referral *r1 = &v3->referrals.r1;
339 t->version = 3;
340 v3->size = VERSION3_REFERRAL_SIZE;
341 if (self_referral) {
342 v3->server_type = DFS_SERVER_ROOT;
343 } else {
344 v3->server_type = DFS_SERVER_NON_ROOT;
346 v3->entry_flags = 0;
347 v3->ttl = ref->ttl;
348 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
349 if (r1->DFS_path == NULL) {
350 return NT_STATUS_NO_MEMORY;
352 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
353 if (r1->DFS_alt_path == NULL) {
354 return NT_STATUS_NO_MEMORY;
356 r1->netw_address = talloc_strdup(mem_ctx,
357 ref->alternate_path);
358 if (r1->netw_address == NULL) {
359 return NT_STATUS_NO_MEMORY;
362 break;
363 default:
364 DEBUG(0,("Invalid dfs referral version: %d\n",
365 max_referral_level));
366 return NT_STATUS_INVALID_LEVEL;
369 if (DEBUGLVL(10)) {
370 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
373 return NT_STATUS_OK;
376 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
377 struct files_struct *dirfsp,
378 const struct smb_filename *smb_fname,
379 const struct referral *reflist,
380 size_t referral_count)
382 TALLOC_CTX *frame = talloc_stackframe();
383 NTSTATUS status = NT_STATUS_NO_MEMORY;
384 int ret;
385 char *msdfs_link = NULL;
387 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
389 /* Form the msdfs_link contents */
390 msdfs_link = msdfs_link_string(frame,
391 reflist,
392 referral_count);
393 if (msdfs_link == NULL) {
394 goto out;
397 ret = symlinkat(msdfs_link,
398 dirfsp->fh->fd,
399 smb_fname->base_name);
400 if (ret == 0) {
401 status = NT_STATUS_OK;
402 } else {
403 status = map_nt_error_from_unix(errno);
406 out:
408 TALLOC_FREE(frame);
409 return status;
413 * Read and return the contents of a DFS redirect given a
414 * pathname. A caller can pass in NULL for ppreflist and
415 * preferral_count but still determine if this was a
416 * DFS redirect point by getting NT_STATUS_OK back
417 * without incurring the overhead of reading and parsing
418 * the referral contents.
421 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
422 TALLOC_CTX *mem_ctx,
423 struct files_struct *dirfsp,
424 struct smb_filename *smb_fname,
425 struct referral **ppreflist,
426 size_t *preferral_count)
428 NTSTATUS status = NT_STATUS_NO_MEMORY;
429 size_t bufsize;
430 char *link_target = NULL;
431 int referral_len;
432 bool ok;
433 #if defined(HAVE_BROKEN_READLINK)
434 char link_target_buf[PATH_MAX];
435 #else
436 char link_target_buf[7];
437 #endif
438 int ret;
440 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
442 if (is_named_stream(smb_fname)) {
443 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
444 goto err;
447 if (ppreflist == NULL && preferral_count == NULL) {
449 * We're only checking if this is a DFS
450 * redirect. We don't need to return data.
452 bufsize = sizeof(link_target_buf);
453 link_target = link_target_buf;
454 } else {
455 bufsize = PATH_MAX;
456 link_target = talloc_array(mem_ctx, char, bufsize);
457 if (!link_target) {
458 goto err;
462 referral_len = readlinkat(dirfsp->fh->fd,
463 smb_fname->base_name,
464 link_target,
465 bufsize - 1);
466 if (referral_len == -1) {
467 if (errno == EINVAL) {
469 * If the path isn't a link, readlinkat
470 * returns EINVAL. Allow the caller to
471 * detect this.
473 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
474 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
475 } else {
476 status = map_nt_error_from_unix(errno);
477 DBG_ERR("Error reading "
478 "msdfs link %s: %s\n",
479 smb_fname->base_name,
480 strerror(errno));
482 goto err;
484 link_target[referral_len] = '\0';
486 DBG_INFO("%s -> %s\n",
487 smb_fname->base_name,
488 link_target);
490 if (!strnequal(link_target, "msdfs:", 6)) {
491 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
492 goto err;
495 ret = sys_lstat(smb_fname->base_name,
496 &smb_fname->st,
497 lp_fake_directory_create_times(SNUM(handle->conn)));
498 if (ret < 0) {
499 status = map_nt_error_from_unix(errno);
500 goto err;
503 if (ppreflist == NULL && preferral_count == NULL) {
504 /* Early return for checking if this is a DFS link. */
505 return NT_STATUS_OK;
508 ok = parse_msdfs_symlink(mem_ctx,
509 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
510 link_target,
511 ppreflist,
512 preferral_count);
514 if (ok) {
515 status = NT_STATUS_OK;
516 } else {
517 status = NT_STATUS_NO_MEMORY;
520 err:
522 if (link_target != link_target_buf) {
523 TALLOC_FREE(link_target);
525 return status;
528 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
529 TALLOC_CTX *mem_ctx,
530 const char *service_path,
531 char **base_volume)
533 return NT_STATUS_NOT_SUPPORTED;
536 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
537 TALLOC_CTX *mem_ctx,
538 const char *base_volume,
539 time_t *tstamp,
540 bool rw,
541 char **base_path,
542 char **snap_path)
544 return NT_STATUS_NOT_SUPPORTED;
547 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
548 TALLOC_CTX *mem_ctx,
549 char *base_path,
550 char *snap_path)
552 return NT_STATUS_NOT_SUPPORTED;
555 /* Directory operations */
557 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
558 files_struct *fsp,
559 const char *mask,
560 uint32_t attr)
562 DIR *result;
564 START_PROFILE(syscall_fdopendir);
565 result = sys_fdopendir(fsp->fh->fd);
566 END_PROFILE(syscall_fdopendir);
567 return result;
571 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
572 DIR *dirp,
573 SMB_STRUCT_STAT *sbuf)
575 struct dirent *result;
577 START_PROFILE(syscall_readdir);
578 result = readdir(dirp);
579 END_PROFILE(syscall_readdir);
580 if (sbuf) {
581 /* Default Posix readdir() does not give us stat info.
582 * Set to invalid to indicate we didn't return this info. */
583 SET_STAT_INVALID(*sbuf);
584 #if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
585 if (result != NULL) {
586 /* See if we can efficiently return this. */
587 struct stat st;
588 int flags = AT_SYMLINK_NOFOLLOW;
589 int ret = fstatat(dirfd(dirp),
590 result->d_name,
591 &st,
592 flags);
594 * As this is an optimization,
595 * ignore it if we stat'ed a
596 * symlink. Make the caller
597 * do it again as we don't
598 * know if they wanted the link
599 * info, or its target info.
601 if ((ret == 0) && (!S_ISLNK(st.st_mode))) {
602 init_stat_ex_from_stat(sbuf,
603 &st,
604 lp_fake_directory_create_times(
605 SNUM(handle->conn)));
608 #endif
610 return result;
613 static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
614 const struct smb_filename *fname,
615 TALLOC_CTX *mem_ctx,
616 struct readdir_attr_data **attr_data)
618 return NT_STATUS_NOT_SUPPORTED;
621 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
623 START_PROFILE(syscall_seekdir);
624 seekdir(dirp, offset);
625 END_PROFILE(syscall_seekdir);
628 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
630 long result;
631 START_PROFILE(syscall_telldir);
632 result = telldir(dirp);
633 END_PROFILE(syscall_telldir);
634 return result;
637 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
639 START_PROFILE(syscall_rewinddir);
640 rewinddir(dirp);
641 END_PROFILE(syscall_rewinddir);
644 static int vfswrap_mkdirat(vfs_handle_struct *handle,
645 struct files_struct *dirfsp,
646 const struct smb_filename *smb_fname,
647 mode_t mode)
649 int result;
650 struct smb_filename *parent = NULL;
651 bool ok;
653 START_PROFILE(syscall_mkdirat);
655 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
657 if (lp_inherit_acls(SNUM(handle->conn))) {
658 ok = parent_smb_fname(talloc_tos(), smb_fname, &parent, NULL);
659 if (ok && directory_has_default_acl(handle->conn,
660 dirfsp,
661 parent))
663 mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
667 TALLOC_FREE(parent);
669 result = mkdirat(dirfsp->fh->fd, smb_fname->base_name, mode);
671 END_PROFILE(syscall_mkdirat);
672 return result;
675 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
677 int result;
679 START_PROFILE(syscall_closedir);
680 result = closedir(dirp);
681 END_PROFILE(syscall_closedir);
682 return result;
685 /* File operations */
687 static int vfswrap_openat(vfs_handle_struct *handle,
688 const struct files_struct *dirfsp,
689 const struct smb_filename *smb_fname,
690 files_struct *fsp,
691 int flags,
692 mode_t mode)
694 int result;
696 START_PROFILE(syscall_openat);
698 if (is_named_stream(smb_fname)) {
699 errno = ENOENT;
700 result = -1;
701 goto out;
704 result = openat(dirfsp->fh->fd, smb_fname->base_name, flags, mode);
706 out:
707 END_PROFILE(syscall_openat);
708 return result;
710 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
711 struct smb_request *req,
712 struct files_struct **dirfsp,
713 struct smb_filename *smb_fname,
714 uint32_t access_mask,
715 uint32_t share_access,
716 uint32_t create_disposition,
717 uint32_t create_options,
718 uint32_t file_attributes,
719 uint32_t oplock_request,
720 const struct smb2_lease *lease,
721 uint64_t allocation_size,
722 uint32_t private_flags,
723 struct security_descriptor *sd,
724 struct ea_list *ea_list,
725 files_struct **result,
726 int *pinfo,
727 const struct smb2_create_blobs *in_context_blobs,
728 struct smb2_create_blobs *out_context_blobs)
730 return create_file_default(handle->conn, req, dirfsp, smb_fname,
731 access_mask, share_access,
732 create_disposition, create_options,
733 file_attributes, oplock_request, lease,
734 allocation_size, private_flags,
735 sd, ea_list, result,
736 pinfo, in_context_blobs, out_context_blobs);
739 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
741 int result;
743 START_PROFILE(syscall_close);
744 result = fd_close_posix(fsp);
745 END_PROFILE(syscall_close);
746 return result;
749 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
750 size_t n, off_t offset)
752 ssize_t result;
754 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
755 START_PROFILE_BYTES(syscall_pread, n);
756 result = sys_pread_full(fsp->fh->fd, data, n, offset);
757 END_PROFILE_BYTES(syscall_pread);
759 if (result == -1 && errno == ESPIPE) {
760 /* Maintain the fiction that pipes can be seeked (sought?) on. */
761 result = sys_read(fsp->fh->fd, data, n);
762 fsp->fh->pos = 0;
765 #else /* HAVE_PREAD */
766 errno = ENOSYS;
767 result = -1;
768 #endif /* HAVE_PREAD */
770 return result;
773 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
774 size_t n, off_t offset)
776 ssize_t result;
778 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
779 START_PROFILE_BYTES(syscall_pwrite, n);
780 result = sys_pwrite_full(fsp->fh->fd, data, n, offset);
781 END_PROFILE_BYTES(syscall_pwrite);
783 if (result == -1 && errno == ESPIPE) {
784 /* Maintain the fiction that pipes can be sought on. */
785 result = sys_write(fsp->fh->fd, data, n);
788 #else /* HAVE_PWRITE */
789 errno = ENOSYS;
790 result = -1;
791 #endif /* HAVE_PWRITE */
793 return result;
796 struct vfswrap_pread_state {
797 ssize_t ret;
798 int fd;
799 void *buf;
800 size_t count;
801 off_t offset;
803 struct vfs_aio_state vfs_aio_state;
804 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
807 static void vfs_pread_do(void *private_data);
808 static void vfs_pread_done(struct tevent_req *subreq);
809 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
811 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
812 TALLOC_CTX *mem_ctx,
813 struct tevent_context *ev,
814 struct files_struct *fsp,
815 void *data,
816 size_t n, off_t offset)
818 struct tevent_req *req, *subreq;
819 struct vfswrap_pread_state *state;
821 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
822 if (req == NULL) {
823 return NULL;
826 state->ret = -1;
827 state->fd = fsp->fh->fd;
828 state->buf = data;
829 state->count = n;
830 state->offset = offset;
832 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
833 state->profile_bytes, n);
834 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
836 subreq = pthreadpool_tevent_job_send(
837 state, ev, handle->conn->sconn->pool,
838 vfs_pread_do, state);
839 if (tevent_req_nomem(subreq, req)) {
840 return tevent_req_post(req, ev);
842 tevent_req_set_callback(subreq, vfs_pread_done, req);
844 talloc_set_destructor(state, vfs_pread_state_destructor);
846 return req;
849 static void vfs_pread_do(void *private_data)
851 struct vfswrap_pread_state *state = talloc_get_type_abort(
852 private_data, struct vfswrap_pread_state);
853 struct timespec start_time;
854 struct timespec end_time;
856 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
858 PROFILE_TIMESTAMP(&start_time);
860 state->ret = sys_pread_full(state->fd,
861 state->buf,
862 state->count,
863 state->offset);
865 if (state->ret == -1) {
866 state->vfs_aio_state.error = errno;
869 PROFILE_TIMESTAMP(&end_time);
871 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
873 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
876 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
878 return -1;
881 static void vfs_pread_done(struct tevent_req *subreq)
883 struct tevent_req *req = tevent_req_callback_data(
884 subreq, struct tevent_req);
885 struct vfswrap_pread_state *state = tevent_req_data(
886 req, struct vfswrap_pread_state);
887 int ret;
889 ret = pthreadpool_tevent_job_recv(subreq);
890 TALLOC_FREE(subreq);
891 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
892 talloc_set_destructor(state, NULL);
893 if (ret != 0) {
894 if (ret != EAGAIN) {
895 tevent_req_error(req, ret);
896 return;
899 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
900 * means the lower level pthreadpool failed to create a new
901 * thread. Fallback to sync processing in that case to allow
902 * some progress for the client.
904 vfs_pread_do(state);
907 tevent_req_done(req);
910 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
911 struct vfs_aio_state *vfs_aio_state)
913 struct vfswrap_pread_state *state = tevent_req_data(
914 req, struct vfswrap_pread_state);
916 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
917 return -1;
920 *vfs_aio_state = state->vfs_aio_state;
921 return state->ret;
924 struct vfswrap_pwrite_state {
925 ssize_t ret;
926 int fd;
927 const void *buf;
928 size_t count;
929 off_t offset;
931 struct vfs_aio_state vfs_aio_state;
932 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
935 static void vfs_pwrite_do(void *private_data);
936 static void vfs_pwrite_done(struct tevent_req *subreq);
937 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
939 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
940 TALLOC_CTX *mem_ctx,
941 struct tevent_context *ev,
942 struct files_struct *fsp,
943 const void *data,
944 size_t n, off_t offset)
946 struct tevent_req *req, *subreq;
947 struct vfswrap_pwrite_state *state;
949 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
950 if (req == NULL) {
951 return NULL;
954 state->ret = -1;
955 state->fd = fsp->fh->fd;
956 state->buf = data;
957 state->count = n;
958 state->offset = offset;
960 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
961 state->profile_bytes, n);
962 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
964 subreq = pthreadpool_tevent_job_send(
965 state, ev, handle->conn->sconn->pool,
966 vfs_pwrite_do, state);
967 if (tevent_req_nomem(subreq, req)) {
968 return tevent_req_post(req, ev);
970 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
972 talloc_set_destructor(state, vfs_pwrite_state_destructor);
974 return req;
977 static void vfs_pwrite_do(void *private_data)
979 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
980 private_data, struct vfswrap_pwrite_state);
981 struct timespec start_time;
982 struct timespec end_time;
984 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
986 PROFILE_TIMESTAMP(&start_time);
988 state->ret = sys_pwrite_full(state->fd,
989 state->buf,
990 state->count,
991 state->offset);
993 if (state->ret == -1) {
994 state->vfs_aio_state.error = errno;
997 PROFILE_TIMESTAMP(&end_time);
999 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1001 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1004 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1006 return -1;
1009 static void vfs_pwrite_done(struct tevent_req *subreq)
1011 struct tevent_req *req = tevent_req_callback_data(
1012 subreq, struct tevent_req);
1013 struct vfswrap_pwrite_state *state = tevent_req_data(
1014 req, struct vfswrap_pwrite_state);
1015 int ret;
1017 ret = pthreadpool_tevent_job_recv(subreq);
1018 TALLOC_FREE(subreq);
1019 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1020 talloc_set_destructor(state, NULL);
1021 if (ret != 0) {
1022 if (ret != EAGAIN) {
1023 tevent_req_error(req, ret);
1024 return;
1027 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1028 * means the lower level pthreadpool failed to create a new
1029 * thread. Fallback to sync processing in that case to allow
1030 * some progress for the client.
1032 vfs_pwrite_do(state);
1035 tevent_req_done(req);
1038 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1039 struct vfs_aio_state *vfs_aio_state)
1041 struct vfswrap_pwrite_state *state = tevent_req_data(
1042 req, struct vfswrap_pwrite_state);
1044 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1045 return -1;
1048 *vfs_aio_state = state->vfs_aio_state;
1049 return state->ret;
1052 struct vfswrap_fsync_state {
1053 ssize_t ret;
1054 int fd;
1056 struct vfs_aio_state vfs_aio_state;
1057 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1060 static void vfs_fsync_do(void *private_data);
1061 static void vfs_fsync_done(struct tevent_req *subreq);
1062 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1064 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1065 TALLOC_CTX *mem_ctx,
1066 struct tevent_context *ev,
1067 struct files_struct *fsp)
1069 struct tevent_req *req, *subreq;
1070 struct vfswrap_fsync_state *state;
1072 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1073 if (req == NULL) {
1074 return NULL;
1077 state->ret = -1;
1078 state->fd = fsp->fh->fd;
1080 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1081 state->profile_bytes, 0);
1082 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1084 subreq = pthreadpool_tevent_job_send(
1085 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1086 if (tevent_req_nomem(subreq, req)) {
1087 return tevent_req_post(req, ev);
1089 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1091 talloc_set_destructor(state, vfs_fsync_state_destructor);
1093 return req;
1096 static void vfs_fsync_do(void *private_data)
1098 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1099 private_data, struct vfswrap_fsync_state);
1100 struct timespec start_time;
1101 struct timespec end_time;
1103 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1105 PROFILE_TIMESTAMP(&start_time);
1107 do {
1108 state->ret = fsync(state->fd);
1109 } while ((state->ret == -1) && (errno == EINTR));
1111 if (state->ret == -1) {
1112 state->vfs_aio_state.error = errno;
1115 PROFILE_TIMESTAMP(&end_time);
1117 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1119 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1122 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1124 return -1;
1127 static void vfs_fsync_done(struct tevent_req *subreq)
1129 struct tevent_req *req = tevent_req_callback_data(
1130 subreq, struct tevent_req);
1131 struct vfswrap_fsync_state *state = tevent_req_data(
1132 req, struct vfswrap_fsync_state);
1133 int ret;
1135 ret = pthreadpool_tevent_job_recv(subreq);
1136 TALLOC_FREE(subreq);
1137 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1138 talloc_set_destructor(state, NULL);
1139 if (ret != 0) {
1140 if (ret != EAGAIN) {
1141 tevent_req_error(req, ret);
1142 return;
1145 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1146 * means the lower level pthreadpool failed to create a new
1147 * thread. Fallback to sync processing in that case to allow
1148 * some progress for the client.
1150 vfs_fsync_do(state);
1153 tevent_req_done(req);
1156 static int vfswrap_fsync_recv(struct tevent_req *req,
1157 struct vfs_aio_state *vfs_aio_state)
1159 struct vfswrap_fsync_state *state = tevent_req_data(
1160 req, struct vfswrap_fsync_state);
1162 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1163 return -1;
1166 *vfs_aio_state = state->vfs_aio_state;
1167 return state->ret;
1170 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1172 off_t result = 0;
1174 START_PROFILE(syscall_lseek);
1176 result = lseek(fsp->fh->fd, offset, whence);
1178 * We want to maintain the fiction that we can seek
1179 * on a fifo for file system purposes. This allows
1180 * people to set up UNIX fifo's that feed data to Windows
1181 * applications. JRA.
1184 if((result == -1) && (errno == ESPIPE)) {
1185 result = 0;
1186 errno = 0;
1189 END_PROFILE(syscall_lseek);
1190 return result;
1193 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1194 off_t offset, size_t n)
1196 ssize_t result;
1198 START_PROFILE_BYTES(syscall_sendfile, n);
1199 result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
1200 END_PROFILE_BYTES(syscall_sendfile);
1201 return result;
1204 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1205 int fromfd,
1206 files_struct *tofsp,
1207 off_t offset,
1208 size_t n)
1210 ssize_t result;
1212 START_PROFILE_BYTES(syscall_recvfile, n);
1213 result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
1214 END_PROFILE_BYTES(syscall_recvfile);
1215 return result;
1218 static int vfswrap_renameat(vfs_handle_struct *handle,
1219 files_struct *srcfsp,
1220 const struct smb_filename *smb_fname_src,
1221 files_struct *dstfsp,
1222 const struct smb_filename *smb_fname_dst)
1224 int result = -1;
1226 START_PROFILE(syscall_renameat);
1228 if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) {
1229 errno = ENOENT;
1230 goto out;
1233 result = renameat(srcfsp->fh->fd,
1234 smb_fname_src->base_name,
1235 dstfsp->fh->fd,
1236 smb_fname_dst->base_name);
1238 out:
1239 END_PROFILE(syscall_renameat);
1240 return result;
1243 static int vfswrap_stat(vfs_handle_struct *handle,
1244 struct smb_filename *smb_fname)
1246 int result = -1;
1248 START_PROFILE(syscall_stat);
1250 if (is_named_stream(smb_fname)) {
1251 errno = ENOENT;
1252 goto out;
1255 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1256 lp_fake_directory_create_times(SNUM(handle->conn)));
1257 out:
1258 END_PROFILE(syscall_stat);
1259 return result;
1262 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1264 int result;
1266 START_PROFILE(syscall_fstat);
1267 result = sys_fstat(fsp->fh->fd,
1268 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1269 END_PROFILE(syscall_fstat);
1270 return result;
1273 static int vfswrap_lstat(vfs_handle_struct *handle,
1274 struct smb_filename *smb_fname)
1276 int result = -1;
1278 START_PROFILE(syscall_lstat);
1280 if (is_named_stream(smb_fname)) {
1281 errno = ENOENT;
1282 goto out;
1285 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1286 lp_fake_directory_create_times(SNUM(handle->conn)));
1287 out:
1288 END_PROFILE(syscall_lstat);
1289 return result;
1292 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1293 const char *name,
1294 enum vfs_translate_direction direction,
1295 TALLOC_CTX *mem_ctx,
1296 char **mapped_name)
1298 return NT_STATUS_NONE_MAPPED;
1302 * Implement the default fsctl operation.
1304 static bool vfswrap_logged_ioctl_message = false;
1306 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1307 struct files_struct *fsp,
1308 TALLOC_CTX *ctx,
1309 uint32_t function,
1310 uint16_t req_flags, /* Needed for UNICODE ... */
1311 const uint8_t *_in_data,
1312 uint32_t in_len,
1313 uint8_t **_out_data,
1314 uint32_t max_out_len,
1315 uint32_t *out_len)
1317 const char *in_data = (const char *)_in_data;
1318 char **out_data = (char **)_out_data;
1319 NTSTATUS status;
1321 switch (function) {
1322 case FSCTL_SET_SPARSE:
1324 bool set_sparse = true;
1326 if (in_len >= 1 && in_data[0] == 0) {
1327 set_sparse = false;
1330 status = file_set_sparse(handle->conn, fsp, set_sparse);
1332 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1333 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1334 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1335 nt_errstr(status)));
1337 return status;
1340 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1342 unsigned char objid[16];
1343 char *return_data = NULL;
1345 /* This should return the object-id on this file.
1346 * I think I'll make this be the inode+dev. JRA.
1349 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1350 fsp_fnum_dbg(fsp)));
1352 *out_len = MIN(max_out_len, 64);
1354 /* Hmmm, will this cause problems if less data asked for? */
1355 return_data = talloc_array(ctx, char, 64);
1356 if (return_data == NULL) {
1357 return NT_STATUS_NO_MEMORY;
1360 /* For backwards compatibility only store the dev/inode. */
1361 push_file_id_16(return_data, &fsp->file_id);
1362 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1363 push_file_id_16(return_data+32, &fsp->file_id);
1364 memset(return_data+48, 0, 16);
1365 *out_data = return_data;
1366 return NT_STATUS_OK;
1369 case FSCTL_GET_REPARSE_POINT:
1371 status = fsctl_get_reparse_point(
1372 fsp, ctx, out_data, max_out_len, out_len);
1373 return status;
1376 case FSCTL_SET_REPARSE_POINT:
1378 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1379 return status;
1382 case FSCTL_DELETE_REPARSE_POINT:
1384 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1385 return status;
1388 case FSCTL_GET_SHADOW_COPY_DATA:
1391 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1392 * and return their volume names. If max_data_count is 16, then it is just
1393 * asking for the number of volumes and length of the combined names.
1395 * pdata is the data allocated by our caller, but that uses
1396 * total_data_count (which is 0 in our case) rather than max_data_count.
1397 * Allocate the correct amount and return the pointer to let
1398 * it be deallocated when we return.
1400 struct shadow_copy_data *shadow_data = NULL;
1401 bool labels = False;
1402 uint32_t labels_data_count = 0;
1403 uint32_t i;
1404 char *cur_pdata = NULL;
1406 if (max_out_len < 16) {
1407 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1408 max_out_len));
1409 return NT_STATUS_INVALID_PARAMETER;
1412 if (max_out_len > 16) {
1413 labels = True;
1416 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1417 if (shadow_data == NULL) {
1418 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1419 return NT_STATUS_NO_MEMORY;
1423 * Call the VFS routine to actually do the work.
1425 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1426 int log_lev = 0;
1427 if (errno == 0) {
1428 /* broken module didn't set errno on error */
1429 status = NT_STATUS_UNSUCCESSFUL;
1430 } else {
1431 status = map_nt_error_from_unix(errno);
1432 if (NT_STATUS_EQUAL(status,
1433 NT_STATUS_NOT_SUPPORTED)) {
1434 log_lev = 5;
1437 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1438 "connectpath %s, failed - %s.\n",
1439 fsp->conn->connectpath,
1440 nt_errstr(status)));
1441 TALLOC_FREE(shadow_data);
1442 return status;
1445 labels_data_count = (shadow_data->num_volumes * 2 *
1446 sizeof(SHADOW_COPY_LABEL)) + 2;
1448 if (!labels) {
1449 *out_len = 16;
1450 } else {
1451 *out_len = 12 + labels_data_count;
1454 if (max_out_len < *out_len) {
1455 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1456 max_out_len, *out_len));
1457 TALLOC_FREE(shadow_data);
1458 return NT_STATUS_BUFFER_TOO_SMALL;
1461 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1462 if (cur_pdata == NULL) {
1463 TALLOC_FREE(shadow_data);
1464 return NT_STATUS_NO_MEMORY;
1467 *out_data = cur_pdata;
1469 /* num_volumes 4 bytes */
1470 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1472 if (labels) {
1473 /* num_labels 4 bytes */
1474 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1477 /* needed_data_count 4 bytes */
1478 SIVAL(cur_pdata, 8, labels_data_count);
1480 cur_pdata += 12;
1482 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1483 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1484 if (labels && shadow_data->labels) {
1485 for (i=0; i<shadow_data->num_volumes; i++) {
1486 size_t len = 0;
1487 status = srvstr_push(cur_pdata, req_flags,
1488 cur_pdata, shadow_data->labels[i],
1489 2 * sizeof(SHADOW_COPY_LABEL),
1490 STR_UNICODE|STR_TERMINATE, &len);
1491 if (!NT_STATUS_IS_OK(status)) {
1492 TALLOC_FREE(*out_data);
1493 TALLOC_FREE(shadow_data);
1494 return status;
1496 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1497 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1501 TALLOC_FREE(shadow_data);
1503 return NT_STATUS_OK;
1506 case FSCTL_FIND_FILES_BY_SID:
1508 /* pretend this succeeded -
1510 * we have to send back a list with all files owned by this SID
1512 * but I have to check that --metze
1514 ssize_t ret;
1515 struct dom_sid sid;
1516 struct dom_sid_buf buf;
1517 uid_t uid;
1518 size_t sid_len;
1520 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1521 fsp_fnum_dbg(fsp)));
1523 if (in_len < 8) {
1524 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1525 return NT_STATUS_INVALID_PARAMETER;
1528 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1530 /* unknown 4 bytes: this is not the length of the sid :-( */
1531 /*unknown = IVAL(pdata,0);*/
1533 ret = sid_parse(_in_data + 4, sid_len, &sid);
1534 if (ret == -1) {
1535 return NT_STATUS_INVALID_PARAMETER;
1537 DEBUGADD(10, ("for SID: %s\n",
1538 dom_sid_str_buf(&sid, &buf)));
1540 if (!sid_to_uid(&sid, &uid)) {
1541 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1542 dom_sid_str_buf(&sid, &buf),
1543 (unsigned long)sid_len));
1544 uid = (-1);
1547 /* we can take a look at the find source :-)
1549 * find ./ -uid $uid -name '*' is what we need here
1552 * and send 4bytes len and then NULL terminated unicode strings
1553 * for each file
1555 * but I don't know how to deal with the paged results
1556 * (maybe we can hang the result anywhere in the fsp struct)
1558 * but I don't know how to deal with the paged results
1559 * (maybe we can hang the result anywhere in the fsp struct)
1561 * we don't send all files at once
1562 * and at the next we should *not* start from the beginning,
1563 * so we have to cache the result
1565 * --metze
1568 /* this works for now... */
1569 return NT_STATUS_OK;
1572 case FSCTL_QUERY_ALLOCATED_RANGES:
1574 /* FIXME: This is just a dummy reply, telling that all of the
1575 * file is allocated. MKS cp needs that.
1576 * Adding the real allocated ranges via FIEMAP on Linux
1577 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1578 * this FSCTL correct for sparse files.
1580 uint64_t offset, length;
1581 char *out_data_tmp = NULL;
1583 if (in_len != 16) {
1584 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1585 in_len));
1586 return NT_STATUS_INVALID_PARAMETER;
1589 if (max_out_len < 16) {
1590 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1591 max_out_len));
1592 return NT_STATUS_INVALID_PARAMETER;
1595 offset = BVAL(in_data,0);
1596 length = BVAL(in_data,8);
1598 if (offset + length < offset) {
1599 /* No 64-bit integer wrap. */
1600 return NT_STATUS_INVALID_PARAMETER;
1603 /* Shouldn't this be SMB_VFS_STAT ... ? */
1604 status = vfs_stat_fsp(fsp);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 return status;
1609 *out_len = 16;
1610 out_data_tmp = talloc_array(ctx, char, *out_len);
1611 if (out_data_tmp == NULL) {
1612 DEBUG(10, ("unable to allocate memory for response\n"));
1613 return NT_STATUS_NO_MEMORY;
1616 if (offset > fsp->fsp_name->st.st_ex_size ||
1617 fsp->fsp_name->st.st_ex_size == 0 ||
1618 length == 0) {
1619 memset(out_data_tmp, 0, *out_len);
1620 } else {
1621 uint64_t end = offset + length;
1622 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1623 SBVAL(out_data_tmp, 0, 0);
1624 SBVAL(out_data_tmp, 8, end);
1627 *out_data = out_data_tmp;
1629 return NT_STATUS_OK;
1632 case FSCTL_IS_VOLUME_DIRTY:
1634 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1635 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1637 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1638 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1640 return NT_STATUS_INVALID_PARAMETER;
1643 default:
1645 * Only print once ... unfortunately there could be lots of
1646 * different FSCTLs that are called.
1648 if (!vfswrap_logged_ioctl_message) {
1649 vfswrap_logged_ioctl_message = true;
1650 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1651 __func__, function));
1655 return NT_STATUS_NOT_SUPPORTED;
1658 static bool vfswrap_is_offline(struct connection_struct *conn,
1659 const struct smb_filename *fname);
1661 static NTSTATUS vfswrap_get_dos_attributes(struct vfs_handle_struct *handle,
1662 struct smb_filename *smb_fname,
1663 uint32_t *dosmode)
1665 bool offline;
1667 offline = vfswrap_is_offline(handle->conn, smb_fname);
1668 if (offline) {
1669 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1672 return get_ea_dos_attribute(handle->conn, smb_fname, dosmode);
1675 struct vfswrap_get_dos_attributes_state {
1676 struct vfs_aio_state aio_state;
1677 connection_struct *conn;
1678 TALLOC_CTX *mem_ctx;
1679 struct tevent_context *ev;
1680 files_struct *dir_fsp;
1681 struct smb_filename *smb_fname;
1682 uint32_t dosmode;
1683 bool as_root;
1686 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1688 static struct tevent_req *vfswrap_get_dos_attributes_send(
1689 TALLOC_CTX *mem_ctx,
1690 struct tevent_context *ev,
1691 struct vfs_handle_struct *handle,
1692 files_struct *dir_fsp,
1693 struct smb_filename *smb_fname)
1695 struct tevent_req *req = NULL;
1696 struct tevent_req *subreq = NULL;
1697 struct vfswrap_get_dos_attributes_state *state = NULL;
1699 req = tevent_req_create(mem_ctx, &state,
1700 struct vfswrap_get_dos_attributes_state);
1701 if (req == NULL) {
1702 return NULL;
1705 *state = (struct vfswrap_get_dos_attributes_state) {
1706 .conn = dir_fsp->conn,
1707 .mem_ctx = mem_ctx,
1708 .ev = ev,
1709 .dir_fsp = dir_fsp,
1710 .smb_fname = smb_fname,
1713 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1715 dir_fsp,
1716 smb_fname,
1717 SAMBA_XATTR_DOS_ATTRIB,
1718 sizeof(fstring));
1719 if (tevent_req_nomem(subreq, req)) {
1720 return tevent_req_post(req, ev);
1722 tevent_req_set_callback(subreq,
1723 vfswrap_get_dos_attributes_getxattr_done,
1724 req);
1726 return req;
1729 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1731 struct tevent_req *req =
1732 tevent_req_callback_data(subreq,
1733 struct tevent_req);
1734 struct vfswrap_get_dos_attributes_state *state =
1735 tevent_req_data(req,
1736 struct vfswrap_get_dos_attributes_state);
1737 ssize_t xattr_size;
1738 DATA_BLOB blob = {0};
1739 char *path = NULL;
1740 char *tofree = NULL;
1741 char pathbuf[PATH_MAX+1];
1742 ssize_t pathlen;
1743 struct smb_filename smb_fname;
1744 bool offline;
1745 NTSTATUS status;
1747 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1748 &state->aio_state,
1749 state,
1750 &blob.data);
1751 TALLOC_FREE(subreq);
1752 if (xattr_size == -1) {
1753 status = map_nt_error_from_unix(state->aio_state.error);
1755 if (state->as_root) {
1756 tevent_req_nterror(req, status);
1757 return;
1759 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1760 tevent_req_nterror(req, status);
1761 return;
1764 state->as_root = true;
1766 become_root();
1767 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1768 state->ev,
1769 state->dir_fsp,
1770 state->smb_fname,
1771 SAMBA_XATTR_DOS_ATTRIB,
1772 sizeof(fstring));
1773 unbecome_root();
1774 if (tevent_req_nomem(subreq, req)) {
1775 return;
1777 tevent_req_set_callback(subreq,
1778 vfswrap_get_dos_attributes_getxattr_done,
1779 req);
1780 return;
1783 blob.length = xattr_size;
1785 status = parse_dos_attribute_blob(state->smb_fname,
1786 blob,
1787 &state->dosmode);
1788 if (!NT_STATUS_IS_OK(status)) {
1789 tevent_req_nterror(req, status);
1790 return;
1793 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1794 state->smb_fname->base_name,
1795 pathbuf,
1796 sizeof(pathbuf),
1797 &path,
1798 &tofree);
1799 if (pathlen == -1) {
1800 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1801 return;
1804 smb_fname = (struct smb_filename) {
1805 .base_name = path,
1806 .st = state->smb_fname->st,
1807 .flags = state->smb_fname->flags,
1808 .twrp = state->smb_fname->twrp,
1811 offline = vfswrap_is_offline(state->conn, &smb_fname);
1812 if (offline) {
1813 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1815 TALLOC_FREE(tofree);
1817 tevent_req_done(req);
1818 return;
1821 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1822 struct vfs_aio_state *aio_state,
1823 uint32_t *dosmode)
1825 struct vfswrap_get_dos_attributes_state *state =
1826 tevent_req_data(req,
1827 struct vfswrap_get_dos_attributes_state);
1828 NTSTATUS status;
1830 if (tevent_req_is_nterror(req, &status)) {
1831 tevent_req_received(req);
1832 return status;
1835 *aio_state = state->aio_state;
1836 *dosmode = state->dosmode;
1837 tevent_req_received(req);
1838 return NT_STATUS_OK;
1841 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1842 struct files_struct *fsp,
1843 uint32_t *dosmode)
1845 bool offline;
1847 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1848 if (offline) {
1849 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1852 return get_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1855 static NTSTATUS vfswrap_set_dos_attributes(struct vfs_handle_struct *handle,
1856 const struct smb_filename *smb_fname,
1857 uint32_t dosmode)
1859 return set_ea_dos_attribute(handle->conn, smb_fname, dosmode);
1862 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1863 struct files_struct *fsp,
1864 uint32_t dosmode)
1866 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1869 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1871 struct vfswrap_offload_read_state {
1872 DATA_BLOB token;
1875 static struct tevent_req *vfswrap_offload_read_send(
1876 TALLOC_CTX *mem_ctx,
1877 struct tevent_context *ev,
1878 struct vfs_handle_struct *handle,
1879 struct files_struct *fsp,
1880 uint32_t fsctl,
1881 uint32_t ttl,
1882 off_t offset,
1883 size_t to_copy)
1885 struct tevent_req *req = NULL;
1886 struct vfswrap_offload_read_state *state = NULL;
1887 NTSTATUS status;
1889 req = tevent_req_create(mem_ctx, &state,
1890 struct vfswrap_offload_read_state);
1891 if (req == NULL) {
1892 return NULL;
1895 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
1896 &vfswrap_offload_ctx);
1897 if (tevent_req_nterror(req, status)) {
1898 return tevent_req_post(req, ev);
1901 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
1902 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
1903 return tevent_req_post(req, ev);
1906 status = vfs_offload_token_create_blob(state, fsp, fsctl,
1907 &state->token);
1908 if (tevent_req_nterror(req, status)) {
1909 return tevent_req_post(req, ev);
1912 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
1913 &state->token);
1914 if (tevent_req_nterror(req, status)) {
1915 return tevent_req_post(req, ev);
1918 tevent_req_done(req);
1919 return tevent_req_post(req, ev);
1922 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
1923 struct vfs_handle_struct *handle,
1924 TALLOC_CTX *mem_ctx,
1925 DATA_BLOB *token)
1927 struct vfswrap_offload_read_state *state = tevent_req_data(
1928 req, struct vfswrap_offload_read_state);
1929 NTSTATUS status;
1931 if (tevent_req_is_nterror(req, &status)) {
1932 tevent_req_received(req);
1933 return status;
1936 token->length = state->token.length;
1937 token->data = talloc_move(mem_ctx, &state->token.data);
1939 tevent_req_received(req);
1940 return NT_STATUS_OK;
1943 struct vfswrap_offload_write_state {
1944 uint8_t *buf;
1945 bool read_lck_locked;
1946 bool write_lck_locked;
1947 DATA_BLOB *token;
1948 struct tevent_context *src_ev;
1949 struct files_struct *src_fsp;
1950 off_t src_off;
1951 struct tevent_context *dst_ev;
1952 struct files_struct *dst_fsp;
1953 off_t dst_off;
1954 off_t to_copy;
1955 off_t remaining;
1956 size_t next_io_size;
1959 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
1960 enum tevent_req_state req_state)
1962 struct vfswrap_offload_write_state *state = tevent_req_data(
1963 req, struct vfswrap_offload_write_state);
1964 bool ok;
1966 if (state->dst_fsp == NULL) {
1967 return;
1970 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
1971 SMB_ASSERT(ok);
1972 state->dst_fsp = NULL;
1975 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
1977 static struct tevent_req *vfswrap_offload_write_send(
1978 struct vfs_handle_struct *handle,
1979 TALLOC_CTX *mem_ctx,
1980 struct tevent_context *ev,
1981 uint32_t fsctl,
1982 DATA_BLOB *token,
1983 off_t transfer_offset,
1984 struct files_struct *dest_fsp,
1985 off_t dest_off,
1986 off_t to_copy)
1988 struct tevent_req *req;
1989 struct vfswrap_offload_write_state *state = NULL;
1990 /* off_t is signed! */
1991 off_t max_offset = INT64_MAX - to_copy;
1992 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
1993 files_struct *src_fsp = NULL;
1994 NTSTATUS status;
1995 bool ok;
1997 req = tevent_req_create(mem_ctx, &state,
1998 struct vfswrap_offload_write_state);
1999 if (req == NULL) {
2000 return NULL;
2003 *state = (struct vfswrap_offload_write_state) {
2004 .token = token,
2005 .src_off = transfer_offset,
2006 .dst_ev = ev,
2007 .dst_fsp = dest_fsp,
2008 .dst_off = dest_off,
2009 .to_copy = to_copy,
2010 .remaining = to_copy,
2013 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2015 switch (fsctl) {
2016 case FSCTL_SRV_COPYCHUNK:
2017 case FSCTL_SRV_COPYCHUNK_WRITE:
2018 break;
2020 case FSCTL_OFFLOAD_WRITE:
2021 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2022 return tevent_req_post(req, ev);
2024 case FSCTL_DUP_EXTENTS_TO_FILE:
2025 DBG_DEBUG("COW clones not supported by vfs_default\n");
2026 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2027 return tevent_req_post(req, ev);
2029 default:
2030 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2031 return tevent_req_post(req, ev);
2035 * From here on we assume a copy-chunk fsctl
2038 if (to_copy == 0) {
2039 tevent_req_done(req);
2040 return tevent_req_post(req, ev);
2043 if (state->src_off > max_offset) {
2045 * Protect integer checks below.
2047 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2048 return tevent_req_post(req, ev);
2050 if (state->src_off < 0) {
2052 * Protect integer checks below.
2054 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2055 return tevent_req_post(req, ev);
2057 if (state->dst_off > max_offset) {
2059 * Protect integer checks below.
2061 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2062 return tevent_req_post(req, ev);
2064 if (state->dst_off < 0) {
2066 * Protect integer checks below.
2068 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2069 return tevent_req_post(req, ev);
2072 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2073 token, &src_fsp);
2074 if (tevent_req_nterror(req, status)) {
2075 return tevent_req_post(req, ev);
2078 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2080 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2081 if (!NT_STATUS_IS_OK(status)) {
2082 tevent_req_nterror(req, status);
2083 return tevent_req_post(req, ev);
2086 ok = change_to_user_and_service_by_fsp(src_fsp);
2087 if (!ok) {
2088 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2089 return tevent_req_post(req, ev);
2092 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2093 state->src_fsp = src_fsp;
2095 status = vfs_stat_fsp(src_fsp);
2096 if (tevent_req_nterror(req, status)) {
2097 return tevent_req_post(req, ev);
2100 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2102 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2103 * If the SourceOffset or SourceOffset + Length extends beyond
2104 * the end of file, the server SHOULD<240> treat this as a
2105 * STATUS_END_OF_FILE error.
2106 * ...
2107 * <240> Section 3.3.5.15.6: Windows servers will return
2108 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2110 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2111 return tevent_req_post(req, ev);
2114 state->buf = talloc_array(state, uint8_t, num);
2115 if (tevent_req_nomem(state->buf, req)) {
2116 return tevent_req_post(req, ev);
2119 status = vfswrap_offload_write_loop(req);
2120 if (!NT_STATUS_IS_OK(status)) {
2121 tevent_req_nterror(req, status);
2122 return tevent_req_post(req, ev);
2125 return req;
2128 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2130 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2132 struct vfswrap_offload_write_state *state = tevent_req_data(
2133 req, struct vfswrap_offload_write_state);
2134 struct tevent_req *subreq = NULL;
2135 struct lock_struct read_lck;
2136 bool ok;
2139 * This is called under the context of state->src_fsp.
2142 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2144 init_strict_lock_struct(state->src_fsp,
2145 state->src_fsp->op->global->open_persistent_id,
2146 state->src_off,
2147 state->next_io_size,
2148 READ_LOCK,
2149 &read_lck);
2151 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2152 state->src_fsp,
2153 &read_lck);
2154 if (!ok) {
2155 return NT_STATUS_FILE_LOCK_CONFLICT;
2158 subreq = SMB_VFS_PREAD_SEND(state,
2159 state->src_ev,
2160 state->src_fsp,
2161 state->buf,
2162 state->next_io_size,
2163 state->src_off);
2164 if (subreq == NULL) {
2165 return NT_STATUS_NO_MEMORY;
2167 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2169 return NT_STATUS_OK;
2172 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2174 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2176 struct tevent_req *req = tevent_req_callback_data(
2177 subreq, struct tevent_req);
2178 struct vfswrap_offload_write_state *state = tevent_req_data(
2179 req, struct vfswrap_offload_write_state);
2180 struct vfs_aio_state aio_state;
2181 struct lock_struct write_lck;
2182 ssize_t nread;
2183 bool ok;
2185 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2186 TALLOC_FREE(subreq);
2187 if (nread == -1) {
2188 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2189 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2190 return;
2192 if (nread != state->next_io_size) {
2193 DBG_ERR("Short read, only %zd of %zu\n",
2194 nread, state->next_io_size);
2195 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2196 return;
2199 state->src_off += nread;
2201 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2202 if (!ok) {
2203 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2204 return;
2207 init_strict_lock_struct(state->dst_fsp,
2208 state->dst_fsp->op->global->open_persistent_id,
2209 state->dst_off,
2210 state->next_io_size,
2211 WRITE_LOCK,
2212 &write_lck);
2214 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2215 state->dst_fsp,
2216 &write_lck);
2217 if (!ok) {
2218 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2219 return;
2222 subreq = SMB_VFS_PWRITE_SEND(state,
2223 state->dst_ev,
2224 state->dst_fsp,
2225 state->buf,
2226 state->next_io_size,
2227 state->dst_off);
2228 if (subreq == NULL) {
2229 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2230 return;
2232 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2235 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2237 struct tevent_req *req = tevent_req_callback_data(
2238 subreq, struct tevent_req);
2239 struct vfswrap_offload_write_state *state = tevent_req_data(
2240 req, struct vfswrap_offload_write_state);
2241 struct vfs_aio_state aio_state;
2242 ssize_t nwritten;
2243 NTSTATUS status;
2244 bool ok;
2246 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2247 TALLOC_FREE(subreq);
2248 if (nwritten == -1) {
2249 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2250 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2251 return;
2253 if (nwritten != state->next_io_size) {
2254 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2255 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2256 return;
2259 state->dst_off += nwritten;
2261 if (state->remaining < nwritten) {
2262 /* Paranoia check */
2263 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2264 return;
2266 state->remaining -= nwritten;
2267 if (state->remaining == 0) {
2268 tevent_req_done(req);
2269 return;
2272 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2273 if (!ok) {
2274 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2275 return;
2278 status = vfswrap_offload_write_loop(req);
2279 if (!NT_STATUS_IS_OK(status)) {
2280 tevent_req_nterror(req, status);
2281 return;
2284 return;
2287 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2288 struct tevent_req *req,
2289 off_t *copied)
2291 struct vfswrap_offload_write_state *state = tevent_req_data(
2292 req, struct vfswrap_offload_write_state);
2293 NTSTATUS status;
2295 if (tevent_req_is_nterror(req, &status)) {
2296 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2297 *copied = 0;
2298 tevent_req_received(req);
2299 return status;
2302 *copied = state->to_copy;
2303 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2304 tevent_req_received(req);
2306 return NT_STATUS_OK;
2309 static NTSTATUS vfswrap_get_compression(struct vfs_handle_struct *handle,
2310 TALLOC_CTX *mem_ctx,
2311 struct files_struct *fsp,
2312 struct smb_filename *smb_fname,
2313 uint16_t *_compression_fmt)
2315 return NT_STATUS_INVALID_DEVICE_REQUEST;
2318 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2319 TALLOC_CTX *mem_ctx,
2320 struct files_struct *fsp,
2321 uint16_t compression_fmt)
2323 return NT_STATUS_INVALID_DEVICE_REQUEST;
2326 /********************************************************************
2327 Given a stat buffer return the allocated size on disk, taking into
2328 account sparse files.
2329 ********************************************************************/
2330 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2331 struct files_struct *fsp,
2332 const SMB_STRUCT_STAT *sbuf)
2334 uint64_t result;
2336 START_PROFILE(syscall_get_alloc_size);
2338 if(S_ISDIR(sbuf->st_ex_mode)) {
2339 result = 0;
2340 goto out;
2343 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2344 /* The type of st_blocksize is blkcnt_t which *MUST* be
2345 signed (according to POSIX) and can be less than 64-bits.
2346 Ensure when we're converting to 64 bits wide we don't
2347 sign extend. */
2348 #if defined(SIZEOF_BLKCNT_T_8)
2349 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2350 #elif defined(SIZEOF_BLKCNT_T_4)
2352 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2353 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2355 #else
2356 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2357 #endif
2358 if (result == 0) {
2360 * Some file systems do not allocate a block for very
2361 * small files. But for non-empty file should report a
2362 * positive size.
2365 uint64_t filesize = get_file_size_stat(sbuf);
2366 if (filesize > 0) {
2367 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2370 #else
2371 result = get_file_size_stat(sbuf);
2372 #endif
2374 if (fsp && fsp->initial_allocation_size)
2375 result = MAX(result,fsp->initial_allocation_size);
2377 result = smb_roundup(handle->conn, result);
2379 out:
2380 END_PROFILE(syscall_get_alloc_size);
2381 return result;
2384 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2385 struct files_struct *dirfsp,
2386 const struct smb_filename *smb_fname,
2387 int flags)
2389 int result = -1;
2391 START_PROFILE(syscall_unlinkat);
2393 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2395 if (is_named_stream(smb_fname)) {
2396 errno = ENOENT;
2397 goto out;
2399 result = unlinkat(dirfsp->fh->fd,
2400 smb_fname->base_name,
2401 flags);
2403 out:
2404 END_PROFILE(syscall_unlinkat);
2405 return result;
2408 static int vfswrap_chmod(vfs_handle_struct *handle,
2409 const struct smb_filename *smb_fname,
2410 mode_t mode)
2412 int result;
2414 START_PROFILE(syscall_chmod);
2415 result = chmod(smb_fname->base_name, mode);
2416 END_PROFILE(syscall_chmod);
2417 return result;
2420 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2422 int result;
2424 START_PROFILE(syscall_fchmod);
2425 #if defined(HAVE_FCHMOD)
2426 result = fchmod(fsp->fh->fd, mode);
2427 #else
2428 result = -1;
2429 errno = ENOSYS;
2430 #endif
2432 END_PROFILE(syscall_fchmod);
2433 return result;
2436 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2438 #ifdef HAVE_FCHOWN
2439 int result;
2441 START_PROFILE(syscall_fchown);
2442 result = fchown(fsp->fh->fd, uid, gid);
2443 END_PROFILE(syscall_fchown);
2444 return result;
2445 #else
2446 errno = ENOSYS;
2447 return -1;
2448 #endif
2451 static int vfswrap_lchown(vfs_handle_struct *handle,
2452 const struct smb_filename *smb_fname,
2453 uid_t uid,
2454 gid_t gid)
2456 int result;
2458 START_PROFILE(syscall_lchown);
2459 result = lchown(smb_fname->base_name, uid, gid);
2460 END_PROFILE(syscall_lchown);
2461 return result;
2464 static int vfswrap_chdir(vfs_handle_struct *handle,
2465 const struct smb_filename *smb_fname)
2467 int result;
2469 START_PROFILE(syscall_chdir);
2470 result = chdir(smb_fname->base_name);
2471 END_PROFILE(syscall_chdir);
2472 return result;
2475 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2476 TALLOC_CTX *ctx)
2478 char *result;
2479 struct smb_filename *smb_fname = NULL;
2481 START_PROFILE(syscall_getwd);
2482 result = sys_getwd();
2483 END_PROFILE(syscall_getwd);
2485 if (result == NULL) {
2486 return NULL;
2488 smb_fname = synthetic_smb_fname(ctx,
2489 result,
2490 NULL,
2491 NULL,
2495 * sys_getwd() *always* returns malloced memory.
2496 * We must free here to avoid leaks:
2497 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2499 SAFE_FREE(result);
2500 return smb_fname;
2503 /*********************************************************************
2504 nsec timestamp resolution call. Convert down to whatever the underlying
2505 system will support.
2506 **********************************************************************/
2508 static int vfswrap_ntimes(vfs_handle_struct *handle,
2509 const struct smb_filename *smb_fname,
2510 struct smb_file_time *ft)
2512 int result = -1;
2514 START_PROFILE(syscall_ntimes);
2516 if (is_named_stream(smb_fname)) {
2517 errno = ENOENT;
2518 goto out;
2521 if (ft != NULL) {
2522 if (is_omit_timespec(&ft->atime)) {
2523 ft->atime= smb_fname->st.st_ex_atime;
2526 if (is_omit_timespec(&ft->mtime)) {
2527 ft->mtime = smb_fname->st.st_ex_mtime;
2530 if (!is_omit_timespec(&ft->create_time)) {
2531 set_create_timespec_ea(handle->conn,
2532 smb_fname,
2533 ft->create_time);
2536 if ((timespec_compare(&ft->atime,
2537 &smb_fname->st.st_ex_atime) == 0) &&
2538 (timespec_compare(&ft->mtime,
2539 &smb_fname->st.st_ex_mtime) == 0)) {
2540 return 0;
2544 #if defined(HAVE_UTIMENSAT)
2545 if (ft != NULL) {
2546 struct timespec ts[2];
2547 ts[0] = ft->atime;
2548 ts[1] = ft->mtime;
2549 result = utimensat(AT_FDCWD, smb_fname->base_name, ts, 0);
2550 } else {
2551 result = utimensat(AT_FDCWD, smb_fname->base_name, NULL, 0);
2553 if (!((result == -1) && (errno == ENOSYS))) {
2554 goto out;
2556 #endif
2557 #if defined(HAVE_UTIMES)
2558 if (ft != NULL) {
2559 struct timeval tv[2];
2560 tv[0] = convert_timespec_to_timeval(ft->atime);
2561 tv[1] = convert_timespec_to_timeval(ft->mtime);
2562 result = utimes(smb_fname->base_name, tv);
2563 } else {
2564 result = utimes(smb_fname->base_name, NULL);
2566 if (!((result == -1) && (errno == ENOSYS))) {
2567 goto out;
2569 #endif
2570 #if defined(HAVE_UTIME)
2571 if (ft != NULL) {
2572 struct utimbuf times;
2573 times.actime = convert_timespec_to_time_t(ft->atime);
2574 times.modtime = convert_timespec_to_time_t(ft->mtime);
2575 result = utime(smb_fname->base_name, &times);
2576 } else {
2577 result = utime(smb_fname->base_name, NULL);
2579 if (!((result == -1) && (errno == ENOSYS))) {
2580 goto out;
2582 #endif
2583 errno = ENOSYS;
2584 result = -1;
2586 out:
2587 END_PROFILE(syscall_ntimes);
2588 return result;
2591 /*********************************************************************
2592 A version of ftruncate that will write the space on disk if strict
2593 allocate is set.
2594 **********************************************************************/
2596 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2598 off_t space_to_write;
2599 uint64_t space_avail;
2600 uint64_t bsize,dfree,dsize;
2601 int ret;
2602 NTSTATUS status;
2603 SMB_STRUCT_STAT *pst;
2604 bool ok;
2606 ok = vfs_valid_pwrite_range(len, 0);
2607 if (!ok) {
2608 errno = EINVAL;
2609 return -1;
2612 status = vfs_stat_fsp(fsp);
2613 if (!NT_STATUS_IS_OK(status)) {
2614 return -1;
2616 pst = &fsp->fsp_name->st;
2618 #ifdef S_ISFIFO
2619 if (S_ISFIFO(pst->st_ex_mode))
2620 return 0;
2621 #endif
2623 if (pst->st_ex_size == len)
2624 return 0;
2626 /* Shrink - just ftruncate. */
2627 if (pst->st_ex_size > len)
2628 return ftruncate(fsp->fh->fd, len);
2630 space_to_write = len - pst->st_ex_size;
2632 /* for allocation try fallocate first. This can fail on some
2633 platforms e.g. when the filesystem doesn't support it and no
2634 emulation is being done by the libc (like on AIX with JFS1). In that
2635 case we do our own emulation. fallocate implementations can
2636 return ENOTSUP or EINVAL in cases like that. */
2637 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2638 if (ret == -1 && errno == ENOSPC) {
2639 return -1;
2641 if (ret == 0) {
2642 return 0;
2644 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2645 "error %d. Falling back to slow manual allocation\n", errno));
2647 /* available disk space is enough or not? */
2648 space_avail =
2649 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2650 /* space_avail is 1k blocks */
2651 if (space_avail == (uint64_t)-1 ||
2652 ((uint64_t)space_to_write/1024 > space_avail) ) {
2653 errno = ENOSPC;
2654 return -1;
2657 /* Write out the real space on disk. */
2658 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2659 if (ret != 0) {
2660 return -1;
2663 return 0;
2666 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2668 int result = -1;
2669 SMB_STRUCT_STAT *pst;
2670 NTSTATUS status;
2671 char c = 0;
2673 START_PROFILE(syscall_ftruncate);
2675 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2676 result = strict_allocate_ftruncate(handle, fsp, len);
2677 END_PROFILE(syscall_ftruncate);
2678 return result;
2681 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2682 ftruncate if the system supports it. Then I discovered that
2683 you can have some filesystems that support ftruncate
2684 expansion and some that don't! On Linux fat can't do
2685 ftruncate extend but ext2 can. */
2687 result = ftruncate(fsp->fh->fd, len);
2689 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2690 extend a file with ftruncate. Provide alternate implementation
2691 for this */
2693 /* Do an fstat to see if the file is longer than the requested
2694 size in which case the ftruncate above should have
2695 succeeded or shorter, in which case seek to len - 1 and
2696 write 1 byte of zero */
2697 status = vfs_stat_fsp(fsp);
2698 if (!NT_STATUS_IS_OK(status)) {
2699 goto done;
2702 /* We need to update the files_struct after successful ftruncate */
2703 if (result == 0) {
2704 goto done;
2707 pst = &fsp->fsp_name->st;
2709 #ifdef S_ISFIFO
2710 if (S_ISFIFO(pst->st_ex_mode)) {
2711 result = 0;
2712 goto done;
2714 #endif
2716 if (pst->st_ex_size == len) {
2717 result = 0;
2718 goto done;
2721 if (pst->st_ex_size > len) {
2722 /* the ftruncate should have worked */
2723 goto done;
2726 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
2727 goto done;
2730 result = 0;
2732 done:
2734 END_PROFILE(syscall_ftruncate);
2735 return result;
2738 static int vfswrap_fallocate(vfs_handle_struct *handle,
2739 files_struct *fsp,
2740 uint32_t mode,
2741 off_t offset,
2742 off_t len)
2744 int result;
2746 START_PROFILE(syscall_fallocate);
2747 if (mode == 0) {
2748 result = sys_posix_fallocate(fsp->fh->fd, offset, len);
2750 * posix_fallocate returns 0 on success, errno on error
2751 * and doesn't set errno. Make it behave like fallocate()
2752 * which returns -1, and sets errno on failure.
2754 if (result != 0) {
2755 errno = result;
2756 result = -1;
2758 } else {
2759 /* sys_fallocate handles filtering of unsupported mode flags */
2760 result = sys_fallocate(fsp->fh->fd, mode, offset, len);
2762 END_PROFILE(syscall_fallocate);
2763 return result;
2766 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
2768 bool result;
2770 START_PROFILE(syscall_fcntl_lock);
2772 if (fsp->fsp_flags.use_ofd_locks) {
2773 op = map_process_lock_to_ofd_lock(op);
2776 result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
2777 END_PROFILE(syscall_fcntl_lock);
2778 return result;
2781 static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
2782 uint32_t share_access, uint32_t access_mask)
2784 START_PROFILE(syscall_kernel_flock);
2785 kernel_flock(fsp->fh->fd, share_access, access_mask);
2786 END_PROFILE(syscall_kernel_flock);
2787 return 0;
2790 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
2791 va_list cmd_arg)
2793 void *argp;
2794 va_list dup_cmd_arg;
2795 int result;
2796 int val;
2798 START_PROFILE(syscall_fcntl);
2800 va_copy(dup_cmd_arg, cmd_arg);
2802 switch(cmd) {
2803 case F_SETLK:
2804 case F_SETLKW:
2805 case F_GETLK:
2806 #if defined(HAVE_OFD_LOCKS)
2807 case F_OFD_SETLK:
2808 case F_OFD_SETLKW:
2809 case F_OFD_GETLK:
2810 #endif
2811 #if defined(HAVE_F_OWNER_EX)
2812 case F_GETOWN_EX:
2813 case F_SETOWN_EX:
2814 #endif
2815 #if defined(HAVE_RW_HINTS)
2816 case F_GET_RW_HINT:
2817 case F_SET_RW_HINT:
2818 case F_GET_FILE_RW_HINT:
2819 case F_SET_FILE_RW_HINT:
2820 #endif
2821 argp = va_arg(dup_cmd_arg, void *);
2822 result = sys_fcntl_ptr(fsp->fh->fd, cmd, argp);
2823 break;
2824 default:
2825 val = va_arg(dup_cmd_arg, int);
2826 result = sys_fcntl_int(fsp->fh->fd, cmd, val);
2829 va_end(dup_cmd_arg);
2831 END_PROFILE(syscall_fcntl);
2832 return result;
2835 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
2837 bool result;
2838 int op = F_GETLK;
2840 START_PROFILE(syscall_fcntl_getlock);
2842 if (fsp->fsp_flags.use_ofd_locks) {
2843 op = map_process_lock_to_ofd_lock(op);
2846 result = fcntl_getlock(fsp->fh->fd, op, poffset, pcount, ptype, ppid);
2847 END_PROFILE(syscall_fcntl_getlock);
2848 return result;
2851 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
2852 int leasetype)
2854 int result = -1;
2856 START_PROFILE(syscall_linux_setlease);
2858 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
2859 result = linux_setlease(fsp->fh->fd, leasetype);
2860 #else
2861 errno = ENOSYS;
2862 #endif
2863 END_PROFILE(syscall_linux_setlease);
2864 return result;
2867 static int vfswrap_symlinkat(vfs_handle_struct *handle,
2868 const struct smb_filename *link_target,
2869 struct files_struct *dirfsp,
2870 const struct smb_filename *new_smb_fname)
2872 int result;
2874 START_PROFILE(syscall_symlinkat);
2876 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2878 result = symlinkat(link_target->base_name,
2879 dirfsp->fh->fd,
2880 new_smb_fname->base_name);
2881 END_PROFILE(syscall_symlinkat);
2882 return result;
2885 static int vfswrap_readlinkat(vfs_handle_struct *handle,
2886 files_struct *dirfsp,
2887 const struct smb_filename *smb_fname,
2888 char *buf,
2889 size_t bufsiz)
2891 int result;
2893 START_PROFILE(syscall_readlinkat);
2895 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2897 result = readlinkat(dirfsp->fh->fd,
2898 smb_fname->base_name,
2899 buf,
2900 bufsiz);
2902 END_PROFILE(syscall_readlinkat);
2903 return result;
2906 static int vfswrap_linkat(vfs_handle_struct *handle,
2907 files_struct *srcfsp,
2908 const struct smb_filename *old_smb_fname,
2909 files_struct *dstfsp,
2910 const struct smb_filename *new_smb_fname,
2911 int flags)
2913 int result;
2915 START_PROFILE(syscall_linkat);
2917 SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
2918 SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
2920 result = linkat(srcfsp->fh->fd,
2921 old_smb_fname->base_name,
2922 dstfsp->fh->fd,
2923 new_smb_fname->base_name,
2924 flags);
2926 END_PROFILE(syscall_linkat);
2927 return result;
2930 static int vfswrap_mknodat(vfs_handle_struct *handle,
2931 files_struct *dirfsp,
2932 const struct smb_filename *smb_fname,
2933 mode_t mode,
2934 SMB_DEV_T dev)
2936 int result;
2938 START_PROFILE(syscall_mknodat);
2940 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2942 result = sys_mknodat(dirfsp->fh->fd,
2943 smb_fname->base_name,
2944 mode,
2945 dev);
2947 END_PROFILE(syscall_mknodat);
2948 return result;
2951 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
2952 TALLOC_CTX *ctx,
2953 const struct smb_filename *smb_fname)
2955 char *result;
2956 struct smb_filename *result_fname = NULL;
2958 START_PROFILE(syscall_realpath);
2959 result = sys_realpath(smb_fname->base_name);
2960 END_PROFILE(syscall_realpath);
2961 if (result) {
2962 result_fname = synthetic_smb_fname(ctx,
2963 result,
2964 NULL,
2965 NULL,
2968 SAFE_FREE(result);
2970 return result_fname;
2973 static int vfswrap_chflags(vfs_handle_struct *handle,
2974 const struct smb_filename *smb_fname,
2975 unsigned int flags)
2977 #ifdef HAVE_CHFLAGS
2978 return chflags(smb_fname->base_name, flags);
2979 #else
2980 errno = ENOSYS;
2981 return -1;
2982 #endif
2985 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
2986 const SMB_STRUCT_STAT *sbuf)
2988 struct file_id key;
2990 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
2991 * blob */
2992 ZERO_STRUCT(key);
2994 key.devid = sbuf->st_ex_dev;
2995 key.inode = sbuf->st_ex_ino;
2996 /* key.extid is unused by default. */
2998 return key;
3001 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3002 const SMB_STRUCT_STAT *psbuf)
3004 uint64_t file_id;
3006 if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
3007 return psbuf->st_ex_file_id;
3010 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3011 return (uint64_t)psbuf->st_ex_ino;
3014 /* FileIDLow */
3015 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3017 /* FileIDHigh */
3018 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3020 return file_id;
3023 static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
3024 struct files_struct *fsp,
3025 const struct smb_filename *smb_fname,
3026 TALLOC_CTX *mem_ctx,
3027 unsigned int *pnum_streams,
3028 struct stream_struct **pstreams)
3030 SMB_STRUCT_STAT sbuf;
3031 struct stream_struct *tmp_streams = NULL;
3032 int ret;
3034 if ((fsp != NULL) && (fsp->fsp_flags.is_directory)) {
3036 * No default streams on directories
3038 goto done;
3041 if ((fsp != NULL) && (fsp->fh->fd != -1)) {
3042 ret = SMB_VFS_FSTAT(fsp, &sbuf);
3044 else {
3045 struct smb_filename *smb_fname_cp = NULL;
3047 smb_fname_cp = cp_smb_filename_nostream(talloc_tos(), smb_fname);
3048 if (smb_fname_cp == NULL) {
3049 return NT_STATUS_NO_MEMORY;
3052 if (smb_fname_cp->flags & SMB_FILENAME_POSIX_PATH) {
3053 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_cp);
3054 } else {
3055 ret = SMB_VFS_STAT(handle->conn, smb_fname_cp);
3057 sbuf = smb_fname_cp->st;
3058 TALLOC_FREE(smb_fname_cp);
3061 if (ret == -1) {
3062 return map_nt_error_from_unix(errno);
3065 if (S_ISDIR(sbuf.st_ex_mode)) {
3066 goto done;
3069 tmp_streams = talloc_realloc(mem_ctx, *pstreams, struct stream_struct,
3070 (*pnum_streams) + 1);
3071 if (tmp_streams == NULL) {
3072 return NT_STATUS_NO_MEMORY;
3074 tmp_streams[*pnum_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3075 if (tmp_streams[*pnum_streams].name == NULL) {
3076 return NT_STATUS_NO_MEMORY;
3078 tmp_streams[*pnum_streams].size = sbuf.st_ex_size;
3079 tmp_streams[*pnum_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, &sbuf);
3081 *pnum_streams += 1;
3082 *pstreams = tmp_streams;
3083 done:
3084 return NT_STATUS_OK;
3087 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
3088 const struct smb_filename *path,
3089 const char *name,
3090 TALLOC_CTX *mem_ctx,
3091 char **found_name)
3094 * Don't fall back to get_real_filename so callers can differentiate
3095 * between a full directory scan and an actual case-insensitive stat.
3097 errno = EOPNOTSUPP;
3098 return -1;
3101 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3102 const struct smb_filename *smb_fname)
3104 return handle->conn->connectpath;
3107 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3108 struct byte_range_lock *br_lck,
3109 struct lock_struct *plock)
3111 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3113 /* Note: blr is not used in the default implementation. */
3114 return brl_lock_windows_default(br_lck, plock);
3117 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3118 struct byte_range_lock *br_lck,
3119 const struct lock_struct *plock)
3121 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3123 return brl_unlock_windows_default(br_lck, plock);
3126 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3127 files_struct *fsp,
3128 struct lock_struct *plock)
3130 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3131 plock->lock_type == WRITE_LOCK);
3133 return strict_lock_check_default(fsp, plock);
3136 /* NT ACL operations. */
3138 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3139 files_struct *fsp,
3140 uint32_t security_info,
3141 TALLOC_CTX *mem_ctx,
3142 struct security_descriptor **ppdesc)
3144 NTSTATUS result;
3146 START_PROFILE(fget_nt_acl);
3147 result = posix_fget_nt_acl(fsp, security_info,
3148 mem_ctx, ppdesc);
3149 END_PROFILE(fget_nt_acl);
3150 return result;
3153 static NTSTATUS vfswrap_get_nt_acl_at(vfs_handle_struct *handle,
3154 struct files_struct *dirfsp,
3155 const struct smb_filename *smb_fname,
3156 uint32_t security_info,
3157 TALLOC_CTX *mem_ctx,
3158 struct security_descriptor **ppdesc)
3160 NTSTATUS result;
3162 START_PROFILE(get_nt_acl_at);
3164 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
3166 result = posix_get_nt_acl(handle->conn,
3167 smb_fname,
3168 security_info,
3169 mem_ctx,
3170 ppdesc);
3171 END_PROFILE(get_nt_acl_at);
3172 return result;
3175 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3177 NTSTATUS result;
3179 START_PROFILE(fset_nt_acl);
3180 result = set_nt_acl(fsp, security_info_sent, psd);
3181 END_PROFILE(fset_nt_acl);
3182 return result;
3185 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3186 struct smb_filename *file,
3187 struct security_acl *sacl,
3188 uint32_t access_requested,
3189 uint32_t access_denied)
3191 return NT_STATUS_OK; /* Nothing to do here ... */
3194 static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle,
3195 const struct smb_filename *smb_fname,
3196 SMB_ACL_TYPE_T type,
3197 TALLOC_CTX *mem_ctx)
3199 return sys_acl_get_file(handle, smb_fname, type, mem_ctx);
3202 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3203 files_struct *fsp,
3204 TALLOC_CTX *mem_ctx)
3206 return sys_acl_get_fd(handle, fsp, mem_ctx);
3209 static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle,
3210 const struct smb_filename *smb_fname,
3211 SMB_ACL_TYPE_T acltype,
3212 SMB_ACL_T theacl)
3214 return sys_acl_set_file(handle, smb_fname, acltype, theacl);
3217 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
3219 return sys_acl_set_fd(handle, fsp, theacl);
3222 static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle,
3223 const struct smb_filename *smb_fname)
3225 return sys_acl_delete_def_file(handle, smb_fname);
3228 /****************************************************************
3229 Extended attribute operations.
3230 *****************************************************************/
3232 static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,
3233 const struct smb_filename *smb_fname,
3234 const char *name,
3235 void *value,
3236 size_t size)
3238 return getxattr(smb_fname->base_name, name, value, size);
3241 struct vfswrap_getxattrat_state {
3242 struct tevent_context *ev;
3243 files_struct *dir_fsp;
3244 const struct smb_filename *smb_fname;
3247 * The following variables are talloced off "state" which is protected
3248 * by a destructor and thus are guaranteed to be safe to be used in the
3249 * job function in the worker thread.
3251 char *name;
3252 const char *xattr_name;
3253 uint8_t *xattr_value;
3254 struct security_unix_token *token;
3256 ssize_t xattr_size;
3257 struct vfs_aio_state vfs_aio_state;
3258 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3261 static int vfswrap_getxattrat_state_destructor(
3262 struct vfswrap_getxattrat_state *state)
3264 return -1;
3267 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3268 static void vfswrap_getxattrat_do_async(void *private_data);
3269 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3271 static struct tevent_req *vfswrap_getxattrat_send(
3272 TALLOC_CTX *mem_ctx,
3273 struct tevent_context *ev,
3274 struct vfs_handle_struct *handle,
3275 files_struct *dir_fsp,
3276 const struct smb_filename *smb_fname,
3277 const char *xattr_name,
3278 size_t alloc_hint)
3280 struct tevent_req *req = NULL;
3281 struct tevent_req *subreq = NULL;
3282 struct vfswrap_getxattrat_state *state = NULL;
3283 size_t max_threads = 0;
3284 bool have_per_thread_cwd = false;
3285 bool have_per_thread_creds = false;
3286 bool do_async = false;
3288 req = tevent_req_create(mem_ctx, &state,
3289 struct vfswrap_getxattrat_state);
3290 if (req == NULL) {
3291 return NULL;
3293 *state = (struct vfswrap_getxattrat_state) {
3294 .ev = ev,
3295 .dir_fsp = dir_fsp,
3296 .smb_fname = smb_fname,
3299 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3300 if (max_threads >= 1) {
3302 * We need a non sync threadpool!
3304 have_per_thread_cwd = per_thread_cwd_supported();
3306 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3307 have_per_thread_creds = true;
3308 #endif
3309 if (have_per_thread_cwd && have_per_thread_creds) {
3310 do_async = true;
3313 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3314 state->profile_bytes, 0);
3316 if (dir_fsp->fh->fd == -1) {
3317 DBG_ERR("Need a valid directory fd\n");
3318 tevent_req_error(req, EINVAL);
3319 return tevent_req_post(req, ev);
3322 if (alloc_hint > 0) {
3323 state->xattr_value = talloc_zero_array(state,
3324 uint8_t,
3325 alloc_hint);
3326 if (tevent_req_nomem(state->xattr_value, req)) {
3327 return tevent_req_post(req, ev);
3331 if (!do_async) {
3332 vfswrap_getxattrat_do_sync(req);
3333 return tevent_req_post(req, ev);
3337 * Now allocate all parameters from a memory context that won't go away
3338 * no matter what. These paremeters will get used in threads and we
3339 * can't reliably cancel threads, so all buffers passed to the threads
3340 * must not be freed before all referencing threads terminate.
3343 state->name = talloc_strdup(state, smb_fname->base_name);
3344 if (tevent_req_nomem(state->name, req)) {
3345 return tevent_req_post(req, ev);
3348 state->xattr_name = talloc_strdup(state, xattr_name);
3349 if (tevent_req_nomem(state->xattr_name, req)) {
3350 return tevent_req_post(req, ev);
3354 * This is a hot codepath so at first glance one might think we should
3355 * somehow optimize away the token allocation and do a
3356 * talloc_reference() or similar black magic instead. But due to the
3357 * talloc_stackframe pool per SMB2 request this should be a simple copy
3358 * without a malloc in most cases.
3360 if (geteuid() == sec_initial_uid()) {
3361 state->token = root_unix_token(state);
3362 } else {
3363 state->token = copy_unix_token(
3364 state,
3365 dir_fsp->conn->session_info->unix_token);
3367 if (tevent_req_nomem(state->token, req)) {
3368 return tevent_req_post(req, ev);
3371 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3373 subreq = pthreadpool_tevent_job_send(
3374 state,
3376 dir_fsp->conn->sconn->pool,
3377 vfswrap_getxattrat_do_async,
3378 state);
3379 if (tevent_req_nomem(subreq, req)) {
3380 return tevent_req_post(req, ev);
3382 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3384 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3386 return req;
3389 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3391 struct vfswrap_getxattrat_state *state = tevent_req_data(
3392 req, struct vfswrap_getxattrat_state);
3393 char *path = NULL;
3394 char *tofree = NULL;
3395 char pathbuf[PATH_MAX+1];
3396 ssize_t pathlen;
3397 int err;
3399 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
3400 state->smb_fname->base_name,
3401 pathbuf,
3402 sizeof(pathbuf),
3403 &path,
3404 &tofree);
3405 if (pathlen == -1) {
3406 tevent_req_error(req, ENOMEM);
3407 return;
3410 state->xattr_size = getxattr(path,
3411 state->xattr_name,
3412 state->xattr_value,
3413 talloc_array_length(state->xattr_value));
3414 err = errno;
3415 TALLOC_FREE(tofree);
3416 if (state->xattr_size == -1) {
3417 tevent_req_error(req, err);
3418 return;
3421 tevent_req_done(req);
3422 return;
3425 static void vfswrap_getxattrat_do_async(void *private_data)
3427 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3428 private_data, struct vfswrap_getxattrat_state);
3429 struct timespec start_time;
3430 struct timespec end_time;
3431 int ret;
3433 PROFILE_TIMESTAMP(&start_time);
3434 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3437 * Here we simulate a getxattrat()
3438 * call using fchdir();getxattr()
3441 per_thread_cwd_activate();
3443 /* Become the correct credential on this thread. */
3444 ret = set_thread_credentials(state->token->uid,
3445 state->token->gid,
3446 (size_t)state->token->ngroups,
3447 state->token->groups);
3448 if (ret != 0) {
3449 state->xattr_size = -1;
3450 state->vfs_aio_state.error = errno;
3451 goto end_profile;
3454 ret = fchdir(state->dir_fsp->fh->fd);
3455 if (ret == -1) {
3456 state->xattr_size = -1;
3457 state->vfs_aio_state.error = errno;
3458 goto end_profile;
3461 state->xattr_size = getxattr(state->name,
3462 state->xattr_name,
3463 state->xattr_value,
3464 talloc_array_length(state->xattr_value));
3465 if (state->xattr_size == -1) {
3466 state->vfs_aio_state.error = errno;
3469 end_profile:
3470 PROFILE_TIMESTAMP(&end_time);
3471 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3472 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3475 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3477 struct tevent_req *req = tevent_req_callback_data(
3478 subreq, struct tevent_req);
3479 struct vfswrap_getxattrat_state *state = tevent_req_data(
3480 req, struct vfswrap_getxattrat_state);
3481 int ret;
3482 bool ok;
3485 * Make sure we run as the user again
3487 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3488 SMB_ASSERT(ok);
3490 ret = pthreadpool_tevent_job_recv(subreq);
3491 TALLOC_FREE(subreq);
3492 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3493 talloc_set_destructor(state, NULL);
3494 if (ret != 0) {
3495 if (ret != EAGAIN) {
3496 tevent_req_error(req, ret);
3497 return;
3500 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3501 * means the lower level pthreadpool failed to create a new
3502 * thread. Fallback to sync processing in that case to allow
3503 * some progress for the client.
3505 vfswrap_getxattrat_do_sync(req);
3506 return;
3509 if (state->xattr_size == -1) {
3510 tevent_req_error(req, state->vfs_aio_state.error);
3511 return;
3514 if (state->xattr_value == NULL) {
3516 * The caller only wanted the size.
3518 tevent_req_done(req);
3519 return;
3523 * shrink the buffer to the returned size.
3524 * (can't fail). It means NULL if size is 0.
3526 state->xattr_value = talloc_realloc(state,
3527 state->xattr_value,
3528 uint8_t,
3529 state->xattr_size);
3531 tevent_req_done(req);
3534 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3535 struct vfs_aio_state *aio_state,
3536 TALLOC_CTX *mem_ctx,
3537 uint8_t **xattr_value)
3539 struct vfswrap_getxattrat_state *state = tevent_req_data(
3540 req, struct vfswrap_getxattrat_state);
3541 ssize_t xattr_size;
3543 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3544 tevent_req_received(req);
3545 return -1;
3548 *aio_state = state->vfs_aio_state;
3549 xattr_size = state->xattr_size;
3550 if (xattr_value != NULL) {
3551 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3554 tevent_req_received(req);
3555 return xattr_size;
3558 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
3560 return fgetxattr(fsp->fh->fd, name, value, size);
3563 static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle,
3564 const struct smb_filename *smb_fname,
3565 char *list,
3566 size_t size)
3568 return listxattr(smb_fname->base_name, list, size);
3571 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3573 return flistxattr(fsp->fh->fd, list, size);
3576 static int vfswrap_removexattr(struct vfs_handle_struct *handle,
3577 const struct smb_filename *smb_fname,
3578 const char *name)
3580 return removexattr(smb_fname->base_name, name);
3583 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3585 return fremovexattr(fsp->fh->fd, name);
3588 static int vfswrap_setxattr(struct vfs_handle_struct *handle,
3589 const struct smb_filename *smb_fname,
3590 const char *name,
3591 const void *value,
3592 size_t size,
3593 int flags)
3595 return setxattr(smb_fname->base_name, name, value, size, flags);
3598 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3600 return fsetxattr(fsp->fh->fd, name, value, size, flags);
3603 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3605 return false;
3608 static bool vfswrap_is_offline(struct connection_struct *conn,
3609 const struct smb_filename *fname)
3611 NTSTATUS status;
3612 char *path;
3613 bool offline = false;
3615 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3616 return false;
3619 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3620 #if defined(ENOTSUP)
3621 errno = ENOTSUP;
3622 #endif
3623 return false;
3626 status = get_full_smb_filename(talloc_tos(), fname, &path);
3627 if (!NT_STATUS_IS_OK(status)) {
3628 errno = map_errno_from_nt_status(status);
3629 return false;
3632 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3634 TALLOC_FREE(path);
3636 return offline;
3639 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3640 struct files_struct *fsp,
3641 TALLOC_CTX *mem_ctx,
3642 DATA_BLOB *cookie)
3644 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3647 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3648 struct files_struct *fsp,
3649 const DATA_BLOB old_cookie,
3650 TALLOC_CTX *mem_ctx,
3651 DATA_BLOB *new_cookie)
3653 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3654 new_cookie);
3657 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3658 struct smb_request *smb1req,
3659 struct smbXsrv_open *op,
3660 const DATA_BLOB old_cookie,
3661 TALLOC_CTX *mem_ctx,
3662 struct files_struct **fsp,
3663 DATA_BLOB *new_cookie)
3665 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3666 old_cookie, mem_ctx,
3667 fsp, new_cookie);
3670 static struct vfs_fn_pointers vfs_default_fns = {
3671 /* Disk operations */
3673 .connect_fn = vfswrap_connect,
3674 .disconnect_fn = vfswrap_disconnect,
3675 .disk_free_fn = vfswrap_disk_free,
3676 .get_quota_fn = vfswrap_get_quota,
3677 .set_quota_fn = vfswrap_set_quota,
3678 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3679 .statvfs_fn = vfswrap_statvfs,
3680 .fs_capabilities_fn = vfswrap_fs_capabilities,
3681 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3682 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3683 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3684 .snap_check_path_fn = vfswrap_snap_check_path,
3685 .snap_create_fn = vfswrap_snap_create,
3686 .snap_delete_fn = vfswrap_snap_delete,
3688 /* Directory operations */
3690 .fdopendir_fn = vfswrap_fdopendir,
3691 .readdir_fn = vfswrap_readdir,
3692 .readdir_attr_fn = vfswrap_readdir_attr,
3693 .seekdir_fn = vfswrap_seekdir,
3694 .telldir_fn = vfswrap_telldir,
3695 .rewind_dir_fn = vfswrap_rewinddir,
3696 .mkdirat_fn = vfswrap_mkdirat,
3697 .closedir_fn = vfswrap_closedir,
3699 /* File operations */
3701 .openat_fn = vfswrap_openat,
3702 .create_file_fn = vfswrap_create_file,
3703 .close_fn = vfswrap_close,
3704 .pread_fn = vfswrap_pread,
3705 .pread_send_fn = vfswrap_pread_send,
3706 .pread_recv_fn = vfswrap_pread_recv,
3707 .pwrite_fn = vfswrap_pwrite,
3708 .pwrite_send_fn = vfswrap_pwrite_send,
3709 .pwrite_recv_fn = vfswrap_pwrite_recv,
3710 .lseek_fn = vfswrap_lseek,
3711 .sendfile_fn = vfswrap_sendfile,
3712 .recvfile_fn = vfswrap_recvfile,
3713 .renameat_fn = vfswrap_renameat,
3714 .fsync_send_fn = vfswrap_fsync_send,
3715 .fsync_recv_fn = vfswrap_fsync_recv,
3716 .stat_fn = vfswrap_stat,
3717 .fstat_fn = vfswrap_fstat,
3718 .lstat_fn = vfswrap_lstat,
3719 .get_alloc_size_fn = vfswrap_get_alloc_size,
3720 .unlinkat_fn = vfswrap_unlinkat,
3721 .chmod_fn = vfswrap_chmod,
3722 .fchmod_fn = vfswrap_fchmod,
3723 .fchown_fn = vfswrap_fchown,
3724 .lchown_fn = vfswrap_lchown,
3725 .chdir_fn = vfswrap_chdir,
3726 .getwd_fn = vfswrap_getwd,
3727 .ntimes_fn = vfswrap_ntimes,
3728 .ftruncate_fn = vfswrap_ftruncate,
3729 .fallocate_fn = vfswrap_fallocate,
3730 .lock_fn = vfswrap_lock,
3731 .kernel_flock_fn = vfswrap_kernel_flock,
3732 .fcntl_fn = vfswrap_fcntl,
3733 .linux_setlease_fn = vfswrap_linux_setlease,
3734 .getlock_fn = vfswrap_getlock,
3735 .symlinkat_fn = vfswrap_symlinkat,
3736 .readlinkat_fn = vfswrap_readlinkat,
3737 .linkat_fn = vfswrap_linkat,
3738 .mknodat_fn = vfswrap_mknodat,
3739 .realpath_fn = vfswrap_realpath,
3740 .chflags_fn = vfswrap_chflags,
3741 .file_id_create_fn = vfswrap_file_id_create,
3742 .fs_file_id_fn = vfswrap_fs_file_id,
3743 .streaminfo_fn = vfswrap_streaminfo,
3744 .get_real_filename_fn = vfswrap_get_real_filename,
3745 .connectpath_fn = vfswrap_connectpath,
3746 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
3747 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
3748 .strict_lock_check_fn = vfswrap_strict_lock_check,
3749 .translate_name_fn = vfswrap_translate_name,
3750 .fsctl_fn = vfswrap_fsctl,
3751 .set_dos_attributes_fn = vfswrap_set_dos_attributes,
3752 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
3753 .get_dos_attributes_fn = vfswrap_get_dos_attributes,
3754 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
3755 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
3756 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
3757 .offload_read_send_fn = vfswrap_offload_read_send,
3758 .offload_read_recv_fn = vfswrap_offload_read_recv,
3759 .offload_write_send_fn = vfswrap_offload_write_send,
3760 .offload_write_recv_fn = vfswrap_offload_write_recv,
3761 .get_compression_fn = vfswrap_get_compression,
3762 .set_compression_fn = vfswrap_set_compression,
3764 /* NT ACL operations. */
3766 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
3767 .get_nt_acl_at_fn = vfswrap_get_nt_acl_at,
3768 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
3769 .audit_file_fn = vfswrap_audit_file,
3771 /* POSIX ACL operations. */
3773 .sys_acl_get_file_fn = vfswrap_sys_acl_get_file,
3774 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
3775 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
3776 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
3777 .sys_acl_set_file_fn = vfswrap_sys_acl_set_file,
3778 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
3779 .sys_acl_delete_def_file_fn = vfswrap_sys_acl_delete_def_file,
3781 /* EA operations. */
3782 .getxattr_fn = vfswrap_getxattr,
3783 .getxattrat_send_fn = vfswrap_getxattrat_send,
3784 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
3785 .fgetxattr_fn = vfswrap_fgetxattr,
3786 .listxattr_fn = vfswrap_listxattr,
3787 .flistxattr_fn = vfswrap_flistxattr,
3788 .removexattr_fn = vfswrap_removexattr,
3789 .fremovexattr_fn = vfswrap_fremovexattr,
3790 .setxattr_fn = vfswrap_setxattr,
3791 .fsetxattr_fn = vfswrap_fsetxattr,
3793 /* aio operations */
3794 .aio_force_fn = vfswrap_aio_force,
3796 /* durable handle operations */
3797 .durable_cookie_fn = vfswrap_durable_cookie,
3798 .durable_disconnect_fn = vfswrap_durable_disconnect,
3799 .durable_reconnect_fn = vfswrap_durable_reconnect,
3802 static_decl_vfs;
3803 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
3806 * Here we need to implement every call!
3808 * As this is the end of the vfs module chain.
3810 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
3811 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
3812 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);