vfs_io_uring: move error handling out of vfs_io_uring_pread_recv()
[Samba.git] / source3 / modules / vfs_default.c
blob4cf553411cb7ebfaea1174f37071cf0e94a3d77c
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"
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_VFS
42 /* Check for NULL pointer parameters in vfswrap_* functions */
44 /* We don't want to have NULL function pointers lying around. Someone
45 is sure to try and execute them. These stubs are used to prevent
46 this possibility. */
48 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
50 return 0; /* Return >= 0 for success */
53 static void vfswrap_disconnect(vfs_handle_struct *handle)
57 /* Disk operations */
59 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
60 const struct smb_filename *smb_fname,
61 uint64_t *bsize,
62 uint64_t *dfree,
63 uint64_t *dsize)
65 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
66 return (uint64_t)-1;
69 *bsize = 512;
70 return *dfree / 2;
73 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
74 const struct smb_filename *smb_fname,
75 enum SMB_QUOTA_TYPE qtype,
76 unid_t id,
77 SMB_DISK_QUOTA *qt)
79 #ifdef HAVE_SYS_QUOTAS
80 int result;
82 START_PROFILE(syscall_get_quota);
83 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
84 END_PROFILE(syscall_get_quota);
85 return result;
86 #else
87 errno = ENOSYS;
88 return -1;
89 #endif
92 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
94 #ifdef HAVE_SYS_QUOTAS
95 int result;
97 START_PROFILE(syscall_set_quota);
98 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
99 END_PROFILE(syscall_set_quota);
100 return result;
101 #else
102 errno = ENOSYS;
103 return -1;
104 #endif
107 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
108 struct files_struct *fsp,
109 struct shadow_copy_data *shadow_copy_data,
110 bool labels)
112 errno = ENOSYS;
113 return -1; /* Not implemented. */
116 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
117 const struct smb_filename *smb_fname,
118 vfs_statvfs_struct *statbuf)
120 return sys_statvfs(smb_fname->base_name, statbuf);
123 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
124 enum timestamp_set_resolution *p_ts_res)
126 const struct loadparm_substitution *lp_sub =
127 loadparm_s3_global_substitution();
128 connection_struct *conn = handle->conn;
129 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
130 struct smb_filename *smb_fname_cpath = NULL;
131 struct vfs_statvfs_struct statbuf;
132 int ret;
134 smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
135 NULL, NULL, 0);
136 if (smb_fname_cpath == NULL) {
137 return caps;
140 ZERO_STRUCT(statbuf);
141 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
142 if (ret == 0) {
143 caps = statbuf.FsCapabilities;
146 *p_ts_res = TIMESTAMP_SET_SECONDS;
148 /* Work out what timestamp resolution we can
149 * use when setting a timestamp. */
151 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
152 if (ret == -1) {
153 TALLOC_FREE(smb_fname_cpath);
154 return caps;
157 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
158 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
159 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
160 /* If any of the normal UNIX directory timestamps
161 * have a non-zero tv_nsec component assume
162 * we might be able to set sub-second timestamps.
163 * See what filetime set primitives we have.
165 #if defined(HAVE_UTIMENSAT)
166 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
167 #elif defined(HAVE_UTIMES)
168 /* utimes allows msec timestamps to be set. */
169 *p_ts_res = TIMESTAMP_SET_MSEC;
170 #elif defined(HAVE_UTIME)
171 /* utime only allows sec timestamps to be set. */
172 *p_ts_res = TIMESTAMP_SET_SECONDS;
173 #endif
175 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
176 "resolution of %s "
177 "available on share %s, directory %s\n",
178 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
179 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
180 conn->connectpath ));
182 TALLOC_FREE(smb_fname_cpath);
183 return caps;
186 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
187 struct dfs_GetDFSReferral *r)
189 struct junction_map *junction = NULL;
190 int consumedcnt = 0;
191 bool self_referral = false;
192 char *pathnamep = NULL;
193 char *local_dfs_path = NULL;
194 NTSTATUS status;
195 size_t i;
196 uint16_t max_referral_level = r->in.req.max_referral_level;
198 if (DEBUGLVL(10)) {
199 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
202 /* get the junction entry */
203 if (r->in.req.servername == NULL) {
204 return NT_STATUS_NOT_FOUND;
208 * Trim pathname sent by client so it begins with only one backslash.
209 * Two backslashes confuse some dfs clients
212 local_dfs_path = talloc_strdup(r, r->in.req.servername);
213 if (local_dfs_path == NULL) {
214 return NT_STATUS_NO_MEMORY;
216 pathnamep = local_dfs_path;
217 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
218 IS_DIRECTORY_SEP(pathnamep[1])) {
219 pathnamep++;
222 junction = talloc_zero(r, struct junction_map);
223 if (junction == NULL) {
224 return NT_STATUS_NO_MEMORY;
227 /* The following call can change cwd. */
228 status = get_referred_path(r,
229 handle->conn->session_info,
230 pathnamep,
231 handle->conn->sconn->remote_address,
232 handle->conn->sconn->local_address,
233 !handle->conn->sconn->using_smb2,
234 junction, &consumedcnt, &self_referral);
235 if (!NT_STATUS_IS_OK(status)) {
236 struct smb_filename connectpath_fname = {
237 .base_name = handle->conn->connectpath
239 vfs_ChDir(handle->conn, &connectpath_fname);
240 return status;
243 struct smb_filename connectpath_fname = {
244 .base_name = handle->conn->connectpath
246 vfs_ChDir(handle->conn, &connectpath_fname);
249 if (!self_referral) {
250 pathnamep[consumedcnt] = '\0';
252 if (DEBUGLVL(3)) {
253 dbgtext("Path %s to alternate path(s):",
254 pathnamep);
255 for (i=0; i < junction->referral_count; i++) {
256 dbgtext(" %s",
257 junction->referral_list[i].alternate_path);
259 dbgtext(".\n");
263 if (r->in.req.max_referral_level <= 2) {
264 max_referral_level = 2;
266 if (r->in.req.max_referral_level >= 3) {
267 max_referral_level = 3;
270 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
271 if (r->out.resp == NULL) {
272 return NT_STATUS_NO_MEMORY;
275 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
276 r->out.resp->nb_referrals = junction->referral_count;
278 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
279 if (self_referral) {
280 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
283 r->out.resp->referral_entries = talloc_zero_array(r,
284 struct dfs_referral_type,
285 r->out.resp->nb_referrals);
286 if (r->out.resp->referral_entries == NULL) {
287 return NT_STATUS_NO_MEMORY;
290 switch (max_referral_level) {
291 case 2:
292 for(i=0; i < junction->referral_count; i++) {
293 struct referral *ref = &junction->referral_list[i];
294 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
295 struct dfs_referral_type *t =
296 &r->out.resp->referral_entries[i];
297 struct dfs_referral_v2 *v2 = &t->referral.v2;
299 t->version = 2;
300 v2->size = VERSION2_REFERRAL_SIZE;
301 if (self_referral) {
302 v2->server_type = DFS_SERVER_ROOT;
303 } else {
304 v2->server_type = DFS_SERVER_NON_ROOT;
306 v2->entry_flags = 0;
307 v2->proximity = ref->proximity;
308 v2->ttl = ref->ttl;
309 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
310 if (v2->DFS_path == NULL) {
311 return NT_STATUS_NO_MEMORY;
313 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
314 if (v2->DFS_alt_path == NULL) {
315 return NT_STATUS_NO_MEMORY;
317 v2->netw_address = talloc_strdup(mem_ctx,
318 ref->alternate_path);
319 if (v2->netw_address == NULL) {
320 return NT_STATUS_NO_MEMORY;
324 break;
325 case 3:
326 for(i=0; i < junction->referral_count; i++) {
327 struct referral *ref = &junction->referral_list[i];
328 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
329 struct dfs_referral_type *t =
330 &r->out.resp->referral_entries[i];
331 struct dfs_referral_v3 *v3 = &t->referral.v3;
332 struct dfs_normal_referral *r1 = &v3->referrals.r1;
334 t->version = 3;
335 v3->size = VERSION3_REFERRAL_SIZE;
336 if (self_referral) {
337 v3->server_type = DFS_SERVER_ROOT;
338 } else {
339 v3->server_type = DFS_SERVER_NON_ROOT;
341 v3->entry_flags = 0;
342 v3->ttl = ref->ttl;
343 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
344 if (r1->DFS_path == NULL) {
345 return NT_STATUS_NO_MEMORY;
347 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
348 if (r1->DFS_alt_path == NULL) {
349 return NT_STATUS_NO_MEMORY;
351 r1->netw_address = talloc_strdup(mem_ctx,
352 ref->alternate_path);
353 if (r1->netw_address == NULL) {
354 return NT_STATUS_NO_MEMORY;
357 break;
358 default:
359 DEBUG(0,("Invalid dfs referral version: %d\n",
360 max_referral_level));
361 return NT_STATUS_INVALID_LEVEL;
364 if (DEBUGLVL(10)) {
365 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
368 return NT_STATUS_OK;
371 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
372 struct files_struct *dirfsp,
373 const struct smb_filename *smb_fname,
374 const struct referral *reflist,
375 size_t referral_count)
377 TALLOC_CTX *frame = talloc_stackframe();
378 NTSTATUS status = NT_STATUS_NO_MEMORY;
379 int ret;
380 char *msdfs_link = NULL;
382 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
384 /* Form the msdfs_link contents */
385 msdfs_link = msdfs_link_string(frame,
386 reflist,
387 referral_count);
388 if (msdfs_link == NULL) {
389 goto out;
392 ret = symlinkat(msdfs_link,
393 dirfsp->fh->fd,
394 smb_fname->base_name);
395 if (ret == 0) {
396 status = NT_STATUS_OK;
397 } else {
398 status = map_nt_error_from_unix(errno);
401 out:
403 TALLOC_FREE(frame);
404 return status;
408 * Read and return the contents of a DFS redirect given a
409 * pathname. A caller can pass in NULL for ppreflist and
410 * preferral_count but still determine if this was a
411 * DFS redirect point by getting NT_STATUS_OK back
412 * without incurring the overhead of reading and parsing
413 * the referral contents.
416 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
417 TALLOC_CTX *mem_ctx,
418 struct files_struct *dirfsp,
419 const struct smb_filename *smb_fname,
420 struct referral **ppreflist,
421 size_t *preferral_count)
423 NTSTATUS status = NT_STATUS_NO_MEMORY;
424 size_t bufsize;
425 char *link_target = NULL;
426 int referral_len;
427 bool ok;
428 #if defined(HAVE_BROKEN_READLINK)
429 char link_target_buf[PATH_MAX];
430 #else
431 char link_target_buf[7];
432 #endif
434 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
436 if (ppreflist == NULL && preferral_count == NULL) {
438 * We're only checking if this is a DFS
439 * redirect. We don't need to return data.
441 bufsize = sizeof(link_target_buf);
442 link_target = link_target_buf;
443 } else {
444 bufsize = PATH_MAX;
445 link_target = talloc_array(mem_ctx, char, bufsize);
446 if (!link_target) {
447 goto err;
451 referral_len = readlinkat(dirfsp->fh->fd,
452 smb_fname->base_name,
453 link_target,
454 bufsize - 1);
455 if (referral_len == -1) {
456 if (errno == EINVAL) {
458 * If the path isn't a link, readlinkat
459 * returns EINVAL. Allow the caller to
460 * detect this.
462 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
463 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
464 } else {
465 status = map_nt_error_from_unix(errno);
466 DBG_ERR("Error reading "
467 "msdfs link %s: %s\n",
468 smb_fname->base_name,
469 strerror(errno));
471 goto err;
473 link_target[referral_len] = '\0';
475 DBG_INFO("%s -> %s\n",
476 smb_fname->base_name,
477 link_target);
479 if (!strnequal(link_target, "msdfs:", 6)) {
480 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
481 goto err;
484 if (ppreflist == NULL && preferral_count == NULL) {
485 /* Early return for checking if this is a DFS link. */
486 return NT_STATUS_OK;
489 ok = parse_msdfs_symlink(mem_ctx,
490 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
491 link_target,
492 ppreflist,
493 preferral_count);
495 if (ok) {
496 status = NT_STATUS_OK;
497 } else {
498 status = NT_STATUS_NO_MEMORY;
501 err:
503 if (link_target != link_target_buf) {
504 TALLOC_FREE(link_target);
506 return status;
509 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
510 TALLOC_CTX *mem_ctx,
511 const char *service_path,
512 char **base_volume)
514 return NT_STATUS_NOT_SUPPORTED;
517 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
518 TALLOC_CTX *mem_ctx,
519 const char *base_volume,
520 time_t *tstamp,
521 bool rw,
522 char **base_path,
523 char **snap_path)
525 return NT_STATUS_NOT_SUPPORTED;
528 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
529 TALLOC_CTX *mem_ctx,
530 char *base_path,
531 char *snap_path)
533 return NT_STATUS_NOT_SUPPORTED;
536 /* Directory operations */
538 static DIR *vfswrap_opendir(vfs_handle_struct *handle,
539 const struct smb_filename *smb_fname,
540 const char *mask,
541 uint32_t attr)
543 DIR *result;
545 START_PROFILE(syscall_opendir);
546 result = opendir(smb_fname->base_name);
547 END_PROFILE(syscall_opendir);
548 return result;
551 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
552 files_struct *fsp,
553 const char *mask,
554 uint32_t attr)
556 DIR *result;
558 START_PROFILE(syscall_fdopendir);
559 result = sys_fdopendir(fsp->fh->fd);
560 END_PROFILE(syscall_fdopendir);
561 return result;
565 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
566 DIR *dirp,
567 SMB_STRUCT_STAT *sbuf)
569 struct dirent *result;
571 START_PROFILE(syscall_readdir);
572 result = readdir(dirp);
573 END_PROFILE(syscall_readdir);
574 if (sbuf) {
575 /* Default Posix readdir() does not give us stat info.
576 * Set to invalid to indicate we didn't return this info. */
577 SET_STAT_INVALID(*sbuf);
578 #if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
579 if (result != NULL) {
580 /* See if we can efficiently return this. */
581 struct stat st;
582 int flags = AT_SYMLINK_NOFOLLOW;
583 int ret = fstatat(dirfd(dirp),
584 result->d_name,
585 &st,
586 flags);
588 * As this is an optimization,
589 * ignore it if we stat'ed a
590 * symlink. Make the caller
591 * do it again as we don't
592 * know if they wanted the link
593 * info, or its target info.
595 if ((ret == 0) && (!S_ISLNK(st.st_mode))) {
596 init_stat_ex_from_stat(sbuf,
597 &st,
598 lp_fake_directory_create_times(
599 SNUM(handle->conn)));
602 #endif
604 return result;
607 static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
608 const struct smb_filename *fname,
609 TALLOC_CTX *mem_ctx,
610 struct readdir_attr_data **attr_data)
612 return NT_STATUS_NOT_SUPPORTED;
615 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
617 START_PROFILE(syscall_seekdir);
618 seekdir(dirp, offset);
619 END_PROFILE(syscall_seekdir);
622 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
624 long result;
625 START_PROFILE(syscall_telldir);
626 result = telldir(dirp);
627 END_PROFILE(syscall_telldir);
628 return result;
631 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
633 START_PROFILE(syscall_rewinddir);
634 rewinddir(dirp);
635 END_PROFILE(syscall_rewinddir);
638 static int vfswrap_mkdirat(vfs_handle_struct *handle,
639 struct files_struct *dirfsp,
640 const struct smb_filename *smb_fname,
641 mode_t mode)
643 int result;
644 const char *path = smb_fname->base_name;
645 char *parent = NULL;
647 START_PROFILE(syscall_mkdirat);
649 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
651 if (lp_inherit_acls(SNUM(handle->conn))
652 && parent_dirname(talloc_tos(), path, &parent, NULL)
653 && directory_has_default_acl(handle->conn, parent)) {
654 mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
657 TALLOC_FREE(parent);
659 result = mkdirat(dirfsp->fh->fd, path, mode);
661 END_PROFILE(syscall_mkdirat);
662 return result;
665 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
667 int result;
669 START_PROFILE(syscall_closedir);
670 result = closedir(dirp);
671 END_PROFILE(syscall_closedir);
672 return result;
675 /* File operations */
677 static int vfswrap_open(vfs_handle_struct *handle,
678 struct smb_filename *smb_fname,
679 files_struct *fsp, int flags, mode_t mode)
681 int result = -1;
683 START_PROFILE(syscall_open);
685 if (is_named_stream(smb_fname)) {
686 errno = ENOENT;
687 goto out;
690 result = open(smb_fname->base_name, flags, mode);
691 out:
692 END_PROFILE(syscall_open);
693 return result;
696 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
697 struct smb_request *req,
698 uint16_t root_dir_fid,
699 struct smb_filename *smb_fname,
700 uint32_t access_mask,
701 uint32_t share_access,
702 uint32_t create_disposition,
703 uint32_t create_options,
704 uint32_t file_attributes,
705 uint32_t oplock_request,
706 const struct smb2_lease *lease,
707 uint64_t allocation_size,
708 uint32_t private_flags,
709 struct security_descriptor *sd,
710 struct ea_list *ea_list,
711 files_struct **result,
712 int *pinfo,
713 const struct smb2_create_blobs *in_context_blobs,
714 struct smb2_create_blobs *out_context_blobs)
716 return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
717 access_mask, share_access,
718 create_disposition, create_options,
719 file_attributes, oplock_request, lease,
720 allocation_size, private_flags,
721 sd, ea_list, result,
722 pinfo, in_context_blobs, out_context_blobs);
725 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
727 int result;
729 START_PROFILE(syscall_close);
730 result = fd_close_posix(fsp);
731 END_PROFILE(syscall_close);
732 return result;
735 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
736 size_t n, off_t offset)
738 ssize_t result;
740 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
741 START_PROFILE_BYTES(syscall_pread, n);
742 result = sys_pread_full(fsp->fh->fd, data, n, offset);
743 END_PROFILE_BYTES(syscall_pread);
745 if (result == -1 && errno == ESPIPE) {
746 /* Maintain the fiction that pipes can be seeked (sought?) on. */
747 result = sys_read(fsp->fh->fd, data, n);
748 fsp->fh->pos = 0;
751 #else /* HAVE_PREAD */
752 errno = ENOSYS;
753 result = -1;
754 #endif /* HAVE_PREAD */
756 return result;
759 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
760 size_t n, off_t offset)
762 ssize_t result;
764 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
765 START_PROFILE_BYTES(syscall_pwrite, n);
766 result = sys_pwrite_full(fsp->fh->fd, data, n, offset);
767 END_PROFILE_BYTES(syscall_pwrite);
769 if (result == -1 && errno == ESPIPE) {
770 /* Maintain the fiction that pipes can be sought on. */
771 result = sys_write(fsp->fh->fd, data, n);
774 #else /* HAVE_PWRITE */
775 errno = ENOSYS;
776 result = -1;
777 #endif /* HAVE_PWRITE */
779 return result;
782 struct vfswrap_pread_state {
783 ssize_t ret;
784 int fd;
785 void *buf;
786 size_t count;
787 off_t offset;
789 struct vfs_aio_state vfs_aio_state;
790 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
793 static void vfs_pread_do(void *private_data);
794 static void vfs_pread_done(struct tevent_req *subreq);
795 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
797 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
798 TALLOC_CTX *mem_ctx,
799 struct tevent_context *ev,
800 struct files_struct *fsp,
801 void *data,
802 size_t n, off_t offset)
804 struct tevent_req *req, *subreq;
805 struct vfswrap_pread_state *state;
807 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
808 if (req == NULL) {
809 return NULL;
812 state->ret = -1;
813 state->fd = fsp->fh->fd;
814 state->buf = data;
815 state->count = n;
816 state->offset = offset;
818 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
819 state->profile_bytes, n);
820 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
822 subreq = pthreadpool_tevent_job_send(
823 state, ev, handle->conn->sconn->pool,
824 vfs_pread_do, state);
825 if (tevent_req_nomem(subreq, req)) {
826 return tevent_req_post(req, ev);
828 tevent_req_set_callback(subreq, vfs_pread_done, req);
830 talloc_set_destructor(state, vfs_pread_state_destructor);
832 return req;
835 static void vfs_pread_do(void *private_data)
837 struct vfswrap_pread_state *state = talloc_get_type_abort(
838 private_data, struct vfswrap_pread_state);
839 struct timespec start_time;
840 struct timespec end_time;
842 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
844 PROFILE_TIMESTAMP(&start_time);
846 state->ret = sys_pread_full(state->fd,
847 state->buf,
848 state->count,
849 state->offset);
851 if (state->ret == -1) {
852 state->vfs_aio_state.error = errno;
855 PROFILE_TIMESTAMP(&end_time);
857 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
859 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
862 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
864 return -1;
867 static void vfs_pread_done(struct tevent_req *subreq)
869 struct tevent_req *req = tevent_req_callback_data(
870 subreq, struct tevent_req);
871 struct vfswrap_pread_state *state = tevent_req_data(
872 req, struct vfswrap_pread_state);
873 int ret;
875 ret = pthreadpool_tevent_job_recv(subreq);
876 TALLOC_FREE(subreq);
877 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
878 talloc_set_destructor(state, NULL);
879 if (ret != 0) {
880 if (ret != EAGAIN) {
881 tevent_req_error(req, ret);
882 return;
885 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
886 * means the lower level pthreadpool failed to create a new
887 * thread. Fallback to sync processing in that case to allow
888 * some progress for the client.
890 vfs_pread_do(state);
893 tevent_req_done(req);
896 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
897 struct vfs_aio_state *vfs_aio_state)
899 struct vfswrap_pread_state *state = tevent_req_data(
900 req, struct vfswrap_pread_state);
902 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
903 return -1;
906 *vfs_aio_state = state->vfs_aio_state;
907 return state->ret;
910 struct vfswrap_pwrite_state {
911 ssize_t ret;
912 int fd;
913 const void *buf;
914 size_t count;
915 off_t offset;
917 struct vfs_aio_state vfs_aio_state;
918 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
921 static void vfs_pwrite_do(void *private_data);
922 static void vfs_pwrite_done(struct tevent_req *subreq);
923 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
925 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
926 TALLOC_CTX *mem_ctx,
927 struct tevent_context *ev,
928 struct files_struct *fsp,
929 const void *data,
930 size_t n, off_t offset)
932 struct tevent_req *req, *subreq;
933 struct vfswrap_pwrite_state *state;
935 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
936 if (req == NULL) {
937 return NULL;
940 state->ret = -1;
941 state->fd = fsp->fh->fd;
942 state->buf = data;
943 state->count = n;
944 state->offset = offset;
946 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
947 state->profile_bytes, n);
948 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
950 subreq = pthreadpool_tevent_job_send(
951 state, ev, handle->conn->sconn->pool,
952 vfs_pwrite_do, state);
953 if (tevent_req_nomem(subreq, req)) {
954 return tevent_req_post(req, ev);
956 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
958 talloc_set_destructor(state, vfs_pwrite_state_destructor);
960 return req;
963 static void vfs_pwrite_do(void *private_data)
965 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
966 private_data, struct vfswrap_pwrite_state);
967 struct timespec start_time;
968 struct timespec end_time;
970 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
972 PROFILE_TIMESTAMP(&start_time);
974 state->ret = sys_pwrite_full(state->fd,
975 state->buf,
976 state->count,
977 state->offset);
979 if (state->ret == -1) {
980 state->vfs_aio_state.error = errno;
983 PROFILE_TIMESTAMP(&end_time);
985 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
987 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
990 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
992 return -1;
995 static void vfs_pwrite_done(struct tevent_req *subreq)
997 struct tevent_req *req = tevent_req_callback_data(
998 subreq, struct tevent_req);
999 struct vfswrap_pwrite_state *state = tevent_req_data(
1000 req, struct vfswrap_pwrite_state);
1001 int ret;
1003 ret = pthreadpool_tevent_job_recv(subreq);
1004 TALLOC_FREE(subreq);
1005 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1006 talloc_set_destructor(state, NULL);
1007 if (ret != 0) {
1008 if (ret != EAGAIN) {
1009 tevent_req_error(req, ret);
1010 return;
1013 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1014 * means the lower level pthreadpool failed to create a new
1015 * thread. Fallback to sync processing in that case to allow
1016 * some progress for the client.
1018 vfs_pwrite_do(state);
1021 tevent_req_done(req);
1024 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1025 struct vfs_aio_state *vfs_aio_state)
1027 struct vfswrap_pwrite_state *state = tevent_req_data(
1028 req, struct vfswrap_pwrite_state);
1030 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1031 return -1;
1034 *vfs_aio_state = state->vfs_aio_state;
1035 return state->ret;
1038 struct vfswrap_fsync_state {
1039 ssize_t ret;
1040 int fd;
1042 struct vfs_aio_state vfs_aio_state;
1043 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1046 static void vfs_fsync_do(void *private_data);
1047 static void vfs_fsync_done(struct tevent_req *subreq);
1048 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1050 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1051 TALLOC_CTX *mem_ctx,
1052 struct tevent_context *ev,
1053 struct files_struct *fsp)
1055 struct tevent_req *req, *subreq;
1056 struct vfswrap_fsync_state *state;
1058 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1059 if (req == NULL) {
1060 return NULL;
1063 state->ret = -1;
1064 state->fd = fsp->fh->fd;
1066 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1067 state->profile_bytes, 0);
1068 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1070 subreq = pthreadpool_tevent_job_send(
1071 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1072 if (tevent_req_nomem(subreq, req)) {
1073 return tevent_req_post(req, ev);
1075 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1077 talloc_set_destructor(state, vfs_fsync_state_destructor);
1079 return req;
1082 static void vfs_fsync_do(void *private_data)
1084 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1085 private_data, struct vfswrap_fsync_state);
1086 struct timespec start_time;
1087 struct timespec end_time;
1089 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1091 PROFILE_TIMESTAMP(&start_time);
1093 do {
1094 state->ret = fsync(state->fd);
1095 } while ((state->ret == -1) && (errno == EINTR));
1097 if (state->ret == -1) {
1098 state->vfs_aio_state.error = errno;
1101 PROFILE_TIMESTAMP(&end_time);
1103 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1105 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1108 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1110 return -1;
1113 static void vfs_fsync_done(struct tevent_req *subreq)
1115 struct tevent_req *req = tevent_req_callback_data(
1116 subreq, struct tevent_req);
1117 struct vfswrap_fsync_state *state = tevent_req_data(
1118 req, struct vfswrap_fsync_state);
1119 int ret;
1121 ret = pthreadpool_tevent_job_recv(subreq);
1122 TALLOC_FREE(subreq);
1123 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1124 talloc_set_destructor(state, NULL);
1125 if (ret != 0) {
1126 if (ret != EAGAIN) {
1127 tevent_req_error(req, ret);
1128 return;
1131 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1132 * means the lower level pthreadpool failed to create a new
1133 * thread. Fallback to sync processing in that case to allow
1134 * some progress for the client.
1136 vfs_fsync_do(state);
1139 tevent_req_done(req);
1142 static int vfswrap_fsync_recv(struct tevent_req *req,
1143 struct vfs_aio_state *vfs_aio_state)
1145 struct vfswrap_fsync_state *state = tevent_req_data(
1146 req, struct vfswrap_fsync_state);
1148 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1149 return -1;
1152 *vfs_aio_state = state->vfs_aio_state;
1153 return state->ret;
1156 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1158 off_t result = 0;
1160 START_PROFILE(syscall_lseek);
1162 result = lseek(fsp->fh->fd, offset, whence);
1164 * We want to maintain the fiction that we can seek
1165 * on a fifo for file system purposes. This allows
1166 * people to set up UNIX fifo's that feed data to Windows
1167 * applications. JRA.
1170 if((result == -1) && (errno == ESPIPE)) {
1171 result = 0;
1172 errno = 0;
1175 END_PROFILE(syscall_lseek);
1176 return result;
1179 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1180 off_t offset, size_t n)
1182 ssize_t result;
1184 START_PROFILE_BYTES(syscall_sendfile, n);
1185 result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
1186 END_PROFILE_BYTES(syscall_sendfile);
1187 return result;
1190 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1191 int fromfd,
1192 files_struct *tofsp,
1193 off_t offset,
1194 size_t n)
1196 ssize_t result;
1198 START_PROFILE_BYTES(syscall_recvfile, n);
1199 result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
1200 END_PROFILE_BYTES(syscall_recvfile);
1201 return result;
1204 static int vfswrap_renameat(vfs_handle_struct *handle,
1205 files_struct *srcfsp,
1206 const struct smb_filename *smb_fname_src,
1207 files_struct *dstfsp,
1208 const struct smb_filename *smb_fname_dst)
1210 int result = -1;
1212 START_PROFILE(syscall_renameat);
1214 if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) {
1215 errno = ENOENT;
1216 goto out;
1219 result = renameat(srcfsp->fh->fd,
1220 smb_fname_src->base_name,
1221 dstfsp->fh->fd,
1222 smb_fname_dst->base_name);
1224 out:
1225 END_PROFILE(syscall_renameat);
1226 return result;
1229 static int vfswrap_stat(vfs_handle_struct *handle,
1230 struct smb_filename *smb_fname)
1232 int result = -1;
1234 START_PROFILE(syscall_stat);
1236 if (is_named_stream(smb_fname)) {
1237 errno = ENOENT;
1238 goto out;
1241 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1242 lp_fake_directory_create_times(SNUM(handle->conn)));
1243 out:
1244 END_PROFILE(syscall_stat);
1245 return result;
1248 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1250 int result;
1252 START_PROFILE(syscall_fstat);
1253 result = sys_fstat(fsp->fh->fd,
1254 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1255 END_PROFILE(syscall_fstat);
1256 return result;
1259 static int vfswrap_lstat(vfs_handle_struct *handle,
1260 struct smb_filename *smb_fname)
1262 int result = -1;
1264 START_PROFILE(syscall_lstat);
1266 if (is_named_stream(smb_fname)) {
1267 errno = ENOENT;
1268 goto out;
1271 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1272 lp_fake_directory_create_times(SNUM(handle->conn)));
1273 out:
1274 END_PROFILE(syscall_lstat);
1275 return result;
1278 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1279 const char *name,
1280 enum vfs_translate_direction direction,
1281 TALLOC_CTX *mem_ctx,
1282 char **mapped_name)
1284 return NT_STATUS_NONE_MAPPED;
1288 * Implement the default fsctl operation.
1290 static bool vfswrap_logged_ioctl_message = false;
1292 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1293 struct files_struct *fsp,
1294 TALLOC_CTX *ctx,
1295 uint32_t function,
1296 uint16_t req_flags, /* Needed for UNICODE ... */
1297 const uint8_t *_in_data,
1298 uint32_t in_len,
1299 uint8_t **_out_data,
1300 uint32_t max_out_len,
1301 uint32_t *out_len)
1303 const char *in_data = (const char *)_in_data;
1304 char **out_data = (char **)_out_data;
1305 NTSTATUS status;
1307 switch (function) {
1308 case FSCTL_SET_SPARSE:
1310 bool set_sparse = true;
1312 if (in_len >= 1 && in_data[0] == 0) {
1313 set_sparse = false;
1316 status = file_set_sparse(handle->conn, fsp, set_sparse);
1318 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1319 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1320 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1321 nt_errstr(status)));
1323 return status;
1326 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1328 unsigned char objid[16];
1329 char *return_data = NULL;
1331 /* This should return the object-id on this file.
1332 * I think I'll make this be the inode+dev. JRA.
1335 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1336 fsp_fnum_dbg(fsp)));
1338 *out_len = MIN(max_out_len, 64);
1340 /* Hmmm, will this cause problems if less data asked for? */
1341 return_data = talloc_array(ctx, char, 64);
1342 if (return_data == NULL) {
1343 return NT_STATUS_NO_MEMORY;
1346 /* For backwards compatibility only store the dev/inode. */
1347 push_file_id_16(return_data, &fsp->file_id);
1348 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1349 push_file_id_16(return_data+32, &fsp->file_id);
1350 memset(return_data+48, 0, 16);
1351 *out_data = return_data;
1352 return NT_STATUS_OK;
1355 case FSCTL_GET_REPARSE_POINT:
1357 /* Fail it with STATUS_NOT_A_REPARSE_POINT */
1358 DEBUG(10, ("FSCTL_GET_REPARSE_POINT: called on %s. "
1359 "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
1360 return NT_STATUS_NOT_A_REPARSE_POINT;
1363 case FSCTL_SET_REPARSE_POINT:
1365 /* Fail it with STATUS_NOT_A_REPARSE_POINT */
1366 DEBUG(10, ("FSCTL_SET_REPARSE_POINT: called on %s. "
1367 "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
1368 return NT_STATUS_NOT_A_REPARSE_POINT;
1371 case FSCTL_GET_SHADOW_COPY_DATA:
1374 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1375 * and return their volume names. If max_data_count is 16, then it is just
1376 * asking for the number of volumes and length of the combined names.
1378 * pdata is the data allocated by our caller, but that uses
1379 * total_data_count (which is 0 in our case) rather than max_data_count.
1380 * Allocate the correct amount and return the pointer to let
1381 * it be deallocated when we return.
1383 struct shadow_copy_data *shadow_data = NULL;
1384 bool labels = False;
1385 uint32_t labels_data_count = 0;
1386 uint32_t i;
1387 char *cur_pdata = NULL;
1389 if (max_out_len < 16) {
1390 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1391 max_out_len));
1392 return NT_STATUS_INVALID_PARAMETER;
1395 if (max_out_len > 16) {
1396 labels = True;
1399 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1400 if (shadow_data == NULL) {
1401 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1402 return NT_STATUS_NO_MEMORY;
1406 * Call the VFS routine to actually do the work.
1408 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1409 int log_lev = 0;
1410 if (errno == 0) {
1411 /* broken module didn't set errno on error */
1412 status = NT_STATUS_UNSUCCESSFUL;
1413 } else {
1414 status = map_nt_error_from_unix(errno);
1415 if (NT_STATUS_EQUAL(status,
1416 NT_STATUS_NOT_SUPPORTED)) {
1417 log_lev = 5;
1420 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1421 "connectpath %s, failed - %s.\n",
1422 fsp->conn->connectpath,
1423 nt_errstr(status)));
1424 TALLOC_FREE(shadow_data);
1425 return status;
1428 labels_data_count = (shadow_data->num_volumes * 2 *
1429 sizeof(SHADOW_COPY_LABEL)) + 2;
1431 if (!labels) {
1432 *out_len = 16;
1433 } else {
1434 *out_len = 12 + labels_data_count;
1437 if (max_out_len < *out_len) {
1438 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1439 max_out_len, *out_len));
1440 TALLOC_FREE(shadow_data);
1441 return NT_STATUS_BUFFER_TOO_SMALL;
1444 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1445 if (cur_pdata == NULL) {
1446 TALLOC_FREE(shadow_data);
1447 return NT_STATUS_NO_MEMORY;
1450 *out_data = cur_pdata;
1452 /* num_volumes 4 bytes */
1453 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1455 if (labels) {
1456 /* num_labels 4 bytes */
1457 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1460 /* needed_data_count 4 bytes */
1461 SIVAL(cur_pdata, 8, labels_data_count);
1463 cur_pdata += 12;
1465 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1466 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1467 if (labels && shadow_data->labels) {
1468 for (i=0; i<shadow_data->num_volumes; i++) {
1469 size_t len = 0;
1470 status = srvstr_push(cur_pdata, req_flags,
1471 cur_pdata, shadow_data->labels[i],
1472 2 * sizeof(SHADOW_COPY_LABEL),
1473 STR_UNICODE|STR_TERMINATE, &len);
1474 if (!NT_STATUS_IS_OK(status)) {
1475 TALLOC_FREE(*out_data);
1476 TALLOC_FREE(shadow_data);
1477 return status;
1479 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1480 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1484 TALLOC_FREE(shadow_data);
1486 return NT_STATUS_OK;
1489 case FSCTL_FIND_FILES_BY_SID:
1491 /* pretend this succeeded -
1493 * we have to send back a list with all files owned by this SID
1495 * but I have to check that --metze
1497 ssize_t ret;
1498 struct dom_sid sid;
1499 struct dom_sid_buf buf;
1500 uid_t uid;
1501 size_t sid_len;
1503 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1504 fsp_fnum_dbg(fsp)));
1506 if (in_len < 8) {
1507 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1508 return NT_STATUS_INVALID_PARAMETER;
1511 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1513 /* unknown 4 bytes: this is not the length of the sid :-( */
1514 /*unknown = IVAL(pdata,0);*/
1516 ret = sid_parse(_in_data + 4, sid_len, &sid);
1517 if (ret == -1) {
1518 return NT_STATUS_INVALID_PARAMETER;
1520 DEBUGADD(10, ("for SID: %s\n",
1521 dom_sid_str_buf(&sid, &buf)));
1523 if (!sid_to_uid(&sid, &uid)) {
1524 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1525 dom_sid_str_buf(&sid, &buf),
1526 (unsigned long)sid_len));
1527 uid = (-1);
1530 /* we can take a look at the find source :-)
1532 * find ./ -uid $uid -name '*' is what we need here
1535 * and send 4bytes len and then NULL terminated unicode strings
1536 * for each file
1538 * but I don't know how to deal with the paged results
1539 * (maybe we can hang the result anywhere in the fsp struct)
1541 * but I don't know how to deal with the paged results
1542 * (maybe we can hang the result anywhere in the fsp struct)
1544 * we don't send all files at once
1545 * and at the next we should *not* start from the beginning,
1546 * so we have to cache the result
1548 * --metze
1551 /* this works for now... */
1552 return NT_STATUS_OK;
1555 case FSCTL_QUERY_ALLOCATED_RANGES:
1557 /* FIXME: This is just a dummy reply, telling that all of the
1558 * file is allocated. MKS cp needs that.
1559 * Adding the real allocated ranges via FIEMAP on Linux
1560 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1561 * this FSCTL correct for sparse files.
1563 uint64_t offset, length;
1564 char *out_data_tmp = NULL;
1566 if (in_len != 16) {
1567 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1568 in_len));
1569 return NT_STATUS_INVALID_PARAMETER;
1572 if (max_out_len < 16) {
1573 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1574 max_out_len));
1575 return NT_STATUS_INVALID_PARAMETER;
1578 offset = BVAL(in_data,0);
1579 length = BVAL(in_data,8);
1581 if (offset + length < offset) {
1582 /* No 64-bit integer wrap. */
1583 return NT_STATUS_INVALID_PARAMETER;
1586 /* Shouldn't this be SMB_VFS_STAT ... ? */
1587 status = vfs_stat_fsp(fsp);
1588 if (!NT_STATUS_IS_OK(status)) {
1589 return status;
1592 *out_len = 16;
1593 out_data_tmp = talloc_array(ctx, char, *out_len);
1594 if (out_data_tmp == NULL) {
1595 DEBUG(10, ("unable to allocate memory for response\n"));
1596 return NT_STATUS_NO_MEMORY;
1599 if (offset > fsp->fsp_name->st.st_ex_size ||
1600 fsp->fsp_name->st.st_ex_size == 0 ||
1601 length == 0) {
1602 memset(out_data_tmp, 0, *out_len);
1603 } else {
1604 uint64_t end = offset + length;
1605 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1606 SBVAL(out_data_tmp, 0, 0);
1607 SBVAL(out_data_tmp, 8, end);
1610 *out_data = out_data_tmp;
1612 return NT_STATUS_OK;
1615 case FSCTL_IS_VOLUME_DIRTY:
1617 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1618 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1620 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1621 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1623 return NT_STATUS_INVALID_PARAMETER;
1626 default:
1628 * Only print once ... unfortunately there could be lots of
1629 * different FSCTLs that are called.
1631 if (!vfswrap_logged_ioctl_message) {
1632 vfswrap_logged_ioctl_message = true;
1633 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1634 __func__, function));
1638 return NT_STATUS_NOT_SUPPORTED;
1641 static bool vfswrap_is_offline(struct connection_struct *conn,
1642 const struct smb_filename *fname);
1644 static NTSTATUS vfswrap_get_dos_attributes(struct vfs_handle_struct *handle,
1645 struct smb_filename *smb_fname,
1646 uint32_t *dosmode)
1648 bool offline;
1650 offline = vfswrap_is_offline(handle->conn, smb_fname);
1651 if (offline) {
1652 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1655 return get_ea_dos_attribute(handle->conn, smb_fname, dosmode);
1658 struct vfswrap_get_dos_attributes_state {
1659 struct vfs_aio_state aio_state;
1660 connection_struct *conn;
1661 TALLOC_CTX *mem_ctx;
1662 struct tevent_context *ev;
1663 files_struct *dir_fsp;
1664 struct smb_filename *smb_fname;
1665 uint32_t dosmode;
1666 bool as_root;
1669 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1671 static struct tevent_req *vfswrap_get_dos_attributes_send(
1672 TALLOC_CTX *mem_ctx,
1673 struct tevent_context *ev,
1674 struct vfs_handle_struct *handle,
1675 files_struct *dir_fsp,
1676 struct smb_filename *smb_fname)
1678 struct tevent_req *req = NULL;
1679 struct tevent_req *subreq = NULL;
1680 struct vfswrap_get_dos_attributes_state *state = NULL;
1682 req = tevent_req_create(mem_ctx, &state,
1683 struct vfswrap_get_dos_attributes_state);
1684 if (req == NULL) {
1685 return NULL;
1688 *state = (struct vfswrap_get_dos_attributes_state) {
1689 .conn = dir_fsp->conn,
1690 .mem_ctx = mem_ctx,
1691 .ev = ev,
1692 .dir_fsp = dir_fsp,
1693 .smb_fname = smb_fname,
1696 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1698 dir_fsp,
1699 smb_fname,
1700 SAMBA_XATTR_DOS_ATTRIB,
1701 sizeof(fstring));
1702 if (tevent_req_nomem(subreq, req)) {
1703 return tevent_req_post(req, ev);
1705 tevent_req_set_callback(subreq,
1706 vfswrap_get_dos_attributes_getxattr_done,
1707 req);
1709 return req;
1712 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1714 struct tevent_req *req =
1715 tevent_req_callback_data(subreq,
1716 struct tevent_req);
1717 struct vfswrap_get_dos_attributes_state *state =
1718 tevent_req_data(req,
1719 struct vfswrap_get_dos_attributes_state);
1720 ssize_t xattr_size;
1721 DATA_BLOB blob = {0};
1722 char *path = NULL;
1723 char *tofree = NULL;
1724 char pathbuf[PATH_MAX+1];
1725 ssize_t pathlen;
1726 struct smb_filename smb_fname;
1727 bool offline;
1728 NTSTATUS status;
1730 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1731 &state->aio_state,
1732 state,
1733 &blob.data);
1734 TALLOC_FREE(subreq);
1735 if (xattr_size == -1) {
1736 status = map_nt_error_from_unix(state->aio_state.error);
1738 if (state->as_root) {
1739 tevent_req_nterror(req, status);
1740 return;
1742 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1743 tevent_req_nterror(req, status);
1744 return;
1747 state->as_root = true;
1749 become_root();
1750 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1751 state->ev,
1752 state->dir_fsp,
1753 state->smb_fname,
1754 SAMBA_XATTR_DOS_ATTRIB,
1755 sizeof(fstring));
1756 unbecome_root();
1757 if (tevent_req_nomem(subreq, req)) {
1758 return;
1760 tevent_req_set_callback(subreq,
1761 vfswrap_get_dos_attributes_getxattr_done,
1762 req);
1763 return;
1766 blob.length = xattr_size;
1768 status = parse_dos_attribute_blob(state->smb_fname,
1769 blob,
1770 &state->dosmode);
1771 if (!NT_STATUS_IS_OK(status)) {
1772 tevent_req_nterror(req, status);
1773 return;
1776 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1777 state->smb_fname->base_name,
1778 pathbuf,
1779 sizeof(pathbuf),
1780 &path,
1781 &tofree);
1782 if (pathlen == -1) {
1783 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1784 return;
1787 smb_fname = (struct smb_filename) {
1788 .base_name = path,
1789 .st = state->smb_fname->st,
1790 .flags = state->smb_fname->flags,
1793 offline = vfswrap_is_offline(state->conn, &smb_fname);
1794 if (offline) {
1795 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1797 TALLOC_FREE(tofree);
1799 tevent_req_done(req);
1800 return;
1803 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1804 struct vfs_aio_state *aio_state,
1805 uint32_t *dosmode)
1807 struct vfswrap_get_dos_attributes_state *state =
1808 tevent_req_data(req,
1809 struct vfswrap_get_dos_attributes_state);
1810 NTSTATUS status;
1812 if (tevent_req_is_nterror(req, &status)) {
1813 tevent_req_received(req);
1814 return status;
1817 *aio_state = state->aio_state;
1818 *dosmode = state->dosmode;
1819 tevent_req_received(req);
1820 return NT_STATUS_OK;
1823 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1824 struct files_struct *fsp,
1825 uint32_t *dosmode)
1827 bool offline;
1829 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1830 if (offline) {
1831 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1834 return get_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1837 static NTSTATUS vfswrap_set_dos_attributes(struct vfs_handle_struct *handle,
1838 const struct smb_filename *smb_fname,
1839 uint32_t dosmode)
1841 return set_ea_dos_attribute(handle->conn, smb_fname, dosmode);
1844 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1845 struct files_struct *fsp,
1846 uint32_t dosmode)
1848 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1851 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1853 struct vfswrap_offload_read_state {
1854 DATA_BLOB token;
1857 static struct tevent_req *vfswrap_offload_read_send(
1858 TALLOC_CTX *mem_ctx,
1859 struct tevent_context *ev,
1860 struct vfs_handle_struct *handle,
1861 struct files_struct *fsp,
1862 uint32_t fsctl,
1863 uint32_t ttl,
1864 off_t offset,
1865 size_t to_copy)
1867 struct tevent_req *req = NULL;
1868 struct vfswrap_offload_read_state *state = NULL;
1869 NTSTATUS status;
1871 req = tevent_req_create(mem_ctx, &state,
1872 struct vfswrap_offload_read_state);
1873 if (req == NULL) {
1874 return NULL;
1877 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
1878 &vfswrap_offload_ctx);
1879 if (tevent_req_nterror(req, status)) {
1880 return tevent_req_post(req, ev);
1883 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
1884 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
1885 return tevent_req_post(req, ev);
1888 status = vfs_offload_token_create_blob(state, fsp, fsctl,
1889 &state->token);
1890 if (tevent_req_nterror(req, status)) {
1891 return tevent_req_post(req, ev);
1894 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
1895 &state->token);
1896 if (tevent_req_nterror(req, status)) {
1897 return tevent_req_post(req, ev);
1900 tevent_req_done(req);
1901 return tevent_req_post(req, ev);
1904 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
1905 struct vfs_handle_struct *handle,
1906 TALLOC_CTX *mem_ctx,
1907 DATA_BLOB *token)
1909 struct vfswrap_offload_read_state *state = tevent_req_data(
1910 req, struct vfswrap_offload_read_state);
1911 NTSTATUS status;
1913 if (tevent_req_is_nterror(req, &status)) {
1914 tevent_req_received(req);
1915 return status;
1918 token->length = state->token.length;
1919 token->data = talloc_move(mem_ctx, &state->token.data);
1921 tevent_req_received(req);
1922 return NT_STATUS_OK;
1925 struct vfswrap_offload_write_state {
1926 uint8_t *buf;
1927 bool read_lck_locked;
1928 bool write_lck_locked;
1929 DATA_BLOB *token;
1930 struct tevent_context *src_ev;
1931 struct files_struct *src_fsp;
1932 off_t src_off;
1933 struct tevent_context *dst_ev;
1934 struct files_struct *dst_fsp;
1935 off_t dst_off;
1936 off_t to_copy;
1937 off_t remaining;
1938 size_t next_io_size;
1941 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
1942 enum tevent_req_state req_state)
1944 struct vfswrap_offload_write_state *state = tevent_req_data(
1945 req, struct vfswrap_offload_write_state);
1946 bool ok;
1948 if (state->dst_fsp == NULL) {
1949 return;
1952 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
1953 SMB_ASSERT(ok);
1954 state->dst_fsp = NULL;
1957 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
1959 static struct tevent_req *vfswrap_offload_write_send(
1960 struct vfs_handle_struct *handle,
1961 TALLOC_CTX *mem_ctx,
1962 struct tevent_context *ev,
1963 uint32_t fsctl,
1964 DATA_BLOB *token,
1965 off_t transfer_offset,
1966 struct files_struct *dest_fsp,
1967 off_t dest_off,
1968 off_t to_copy)
1970 struct tevent_req *req;
1971 struct vfswrap_offload_write_state *state = NULL;
1972 /* off_t is signed! */
1973 off_t max_offset = INT64_MAX - to_copy;
1974 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
1975 files_struct *src_fsp = NULL;
1976 NTSTATUS status;
1977 bool ok;
1979 req = tevent_req_create(mem_ctx, &state,
1980 struct vfswrap_offload_write_state);
1981 if (req == NULL) {
1982 return NULL;
1985 *state = (struct vfswrap_offload_write_state) {
1986 .token = token,
1987 .src_off = transfer_offset,
1988 .dst_ev = ev,
1989 .dst_fsp = dest_fsp,
1990 .dst_off = dest_off,
1991 .to_copy = to_copy,
1992 .remaining = to_copy,
1995 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
1997 switch (fsctl) {
1998 case FSCTL_SRV_COPYCHUNK:
1999 case FSCTL_SRV_COPYCHUNK_WRITE:
2000 break;
2002 case FSCTL_OFFLOAD_WRITE:
2003 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2004 return tevent_req_post(req, ev);
2006 case FSCTL_DUP_EXTENTS_TO_FILE:
2007 DBG_DEBUG("COW clones not supported by vfs_default\n");
2008 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2009 return tevent_req_post(req, ev);
2011 default:
2012 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2013 return tevent_req_post(req, ev);
2017 * From here on we assume a copy-chunk fsctl
2020 if (to_copy == 0) {
2021 tevent_req_done(req);
2022 return tevent_req_post(req, ev);
2025 if (state->src_off > max_offset) {
2027 * Protect integer checks below.
2029 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2030 return tevent_req_post(req, ev);
2032 if (state->src_off < 0) {
2034 * Protect integer checks below.
2036 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2037 return tevent_req_post(req, ev);
2039 if (state->dst_off > max_offset) {
2041 * Protect integer checks below.
2043 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2044 return tevent_req_post(req, ev);
2046 if (state->dst_off < 0) {
2048 * Protect integer checks below.
2050 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2051 return tevent_req_post(req, ev);
2054 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2055 token, &src_fsp);
2056 if (tevent_req_nterror(req, status)) {
2057 return tevent_req_post(req, ev);
2060 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2062 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2063 if (!NT_STATUS_IS_OK(status)) {
2064 tevent_req_nterror(req, status);
2065 return tevent_req_post(req, ev);
2068 ok = change_to_user_and_service_by_fsp(src_fsp);
2069 if (!ok) {
2070 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2071 return tevent_req_post(req, ev);
2074 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2075 state->src_fsp = src_fsp;
2077 status = vfs_stat_fsp(src_fsp);
2078 if (tevent_req_nterror(req, status)) {
2079 return tevent_req_post(req, ev);
2082 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2084 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2085 * If the SourceOffset or SourceOffset + Length extends beyond
2086 * the end of file, the server SHOULD<240> treat this as a
2087 * STATUS_END_OF_FILE error.
2088 * ...
2089 * <240> Section 3.3.5.15.6: Windows servers will return
2090 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2092 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2093 return tevent_req_post(req, ev);
2096 state->buf = talloc_array(state, uint8_t, num);
2097 if (tevent_req_nomem(state->buf, req)) {
2098 return tevent_req_post(req, ev);
2101 status = vfswrap_offload_write_loop(req);
2102 if (!NT_STATUS_IS_OK(status)) {
2103 tevent_req_nterror(req, status);
2104 return tevent_req_post(req, ev);
2107 return req;
2110 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2112 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2114 struct vfswrap_offload_write_state *state = tevent_req_data(
2115 req, struct vfswrap_offload_write_state);
2116 struct tevent_req *subreq = NULL;
2117 struct lock_struct read_lck;
2118 bool ok;
2121 * This is called under the context of state->src_fsp.
2124 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2126 init_strict_lock_struct(state->src_fsp,
2127 state->src_fsp->op->global->open_persistent_id,
2128 state->src_off,
2129 state->next_io_size,
2130 READ_LOCK,
2131 &read_lck);
2133 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2134 state->src_fsp,
2135 &read_lck);
2136 if (!ok) {
2137 return NT_STATUS_FILE_LOCK_CONFLICT;
2140 subreq = SMB_VFS_PREAD_SEND(state,
2141 state->src_ev,
2142 state->src_fsp,
2143 state->buf,
2144 state->next_io_size,
2145 state->src_off);
2146 if (subreq == NULL) {
2147 return NT_STATUS_NO_MEMORY;
2149 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2151 return NT_STATUS_OK;
2154 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2156 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2158 struct tevent_req *req = tevent_req_callback_data(
2159 subreq, struct tevent_req);
2160 struct vfswrap_offload_write_state *state = tevent_req_data(
2161 req, struct vfswrap_offload_write_state);
2162 struct vfs_aio_state aio_state;
2163 struct lock_struct write_lck;
2164 ssize_t nread;
2165 bool ok;
2167 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2168 TALLOC_FREE(subreq);
2169 if (nread == -1) {
2170 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2171 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2172 return;
2174 if (nread != state->next_io_size) {
2175 DBG_ERR("Short read, only %zd of %zu\n",
2176 nread, state->next_io_size);
2177 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2178 return;
2181 state->src_off += nread;
2183 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2184 if (!ok) {
2185 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2186 return;
2189 init_strict_lock_struct(state->dst_fsp,
2190 state->dst_fsp->op->global->open_persistent_id,
2191 state->dst_off,
2192 state->next_io_size,
2193 WRITE_LOCK,
2194 &write_lck);
2196 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2197 state->dst_fsp,
2198 &write_lck);
2199 if (!ok) {
2200 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2201 return;
2204 subreq = SMB_VFS_PWRITE_SEND(state,
2205 state->dst_ev,
2206 state->dst_fsp,
2207 state->buf,
2208 state->next_io_size,
2209 state->dst_off);
2210 if (subreq == NULL) {
2211 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2212 return;
2214 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2217 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2219 struct tevent_req *req = tevent_req_callback_data(
2220 subreq, struct tevent_req);
2221 struct vfswrap_offload_write_state *state = tevent_req_data(
2222 req, struct vfswrap_offload_write_state);
2223 struct vfs_aio_state aio_state;
2224 ssize_t nwritten;
2225 NTSTATUS status;
2226 bool ok;
2228 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2229 TALLOC_FREE(subreq);
2230 if (nwritten == -1) {
2231 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2232 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2233 return;
2235 if (nwritten != state->next_io_size) {
2236 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2237 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2238 return;
2241 state->dst_off += nwritten;
2243 if (state->remaining < nwritten) {
2244 /* Paranoia check */
2245 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2246 return;
2248 state->remaining -= nwritten;
2249 if (state->remaining == 0) {
2250 tevent_req_done(req);
2251 return;
2254 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2255 if (!ok) {
2256 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2257 return;
2260 status = vfswrap_offload_write_loop(req);
2261 if (!NT_STATUS_IS_OK(status)) {
2262 tevent_req_nterror(req, status);
2263 return;
2266 return;
2269 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2270 struct tevent_req *req,
2271 off_t *copied)
2273 struct vfswrap_offload_write_state *state = tevent_req_data(
2274 req, struct vfswrap_offload_write_state);
2275 NTSTATUS status;
2277 if (tevent_req_is_nterror(req, &status)) {
2278 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2279 *copied = 0;
2280 tevent_req_received(req);
2281 return status;
2284 *copied = state->to_copy;
2285 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2286 tevent_req_received(req);
2288 return NT_STATUS_OK;
2291 static NTSTATUS vfswrap_get_compression(struct vfs_handle_struct *handle,
2292 TALLOC_CTX *mem_ctx,
2293 struct files_struct *fsp,
2294 struct smb_filename *smb_fname,
2295 uint16_t *_compression_fmt)
2297 return NT_STATUS_INVALID_DEVICE_REQUEST;
2300 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2301 TALLOC_CTX *mem_ctx,
2302 struct files_struct *fsp,
2303 uint16_t compression_fmt)
2305 return NT_STATUS_INVALID_DEVICE_REQUEST;
2308 /********************************************************************
2309 Given a stat buffer return the allocated size on disk, taking into
2310 account sparse files.
2311 ********************************************************************/
2312 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2313 struct files_struct *fsp,
2314 const SMB_STRUCT_STAT *sbuf)
2316 uint64_t result;
2318 START_PROFILE(syscall_get_alloc_size);
2320 if(S_ISDIR(sbuf->st_ex_mode)) {
2321 result = 0;
2322 goto out;
2325 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2326 /* The type of st_blocksize is blkcnt_t which *MUST* be
2327 signed (according to POSIX) and can be less than 64-bits.
2328 Ensure when we're converting to 64 bits wide we don't
2329 sign extend. */
2330 #if defined(SIZEOF_BLKCNT_T_8)
2331 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2332 #elif defined(SIZEOF_BLKCNT_T_4)
2334 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2335 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2337 #else
2338 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2339 #endif
2340 if (result == 0) {
2342 * Some file systems do not allocate a block for very
2343 * small files. But for non-empty file should report a
2344 * positive size.
2347 uint64_t filesize = get_file_size_stat(sbuf);
2348 if (filesize > 0) {
2349 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2352 #else
2353 result = get_file_size_stat(sbuf);
2354 #endif
2356 if (fsp && fsp->initial_allocation_size)
2357 result = MAX(result,fsp->initial_allocation_size);
2359 result = smb_roundup(handle->conn, result);
2361 out:
2362 END_PROFILE(syscall_get_alloc_size);
2363 return result;
2366 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2367 struct files_struct *dirfsp,
2368 const struct smb_filename *smb_fname,
2369 int flags)
2371 int result = -1;
2373 START_PROFILE(syscall_unlinkat);
2375 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2377 if (is_named_stream(smb_fname)) {
2378 errno = ENOENT;
2379 goto out;
2381 result = unlinkat(dirfsp->fh->fd,
2382 smb_fname->base_name,
2383 flags);
2385 out:
2386 END_PROFILE(syscall_unlinkat);
2387 return result;
2390 static int vfswrap_chmod(vfs_handle_struct *handle,
2391 const struct smb_filename *smb_fname,
2392 mode_t mode)
2394 int result;
2396 START_PROFILE(syscall_chmod);
2397 result = chmod(smb_fname->base_name, mode);
2398 END_PROFILE(syscall_chmod);
2399 return result;
2402 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2404 int result;
2406 START_PROFILE(syscall_fchmod);
2407 #if defined(HAVE_FCHMOD)
2408 result = fchmod(fsp->fh->fd, mode);
2409 #else
2410 result = -1;
2411 errno = ENOSYS;
2412 #endif
2414 END_PROFILE(syscall_fchmod);
2415 return result;
2418 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2420 #ifdef HAVE_FCHOWN
2421 int result;
2423 START_PROFILE(syscall_fchown);
2424 result = fchown(fsp->fh->fd, uid, gid);
2425 END_PROFILE(syscall_fchown);
2426 return result;
2427 #else
2428 errno = ENOSYS;
2429 return -1;
2430 #endif
2433 static int vfswrap_lchown(vfs_handle_struct *handle,
2434 const struct smb_filename *smb_fname,
2435 uid_t uid,
2436 gid_t gid)
2438 int result;
2440 START_PROFILE(syscall_lchown);
2441 result = lchown(smb_fname->base_name, uid, gid);
2442 END_PROFILE(syscall_lchown);
2443 return result;
2446 static int vfswrap_chdir(vfs_handle_struct *handle,
2447 const struct smb_filename *smb_fname)
2449 int result;
2451 START_PROFILE(syscall_chdir);
2452 result = chdir(smb_fname->base_name);
2453 END_PROFILE(syscall_chdir);
2454 return result;
2457 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2458 TALLOC_CTX *ctx)
2460 char *result;
2461 struct smb_filename *smb_fname = NULL;
2463 START_PROFILE(syscall_getwd);
2464 result = sys_getwd();
2465 END_PROFILE(syscall_getwd);
2467 if (result == NULL) {
2468 return NULL;
2470 smb_fname = synthetic_smb_fname(ctx,
2471 result,
2472 NULL,
2473 NULL,
2476 * sys_getwd() *always* returns malloced memory.
2477 * We must free here to avoid leaks:
2478 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2480 SAFE_FREE(result);
2481 return smb_fname;
2484 /*********************************************************************
2485 nsec timestamp resolution call. Convert down to whatever the underlying
2486 system will support.
2487 **********************************************************************/
2489 static int vfswrap_ntimes(vfs_handle_struct *handle,
2490 const struct smb_filename *smb_fname,
2491 struct smb_file_time *ft)
2493 int result = -1;
2495 START_PROFILE(syscall_ntimes);
2497 if (is_named_stream(smb_fname)) {
2498 errno = ENOENT;
2499 goto out;
2502 if (ft != NULL) {
2503 if (is_omit_timespec(&ft->atime)) {
2504 ft->atime= smb_fname->st.st_ex_atime;
2507 if (is_omit_timespec(&ft->mtime)) {
2508 ft->mtime = smb_fname->st.st_ex_mtime;
2511 if (!is_omit_timespec(&ft->create_time)) {
2512 set_create_timespec_ea(handle->conn,
2513 smb_fname,
2514 ft->create_time);
2517 if ((timespec_compare(&ft->atime,
2518 &smb_fname->st.st_ex_atime) == 0) &&
2519 (timespec_compare(&ft->mtime,
2520 &smb_fname->st.st_ex_mtime) == 0)) {
2521 return 0;
2525 #if defined(HAVE_UTIMENSAT)
2526 if (ft != NULL) {
2527 struct timespec ts[2];
2528 ts[0] = ft->atime;
2529 ts[1] = ft->mtime;
2530 result = utimensat(AT_FDCWD, smb_fname->base_name, ts, 0);
2531 } else {
2532 result = utimensat(AT_FDCWD, smb_fname->base_name, NULL, 0);
2534 if (!((result == -1) && (errno == ENOSYS))) {
2535 goto out;
2537 #endif
2538 #if defined(HAVE_UTIMES)
2539 if (ft != NULL) {
2540 struct timeval tv[2];
2541 tv[0] = convert_timespec_to_timeval(ft->atime);
2542 tv[1] = convert_timespec_to_timeval(ft->mtime);
2543 result = utimes(smb_fname->base_name, tv);
2544 } else {
2545 result = utimes(smb_fname->base_name, NULL);
2547 if (!((result == -1) && (errno == ENOSYS))) {
2548 goto out;
2550 #endif
2551 #if defined(HAVE_UTIME)
2552 if (ft != NULL) {
2553 struct utimbuf times;
2554 times.actime = convert_timespec_to_time_t(ft->atime);
2555 times.modtime = convert_timespec_to_time_t(ft->mtime);
2556 result = utime(smb_fname->base_name, &times);
2557 } else {
2558 result = utime(smb_fname->base_name, NULL);
2560 if (!((result == -1) && (errno == ENOSYS))) {
2561 goto out;
2563 #endif
2564 errno = ENOSYS;
2565 result = -1;
2567 out:
2568 END_PROFILE(syscall_ntimes);
2569 return result;
2572 /*********************************************************************
2573 A version of ftruncate that will write the space on disk if strict
2574 allocate is set.
2575 **********************************************************************/
2577 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2579 off_t space_to_write;
2580 uint64_t space_avail;
2581 uint64_t bsize,dfree,dsize;
2582 int ret;
2583 NTSTATUS status;
2584 SMB_STRUCT_STAT *pst;
2585 bool ok;
2587 ok = vfs_valid_pwrite_range(len, 0);
2588 if (!ok) {
2589 errno = EINVAL;
2590 return -1;
2593 status = vfs_stat_fsp(fsp);
2594 if (!NT_STATUS_IS_OK(status)) {
2595 return -1;
2597 pst = &fsp->fsp_name->st;
2599 #ifdef S_ISFIFO
2600 if (S_ISFIFO(pst->st_ex_mode))
2601 return 0;
2602 #endif
2604 if (pst->st_ex_size == len)
2605 return 0;
2607 /* Shrink - just ftruncate. */
2608 if (pst->st_ex_size > len)
2609 return ftruncate(fsp->fh->fd, len);
2611 space_to_write = len - pst->st_ex_size;
2613 /* for allocation try fallocate first. This can fail on some
2614 platforms e.g. when the filesystem doesn't support it and no
2615 emulation is being done by the libc (like on AIX with JFS1). In that
2616 case we do our own emulation. fallocate implementations can
2617 return ENOTSUP or EINVAL in cases like that. */
2618 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2619 if (ret == -1 && errno == ENOSPC) {
2620 return -1;
2622 if (ret == 0) {
2623 return 0;
2625 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2626 "error %d. Falling back to slow manual allocation\n", errno));
2628 /* available disk space is enough or not? */
2629 space_avail =
2630 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2631 /* space_avail is 1k blocks */
2632 if (space_avail == (uint64_t)-1 ||
2633 ((uint64_t)space_to_write/1024 > space_avail) ) {
2634 errno = ENOSPC;
2635 return -1;
2638 /* Write out the real space on disk. */
2639 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2640 if (ret != 0) {
2641 return -1;
2644 return 0;
2647 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2649 int result = -1;
2650 SMB_STRUCT_STAT *pst;
2651 NTSTATUS status;
2652 char c = 0;
2654 START_PROFILE(syscall_ftruncate);
2656 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->is_sparse) {
2657 result = strict_allocate_ftruncate(handle, fsp, len);
2658 END_PROFILE(syscall_ftruncate);
2659 return result;
2662 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2663 ftruncate if the system supports it. Then I discovered that
2664 you can have some filesystems that support ftruncate
2665 expansion and some that don't! On Linux fat can't do
2666 ftruncate extend but ext2 can. */
2668 result = ftruncate(fsp->fh->fd, len);
2670 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2671 extend a file with ftruncate. Provide alternate implementation
2672 for this */
2674 /* Do an fstat to see if the file is longer than the requested
2675 size in which case the ftruncate above should have
2676 succeeded or shorter, in which case seek to len - 1 and
2677 write 1 byte of zero */
2678 status = vfs_stat_fsp(fsp);
2679 if (!NT_STATUS_IS_OK(status)) {
2680 goto done;
2683 /* We need to update the files_struct after successful ftruncate */
2684 if (result == 0) {
2685 goto done;
2688 pst = &fsp->fsp_name->st;
2690 #ifdef S_ISFIFO
2691 if (S_ISFIFO(pst->st_ex_mode)) {
2692 result = 0;
2693 goto done;
2695 #endif
2697 if (pst->st_ex_size == len) {
2698 result = 0;
2699 goto done;
2702 if (pst->st_ex_size > len) {
2703 /* the ftruncate should have worked */
2704 goto done;
2707 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
2708 goto done;
2711 result = 0;
2713 done:
2715 END_PROFILE(syscall_ftruncate);
2716 return result;
2719 static int vfswrap_fallocate(vfs_handle_struct *handle,
2720 files_struct *fsp,
2721 uint32_t mode,
2722 off_t offset,
2723 off_t len)
2725 int result;
2727 START_PROFILE(syscall_fallocate);
2728 if (mode == 0) {
2729 result = sys_posix_fallocate(fsp->fh->fd, offset, len);
2731 * posix_fallocate returns 0 on success, errno on error
2732 * and doesn't set errno. Make it behave like fallocate()
2733 * which returns -1, and sets errno on failure.
2735 if (result != 0) {
2736 errno = result;
2737 result = -1;
2739 } else {
2740 /* sys_fallocate handles filtering of unsupported mode flags */
2741 result = sys_fallocate(fsp->fh->fd, mode, offset, len);
2743 END_PROFILE(syscall_fallocate);
2744 return result;
2747 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
2749 bool result;
2751 START_PROFILE(syscall_fcntl_lock);
2753 if (fsp->use_ofd_locks) {
2754 op = map_process_lock_to_ofd_lock(op);
2757 result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
2758 END_PROFILE(syscall_fcntl_lock);
2759 return result;
2762 static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
2763 uint32_t share_access, uint32_t access_mask)
2765 START_PROFILE(syscall_kernel_flock);
2766 kernel_flock(fsp->fh->fd, share_access, access_mask);
2767 END_PROFILE(syscall_kernel_flock);
2768 return 0;
2771 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
2772 va_list cmd_arg)
2774 void *argp;
2775 va_list dup_cmd_arg;
2776 int result;
2777 int val;
2779 START_PROFILE(syscall_fcntl);
2781 va_copy(dup_cmd_arg, cmd_arg);
2783 switch(cmd) {
2784 case F_SETLK:
2785 case F_SETLKW:
2786 case F_GETLK:
2787 #if defined(HAVE_OFD_LOCKS)
2788 case F_OFD_SETLK:
2789 case F_OFD_SETLKW:
2790 case F_OFD_GETLK:
2791 #endif
2792 #if defined(HAVE_F_OWNER_EX)
2793 case F_GETOWN_EX:
2794 case F_SETOWN_EX:
2795 #endif
2796 #if defined(HAVE_RW_HINTS)
2797 case F_GET_RW_HINT:
2798 case F_SET_RW_HINT:
2799 case F_GET_FILE_RW_HINT:
2800 case F_SET_FILE_RW_HINT:
2801 #endif
2802 argp = va_arg(dup_cmd_arg, void *);
2803 result = sys_fcntl_ptr(fsp->fh->fd, cmd, argp);
2804 break;
2805 default:
2806 val = va_arg(dup_cmd_arg, int);
2807 result = sys_fcntl_int(fsp->fh->fd, cmd, val);
2810 va_end(dup_cmd_arg);
2812 END_PROFILE(syscall_fcntl);
2813 return result;
2816 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
2818 bool result;
2819 int op = F_GETLK;
2821 START_PROFILE(syscall_fcntl_getlock);
2823 if (fsp->use_ofd_locks) {
2824 op = map_process_lock_to_ofd_lock(op);
2827 result = fcntl_getlock(fsp->fh->fd, op, poffset, pcount, ptype, ppid);
2828 END_PROFILE(syscall_fcntl_getlock);
2829 return result;
2832 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
2833 int leasetype)
2835 int result = -1;
2837 START_PROFILE(syscall_linux_setlease);
2839 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
2840 result = linux_setlease(fsp->fh->fd, leasetype);
2841 #else
2842 errno = ENOSYS;
2843 #endif
2844 END_PROFILE(syscall_linux_setlease);
2845 return result;
2848 static int vfswrap_symlinkat(vfs_handle_struct *handle,
2849 const char *link_target,
2850 struct files_struct *dirfsp,
2851 const struct smb_filename *new_smb_fname)
2853 int result;
2855 START_PROFILE(syscall_symlinkat);
2857 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2859 result = symlinkat(link_target,
2860 dirfsp->fh->fd,
2861 new_smb_fname->base_name);
2862 END_PROFILE(syscall_symlinkat);
2863 return result;
2866 static int vfswrap_readlinkat(vfs_handle_struct *handle,
2867 files_struct *dirfsp,
2868 const struct smb_filename *smb_fname,
2869 char *buf,
2870 size_t bufsiz)
2872 int result;
2874 START_PROFILE(syscall_readlinkat);
2876 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2878 result = readlinkat(dirfsp->fh->fd,
2879 smb_fname->base_name,
2880 buf,
2881 bufsiz);
2883 END_PROFILE(syscall_readlinkat);
2884 return result;
2887 static int vfswrap_linkat(vfs_handle_struct *handle,
2888 files_struct *srcfsp,
2889 const struct smb_filename *old_smb_fname,
2890 files_struct *dstfsp,
2891 const struct smb_filename *new_smb_fname,
2892 int flags)
2894 int result;
2896 START_PROFILE(syscall_linkat);
2898 SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
2899 SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
2901 result = linkat(srcfsp->fh->fd,
2902 old_smb_fname->base_name,
2903 dstfsp->fh->fd,
2904 new_smb_fname->base_name,
2905 flags);
2907 END_PROFILE(syscall_linkat);
2908 return result;
2911 static int vfswrap_mknodat(vfs_handle_struct *handle,
2912 files_struct *dirfsp,
2913 const struct smb_filename *smb_fname,
2914 mode_t mode,
2915 SMB_DEV_T dev)
2917 int result;
2919 START_PROFILE(syscall_mknodat);
2921 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2923 result = sys_mknodat(dirfsp->fh->fd,
2924 smb_fname->base_name,
2925 mode,
2926 dev);
2928 END_PROFILE(syscall_mknodat);
2929 return result;
2932 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
2933 TALLOC_CTX *ctx,
2934 const struct smb_filename *smb_fname)
2936 char *result;
2937 struct smb_filename *result_fname = NULL;
2939 START_PROFILE(syscall_realpath);
2940 result = sys_realpath(smb_fname->base_name);
2941 END_PROFILE(syscall_realpath);
2942 if (result) {
2943 result_fname = synthetic_smb_fname(ctx, result, NULL, NULL, 0);
2944 SAFE_FREE(result);
2946 return result_fname;
2949 static int vfswrap_chflags(vfs_handle_struct *handle,
2950 const struct smb_filename *smb_fname,
2951 unsigned int flags)
2953 #ifdef HAVE_CHFLAGS
2954 return chflags(smb_fname->base_name, flags);
2955 #else
2956 errno = ENOSYS;
2957 return -1;
2958 #endif
2961 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
2962 const SMB_STRUCT_STAT *sbuf)
2964 struct file_id key;
2966 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
2967 * blob */
2968 ZERO_STRUCT(key);
2970 key.devid = sbuf->st_ex_dev;
2971 key.inode = sbuf->st_ex_ino;
2972 /* key.extid is unused by default. */
2974 return key;
2977 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
2978 const SMB_STRUCT_STAT *psbuf)
2980 uint64_t file_id;
2982 if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
2983 return psbuf->st_ex_file_id;
2986 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
2987 return (uint64_t)psbuf->st_ex_ino;
2990 /* FileIDLow */
2991 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
2993 /* FileIDHigh */
2994 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
2996 return file_id;
2999 static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
3000 struct files_struct *fsp,
3001 const struct smb_filename *smb_fname,
3002 TALLOC_CTX *mem_ctx,
3003 unsigned int *pnum_streams,
3004 struct stream_struct **pstreams)
3006 SMB_STRUCT_STAT sbuf;
3007 struct stream_struct *tmp_streams = NULL;
3008 int ret;
3010 if ((fsp != NULL) && (fsp->is_directory)) {
3012 * No default streams on directories
3014 goto done;
3017 if ((fsp != NULL) && (fsp->fh->fd != -1)) {
3018 ret = SMB_VFS_FSTAT(fsp, &sbuf);
3020 else {
3021 struct smb_filename smb_fname_cp;
3023 ZERO_STRUCT(smb_fname_cp);
3024 smb_fname_cp.base_name = discard_const_p(char,
3025 smb_fname->base_name);
3026 smb_fname_cp.flags = smb_fname->flags;
3028 if (smb_fname_cp.flags & SMB_FILENAME_POSIX_PATH) {
3029 ret = SMB_VFS_LSTAT(handle->conn, &smb_fname_cp);
3030 } else {
3031 ret = SMB_VFS_STAT(handle->conn, &smb_fname_cp);
3033 sbuf = smb_fname_cp.st;
3036 if (ret == -1) {
3037 return map_nt_error_from_unix(errno);
3040 if (S_ISDIR(sbuf.st_ex_mode)) {
3041 goto done;
3044 tmp_streams = talloc_realloc(mem_ctx, *pstreams, struct stream_struct,
3045 (*pnum_streams) + 1);
3046 if (tmp_streams == NULL) {
3047 return NT_STATUS_NO_MEMORY;
3049 tmp_streams[*pnum_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3050 if (tmp_streams[*pnum_streams].name == NULL) {
3051 return NT_STATUS_NO_MEMORY;
3053 tmp_streams[*pnum_streams].size = sbuf.st_ex_size;
3054 tmp_streams[*pnum_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, &sbuf);
3056 *pnum_streams += 1;
3057 *pstreams = tmp_streams;
3058 done:
3059 return NT_STATUS_OK;
3062 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
3063 const char *path,
3064 const char *name,
3065 TALLOC_CTX *mem_ctx,
3066 char **found_name)
3069 * Don't fall back to get_real_filename so callers can differentiate
3070 * between a full directory scan and an actual case-insensitive stat.
3072 errno = EOPNOTSUPP;
3073 return -1;
3076 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3077 const struct smb_filename *smb_fname)
3079 return handle->conn->connectpath;
3082 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3083 struct byte_range_lock *br_lck,
3084 struct lock_struct *plock)
3086 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3088 /* Note: blr is not used in the default implementation. */
3089 return brl_lock_windows_default(br_lck, plock);
3092 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3093 struct byte_range_lock *br_lck,
3094 const struct lock_struct *plock)
3096 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3098 return brl_unlock_windows_default(br_lck, plock);
3101 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3102 files_struct *fsp,
3103 struct lock_struct *plock)
3105 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3106 plock->lock_type == WRITE_LOCK);
3108 return strict_lock_check_default(fsp, plock);
3111 /* NT ACL operations. */
3113 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3114 files_struct *fsp,
3115 uint32_t security_info,
3116 TALLOC_CTX *mem_ctx,
3117 struct security_descriptor **ppdesc)
3119 NTSTATUS result;
3121 START_PROFILE(fget_nt_acl);
3122 result = posix_fget_nt_acl(fsp, security_info,
3123 mem_ctx, ppdesc);
3124 END_PROFILE(fget_nt_acl);
3125 return result;
3128 static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
3129 const struct smb_filename *smb_fname,
3130 uint32_t security_info,
3131 TALLOC_CTX *mem_ctx,
3132 struct security_descriptor **ppdesc)
3134 NTSTATUS result;
3136 START_PROFILE(get_nt_acl);
3137 result = posix_get_nt_acl(handle->conn,
3138 smb_fname,
3139 security_info,
3140 mem_ctx,
3141 ppdesc);
3142 END_PROFILE(get_nt_acl);
3143 return result;
3146 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3148 NTSTATUS result;
3150 START_PROFILE(fset_nt_acl);
3151 result = set_nt_acl(fsp, security_info_sent, psd);
3152 END_PROFILE(fset_nt_acl);
3153 return result;
3156 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3157 struct smb_filename *file,
3158 struct security_acl *sacl,
3159 uint32_t access_requested,
3160 uint32_t access_denied)
3162 return NT_STATUS_OK; /* Nothing to do here ... */
3165 static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle,
3166 const struct smb_filename *smb_fname,
3167 SMB_ACL_TYPE_T type,
3168 TALLOC_CTX *mem_ctx)
3170 return sys_acl_get_file(handle, smb_fname, type, mem_ctx);
3173 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3174 files_struct *fsp,
3175 TALLOC_CTX *mem_ctx)
3177 return sys_acl_get_fd(handle, fsp, mem_ctx);
3180 static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle,
3181 const struct smb_filename *smb_fname,
3182 SMB_ACL_TYPE_T acltype,
3183 SMB_ACL_T theacl)
3185 return sys_acl_set_file(handle, smb_fname, acltype, theacl);
3188 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
3190 return sys_acl_set_fd(handle, fsp, theacl);
3193 static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle,
3194 const struct smb_filename *smb_fname)
3196 return sys_acl_delete_def_file(handle, smb_fname);
3199 /****************************************************************
3200 Extended attribute operations.
3201 *****************************************************************/
3203 static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,
3204 const struct smb_filename *smb_fname,
3205 const char *name,
3206 void *value,
3207 size_t size)
3209 return getxattr(smb_fname->base_name, name, value, size);
3212 struct vfswrap_getxattrat_state {
3213 struct tevent_context *ev;
3214 files_struct *dir_fsp;
3215 const struct smb_filename *smb_fname;
3216 struct tevent_req *req;
3219 * The following variables are talloced off "state" which is protected
3220 * by a destructor and thus are guaranteed to be safe to be used in the
3221 * job function in the worker thread.
3223 char *name;
3224 const char *xattr_name;
3225 uint8_t *xattr_value;
3226 struct security_unix_token *token;
3228 ssize_t xattr_size;
3229 struct vfs_aio_state vfs_aio_state;
3230 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3233 static int vfswrap_getxattrat_state_destructor(
3234 struct vfswrap_getxattrat_state *state)
3236 return -1;
3239 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3240 static void vfswrap_getxattrat_do_async(void *private_data);
3241 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3243 static struct tevent_req *vfswrap_getxattrat_send(
3244 TALLOC_CTX *mem_ctx,
3245 struct tevent_context *ev,
3246 struct vfs_handle_struct *handle,
3247 files_struct *dir_fsp,
3248 const struct smb_filename *smb_fname,
3249 const char *xattr_name,
3250 size_t alloc_hint)
3252 struct tevent_req *req = NULL;
3253 struct tevent_req *subreq = NULL;
3254 struct vfswrap_getxattrat_state *state = NULL;
3255 size_t max_threads = 0;
3256 bool have_per_thread_cwd = false;
3257 bool have_per_thread_creds = false;
3258 bool do_async = false;
3260 req = tevent_req_create(mem_ctx, &state,
3261 struct vfswrap_getxattrat_state);
3262 if (req == NULL) {
3263 return NULL;
3265 *state = (struct vfswrap_getxattrat_state) {
3266 .ev = ev,
3267 .dir_fsp = dir_fsp,
3268 .smb_fname = smb_fname,
3269 .req = req,
3272 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3273 if (max_threads >= 1) {
3275 * We need a non sync threadpool!
3277 have_per_thread_cwd = per_thread_cwd_supported();
3279 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3280 have_per_thread_creds = true;
3281 #endif
3282 if (have_per_thread_cwd && have_per_thread_creds) {
3283 do_async = true;
3286 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3287 state->profile_bytes, 0);
3289 if (dir_fsp->fh->fd == -1) {
3290 DBG_ERR("Need a valid directory fd\n");
3291 tevent_req_error(req, EINVAL);
3292 return tevent_req_post(req, ev);
3295 if (alloc_hint > 0) {
3296 state->xattr_value = talloc_zero_array(state,
3297 uint8_t,
3298 alloc_hint);
3299 if (tevent_req_nomem(state->xattr_value, req)) {
3300 return tevent_req_post(req, ev);
3304 if (!do_async) {
3305 vfswrap_getxattrat_do_sync(req);
3306 return tevent_req_post(req, ev);
3310 * Now allocate all parameters from a memory context that won't go away
3311 * no matter what. These paremeters will get used in threads and we
3312 * can't reliably cancel threads, so all buffers passed to the threads
3313 * must not be freed before all referencing threads terminate.
3316 state->name = talloc_strdup(state, smb_fname->base_name);
3317 if (tevent_req_nomem(state->name, req)) {
3318 return tevent_req_post(req, ev);
3321 state->xattr_name = talloc_strdup(state, xattr_name);
3322 if (tevent_req_nomem(state->xattr_name, req)) {
3323 return tevent_req_post(req, ev);
3327 * This is a hot codepath so at first glance one might think we should
3328 * somehow optimize away the token allocation and do a
3329 * talloc_reference() or similar black magic instead. But due to the
3330 * talloc_stackframe pool per SMB2 request this should be a simple copy
3331 * without a malloc in most cases.
3333 if (geteuid() == sec_initial_uid()) {
3334 state->token = root_unix_token(state);
3335 } else {
3336 state->token = copy_unix_token(
3337 state,
3338 dir_fsp->conn->session_info->unix_token);
3340 if (tevent_req_nomem(state->token, req)) {
3341 return tevent_req_post(req, ev);
3344 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3346 subreq = pthreadpool_tevent_job_send(
3347 state,
3349 dir_fsp->conn->sconn->pool,
3350 vfswrap_getxattrat_do_async,
3351 state);
3352 if (tevent_req_nomem(subreq, req)) {
3353 return tevent_req_post(req, ev);
3355 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3357 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3359 return req;
3362 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3364 struct vfswrap_getxattrat_state *state = tevent_req_data(
3365 req, struct vfswrap_getxattrat_state);
3366 char *path = NULL;
3367 char *tofree = NULL;
3368 char pathbuf[PATH_MAX+1];
3369 ssize_t pathlen;
3370 int err;
3372 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
3373 state->smb_fname->base_name,
3374 pathbuf,
3375 sizeof(pathbuf),
3376 &path,
3377 &tofree);
3378 if (pathlen == -1) {
3379 tevent_req_error(req, ENOMEM);
3380 return;
3383 state->xattr_size = getxattr(path,
3384 state->xattr_name,
3385 state->xattr_value,
3386 talloc_array_length(state->xattr_value));
3387 err = errno;
3388 TALLOC_FREE(tofree);
3389 if (state->xattr_size == -1) {
3390 tevent_req_error(req, err);
3391 return;
3394 tevent_req_done(req);
3395 return;
3398 static void vfswrap_getxattrat_do_async(void *private_data)
3400 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3401 private_data, struct vfswrap_getxattrat_state);
3402 struct timespec start_time;
3403 struct timespec end_time;
3404 int ret;
3406 PROFILE_TIMESTAMP(&start_time);
3407 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3410 * Here we simulate a getxattrat()
3411 * call using fchdir();getxattr()
3414 per_thread_cwd_activate();
3416 /* Become the correct credential on this thread. */
3417 ret = set_thread_credentials(state->token->uid,
3418 state->token->gid,
3419 (size_t)state->token->ngroups,
3420 state->token->groups);
3421 if (ret != 0) {
3422 state->xattr_size = -1;
3423 state->vfs_aio_state.error = errno;
3424 goto end_profile;
3427 ret = fchdir(state->dir_fsp->fh->fd);
3428 if (ret == -1) {
3429 state->xattr_size = -1;
3430 state->vfs_aio_state.error = errno;
3431 goto end_profile;
3434 state->xattr_size = getxattr(state->name,
3435 state->xattr_name,
3436 state->xattr_value,
3437 talloc_array_length(state->xattr_value));
3438 if (state->xattr_size == -1) {
3439 state->vfs_aio_state.error = errno;
3442 end_profile:
3443 PROFILE_TIMESTAMP(&end_time);
3444 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3445 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3448 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3450 struct tevent_req *req = tevent_req_callback_data(
3451 subreq, struct tevent_req);
3452 struct vfswrap_getxattrat_state *state = tevent_req_data(
3453 req, struct vfswrap_getxattrat_state);
3454 int ret;
3455 bool ok;
3458 * Make sure we run as the user again
3460 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3461 SMB_ASSERT(ok);
3463 ret = pthreadpool_tevent_job_recv(subreq);
3464 TALLOC_FREE(subreq);
3465 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3466 talloc_set_destructor(state, NULL);
3467 if (ret != 0) {
3468 if (ret != EAGAIN) {
3469 tevent_req_error(req, ret);
3470 return;
3473 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3474 * means the lower level pthreadpool failed to create a new
3475 * thread. Fallback to sync processing in that case to allow
3476 * some progress for the client.
3478 vfswrap_getxattrat_do_sync(req);
3479 return;
3482 if (state->xattr_size == -1) {
3483 tevent_req_error(req, state->vfs_aio_state.error);
3484 return;
3487 if (state->xattr_value == NULL) {
3489 * The caller only wanted the size.
3491 tevent_req_done(req);
3492 return;
3496 * shrink the buffer to the returned size.
3497 * (can't fail). It means NULL if size is 0.
3499 state->xattr_value = talloc_realloc(state,
3500 state->xattr_value,
3501 uint8_t,
3502 state->xattr_size);
3504 tevent_req_done(req);
3507 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3508 struct vfs_aio_state *aio_state,
3509 TALLOC_CTX *mem_ctx,
3510 uint8_t **xattr_value)
3512 struct vfswrap_getxattrat_state *state = tevent_req_data(
3513 req, struct vfswrap_getxattrat_state);
3514 ssize_t xattr_size;
3516 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3517 tevent_req_received(req);
3518 return -1;
3521 *aio_state = state->vfs_aio_state;
3522 xattr_size = state->xattr_size;
3523 if (xattr_value != NULL) {
3524 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3527 tevent_req_received(req);
3528 return xattr_size;
3531 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
3533 return fgetxattr(fsp->fh->fd, name, value, size);
3536 static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle,
3537 const struct smb_filename *smb_fname,
3538 char *list,
3539 size_t size)
3541 return listxattr(smb_fname->base_name, list, size);
3544 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3546 return flistxattr(fsp->fh->fd, list, size);
3549 static int vfswrap_removexattr(struct vfs_handle_struct *handle,
3550 const struct smb_filename *smb_fname,
3551 const char *name)
3553 return removexattr(smb_fname->base_name, name);
3556 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3558 return fremovexattr(fsp->fh->fd, name);
3561 static int vfswrap_setxattr(struct vfs_handle_struct *handle,
3562 const struct smb_filename *smb_fname,
3563 const char *name,
3564 const void *value,
3565 size_t size,
3566 int flags)
3568 return setxattr(smb_fname->base_name, name, value, size, flags);
3571 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3573 return fsetxattr(fsp->fh->fd, name, value, size, flags);
3576 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3578 return false;
3581 static bool vfswrap_is_offline(struct connection_struct *conn,
3582 const struct smb_filename *fname)
3584 NTSTATUS status;
3585 char *path;
3586 bool offline = false;
3588 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3589 return false;
3592 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3593 #if defined(ENOTSUP)
3594 errno = ENOTSUP;
3595 #endif
3596 return false;
3599 status = get_full_smb_filename(talloc_tos(), fname, &path);
3600 if (!NT_STATUS_IS_OK(status)) {
3601 errno = map_errno_from_nt_status(status);
3602 return false;
3605 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3607 TALLOC_FREE(path);
3609 return offline;
3612 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3613 struct files_struct *fsp,
3614 TALLOC_CTX *mem_ctx,
3615 DATA_BLOB *cookie)
3617 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3620 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3621 struct files_struct *fsp,
3622 const DATA_BLOB old_cookie,
3623 TALLOC_CTX *mem_ctx,
3624 DATA_BLOB *new_cookie)
3626 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3627 new_cookie);
3630 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3631 struct smb_request *smb1req,
3632 struct smbXsrv_open *op,
3633 const DATA_BLOB old_cookie,
3634 TALLOC_CTX *mem_ctx,
3635 struct files_struct **fsp,
3636 DATA_BLOB *new_cookie)
3638 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3639 old_cookie, mem_ctx,
3640 fsp, new_cookie);
3643 static struct vfs_fn_pointers vfs_default_fns = {
3644 /* Disk operations */
3646 .connect_fn = vfswrap_connect,
3647 .disconnect_fn = vfswrap_disconnect,
3648 .disk_free_fn = vfswrap_disk_free,
3649 .get_quota_fn = vfswrap_get_quota,
3650 .set_quota_fn = vfswrap_set_quota,
3651 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3652 .statvfs_fn = vfswrap_statvfs,
3653 .fs_capabilities_fn = vfswrap_fs_capabilities,
3654 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3655 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3656 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3657 .snap_check_path_fn = vfswrap_snap_check_path,
3658 .snap_create_fn = vfswrap_snap_create,
3659 .snap_delete_fn = vfswrap_snap_delete,
3661 /* Directory operations */
3663 .opendir_fn = vfswrap_opendir,
3664 .fdopendir_fn = vfswrap_fdopendir,
3665 .readdir_fn = vfswrap_readdir,
3666 .readdir_attr_fn = vfswrap_readdir_attr,
3667 .seekdir_fn = vfswrap_seekdir,
3668 .telldir_fn = vfswrap_telldir,
3669 .rewind_dir_fn = vfswrap_rewinddir,
3670 .mkdirat_fn = vfswrap_mkdirat,
3671 .closedir_fn = vfswrap_closedir,
3673 /* File operations */
3675 .open_fn = vfswrap_open,
3676 .create_file_fn = vfswrap_create_file,
3677 .close_fn = vfswrap_close,
3678 .pread_fn = vfswrap_pread,
3679 .pread_send_fn = vfswrap_pread_send,
3680 .pread_recv_fn = vfswrap_pread_recv,
3681 .pwrite_fn = vfswrap_pwrite,
3682 .pwrite_send_fn = vfswrap_pwrite_send,
3683 .pwrite_recv_fn = vfswrap_pwrite_recv,
3684 .lseek_fn = vfswrap_lseek,
3685 .sendfile_fn = vfswrap_sendfile,
3686 .recvfile_fn = vfswrap_recvfile,
3687 .renameat_fn = vfswrap_renameat,
3688 .fsync_send_fn = vfswrap_fsync_send,
3689 .fsync_recv_fn = vfswrap_fsync_recv,
3690 .stat_fn = vfswrap_stat,
3691 .fstat_fn = vfswrap_fstat,
3692 .lstat_fn = vfswrap_lstat,
3693 .get_alloc_size_fn = vfswrap_get_alloc_size,
3694 .unlinkat_fn = vfswrap_unlinkat,
3695 .chmod_fn = vfswrap_chmod,
3696 .fchmod_fn = vfswrap_fchmod,
3697 .fchown_fn = vfswrap_fchown,
3698 .lchown_fn = vfswrap_lchown,
3699 .chdir_fn = vfswrap_chdir,
3700 .getwd_fn = vfswrap_getwd,
3701 .ntimes_fn = vfswrap_ntimes,
3702 .ftruncate_fn = vfswrap_ftruncate,
3703 .fallocate_fn = vfswrap_fallocate,
3704 .lock_fn = vfswrap_lock,
3705 .kernel_flock_fn = vfswrap_kernel_flock,
3706 .fcntl_fn = vfswrap_fcntl,
3707 .linux_setlease_fn = vfswrap_linux_setlease,
3708 .getlock_fn = vfswrap_getlock,
3709 .symlinkat_fn = vfswrap_symlinkat,
3710 .readlinkat_fn = vfswrap_readlinkat,
3711 .linkat_fn = vfswrap_linkat,
3712 .mknodat_fn = vfswrap_mknodat,
3713 .realpath_fn = vfswrap_realpath,
3714 .chflags_fn = vfswrap_chflags,
3715 .file_id_create_fn = vfswrap_file_id_create,
3716 .fs_file_id_fn = vfswrap_fs_file_id,
3717 .streaminfo_fn = vfswrap_streaminfo,
3718 .get_real_filename_fn = vfswrap_get_real_filename,
3719 .connectpath_fn = vfswrap_connectpath,
3720 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
3721 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
3722 .strict_lock_check_fn = vfswrap_strict_lock_check,
3723 .translate_name_fn = vfswrap_translate_name,
3724 .fsctl_fn = vfswrap_fsctl,
3725 .set_dos_attributes_fn = vfswrap_set_dos_attributes,
3726 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
3727 .get_dos_attributes_fn = vfswrap_get_dos_attributes,
3728 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
3729 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
3730 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
3731 .offload_read_send_fn = vfswrap_offload_read_send,
3732 .offload_read_recv_fn = vfswrap_offload_read_recv,
3733 .offload_write_send_fn = vfswrap_offload_write_send,
3734 .offload_write_recv_fn = vfswrap_offload_write_recv,
3735 .get_compression_fn = vfswrap_get_compression,
3736 .set_compression_fn = vfswrap_set_compression,
3738 /* NT ACL operations. */
3740 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
3741 .get_nt_acl_fn = vfswrap_get_nt_acl,
3742 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
3743 .audit_file_fn = vfswrap_audit_file,
3745 /* POSIX ACL operations. */
3747 .sys_acl_get_file_fn = vfswrap_sys_acl_get_file,
3748 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
3749 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
3750 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
3751 .sys_acl_set_file_fn = vfswrap_sys_acl_set_file,
3752 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
3753 .sys_acl_delete_def_file_fn = vfswrap_sys_acl_delete_def_file,
3755 /* EA operations. */
3756 .getxattr_fn = vfswrap_getxattr,
3757 .getxattrat_send_fn = vfswrap_getxattrat_send,
3758 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
3759 .fgetxattr_fn = vfswrap_fgetxattr,
3760 .listxattr_fn = vfswrap_listxattr,
3761 .flistxattr_fn = vfswrap_flistxattr,
3762 .removexattr_fn = vfswrap_removexattr,
3763 .fremovexattr_fn = vfswrap_fremovexattr,
3764 .setxattr_fn = vfswrap_setxattr,
3765 .fsetxattr_fn = vfswrap_fsetxattr,
3767 /* aio operations */
3768 .aio_force_fn = vfswrap_aio_force,
3770 /* durable handle operations */
3771 .durable_cookie_fn = vfswrap_durable_cookie,
3772 .durable_disconnect_fn = vfswrap_durable_disconnect,
3773 .durable_reconnect_fn = vfswrap_durable_reconnect,
3776 static_decl_vfs;
3777 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
3780 * Here we need to implement every call!
3782 * As this is the end of the vfs module chain.
3784 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
3785 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
3786 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);