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/>.
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
27 #include "smbprofile.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/lookup_sid.h"
30 #include "source3/include/msdfs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "lib/util/sys_rw.h"
35 #include "lib/pthreadpool/pthreadpool_tevent.h"
36 #include "librpc/gen_ndr/ndr_ioctl.h"
37 #include "offload_token.h"
38 #include "util_reparse.h"
39 #include "lib/util/string_wrappers.h"
42 #define DBGC_CLASS DBGC_VFS
44 /* Check for NULL pointer parameters in vfswrap_* functions */
46 /* We don't want to have NULL function pointers lying around. Someone
47 is sure to try and execute them. These stubs are used to prevent
50 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
54 handle->conn->have_proc_fds = sys_have_proc_fds();
57 * assume the kernel will support openat2(),
58 * it will be reset on the first ENOSYS.
60 * Note that libreplace will always provide openat2(),
61 * but return -1/errno = ENOSYS...
63 * The option is only there to test the fallback code.
65 bval = lp_parm_bool(SNUM(handle->conn),
67 "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
70 handle->conn->open_how_resolve |=
71 VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
74 return 0; /* Return >= 0 for success */
77 static void vfswrap_disconnect(vfs_handle_struct *handle)
83 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
84 const struct smb_filename *smb_fname,
89 if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
97 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
98 const struct smb_filename *smb_fname,
99 enum SMB_QUOTA_TYPE qtype,
103 #ifdef HAVE_SYS_QUOTAS
106 START_PROFILE(syscall_get_quota);
107 result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
108 END_PROFILE(syscall_get_quota);
116 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
118 #ifdef HAVE_SYS_QUOTAS
121 START_PROFILE(syscall_set_quota);
122 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
123 END_PROFILE(syscall_set_quota);
131 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
132 struct files_struct *fsp,
133 struct shadow_copy_data *shadow_copy_data,
137 return -1; /* Not implemented. */
140 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
141 const struct smb_filename *smb_fname,
142 struct vfs_statvfs_struct *statbuf)
144 return sys_statvfs(smb_fname->base_name, statbuf);
147 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
148 enum timestamp_set_resolution *p_ts_res)
150 const struct loadparm_substitution *lp_sub =
151 loadparm_s3_global_substitution();
152 connection_struct *conn = handle->conn;
153 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
154 struct smb_filename *smb_fname_cpath = NULL;
155 struct vfs_statvfs_struct statbuf;
158 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
164 if (smb_fname_cpath == NULL) {
168 ZERO_STRUCT(statbuf);
169 ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
171 caps = statbuf.FsCapabilities;
174 *p_ts_res = TIMESTAMP_SET_SECONDS;
176 /* Work out what timestamp resolution we can
177 * use when setting a timestamp. */
179 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
181 TALLOC_FREE(smb_fname_cpath);
185 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
186 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
187 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
188 /* If any of the normal UNIX directory timestamps
189 * have a non-zero tv_nsec component assume
190 * we might be able to set sub-second timestamps.
191 * See what filetime set primitives we have.
193 #if defined(HAVE_UTIMENSAT)
194 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
195 #elif defined(HAVE_UTIMES)
196 /* utimes allows msec timestamps to be set. */
197 *p_ts_res = TIMESTAMP_SET_MSEC;
198 #elif defined(HAVE_UTIME)
199 /* utime only allows sec timestamps to be set. */
200 *p_ts_res = TIMESTAMP_SET_SECONDS;
203 DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
205 "available on share %s, directory %s\n",
206 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
207 lp_servicename(talloc_tos(), lp_sub, conn->params->service),
210 TALLOC_FREE(smb_fname_cpath);
214 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
215 struct dfs_GetDFSReferral *r)
217 struct junction_map *junction = NULL;
218 size_t consumedcnt = 0;
219 bool self_referral = false;
220 char *pathnamep = NULL;
221 char *local_dfs_path = NULL;
224 uint16_t max_referral_level = r->in.req.max_referral_level;
226 if (DEBUGLVL(DBGLVL_DEBUG)) {
227 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
230 /* get the junction entry */
231 if (r->in.req.servername == NULL) {
232 return NT_STATUS_NOT_FOUND;
236 * Trim pathname sent by client so it begins with only one backslash.
237 * Two backslashes confuse some dfs clients
240 local_dfs_path = talloc_strdup(r, r->in.req.servername);
241 if (local_dfs_path == NULL) {
242 return NT_STATUS_NO_MEMORY;
244 pathnamep = local_dfs_path;
245 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
246 IS_DIRECTORY_SEP(pathnamep[1])) {
250 junction = talloc_zero(r, struct junction_map);
251 if (junction == NULL) {
252 return NT_STATUS_NO_MEMORY;
255 /* The following call can change cwd. */
256 status = get_referred_path(r,
257 handle->conn->session_info,
259 handle->conn->sconn->remote_address,
260 handle->conn->sconn->local_address,
261 junction, &consumedcnt, &self_referral);
262 if (!NT_STATUS_IS_OK(status)) {
263 struct smb_filename connectpath_fname = {
264 .base_name = handle->conn->connectpath
266 vfs_ChDir(handle->conn, &connectpath_fname);
270 struct smb_filename connectpath_fname = {
271 .base_name = handle->conn->connectpath
273 vfs_ChDir(handle->conn, &connectpath_fname);
276 if (!self_referral) {
277 pathnamep[consumedcnt] = '\0';
279 if (DEBUGLVL(DBGLVL_INFO)) {
280 dbgtext("Path %s to alternate path(s):",
282 for (i=0; i < junction->referral_count; i++) {
284 junction->referral_list[i].alternate_path);
290 if (r->in.req.max_referral_level <= 2) {
291 max_referral_level = 2;
293 if (r->in.req.max_referral_level >= 3) {
294 max_referral_level = 3;
297 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
298 if (r->out.resp == NULL) {
299 return NT_STATUS_NO_MEMORY;
302 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
303 r->out.resp->nb_referrals = junction->referral_count;
305 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
307 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
310 r->out.resp->referral_entries = talloc_zero_array(r,
311 struct dfs_referral_type,
312 r->out.resp->nb_referrals);
313 if (r->out.resp->referral_entries == NULL) {
314 return NT_STATUS_NO_MEMORY;
317 switch (max_referral_level) {
319 for(i=0; i < junction->referral_count; i++) {
320 struct referral *ref = &junction->referral_list[i];
321 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
322 struct dfs_referral_type *t =
323 &r->out.resp->referral_entries[i];
324 struct dfs_referral_v2 *v2 = &t->referral.v2;
327 v2->size = VERSION2_REFERRAL_SIZE;
329 v2->server_type = DFS_SERVER_ROOT;
331 v2->server_type = DFS_SERVER_NON_ROOT;
334 v2->proximity = ref->proximity;
336 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
337 if (v2->DFS_path == NULL) {
338 return NT_STATUS_NO_MEMORY;
340 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
341 if (v2->DFS_alt_path == NULL) {
342 return NT_STATUS_NO_MEMORY;
344 v2->netw_address = talloc_strdup(mem_ctx,
345 ref->alternate_path);
346 if (v2->netw_address == NULL) {
347 return NT_STATUS_NO_MEMORY;
353 for(i=0; i < junction->referral_count; i++) {
354 struct referral *ref = &junction->referral_list[i];
355 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
356 struct dfs_referral_type *t =
357 &r->out.resp->referral_entries[i];
358 struct dfs_referral_v3 *v3 = &t->referral.v3;
359 struct dfs_normal_referral *r1 = &v3->referrals.r1;
362 v3->size = VERSION3_REFERRAL_SIZE;
364 v3->server_type = DFS_SERVER_ROOT;
366 v3->server_type = DFS_SERVER_NON_ROOT;
370 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
371 if (r1->DFS_path == NULL) {
372 return NT_STATUS_NO_MEMORY;
374 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
375 if (r1->DFS_alt_path == NULL) {
376 return NT_STATUS_NO_MEMORY;
378 r1->netw_address = talloc_strdup(mem_ctx,
379 ref->alternate_path);
380 if (r1->netw_address == NULL) {
381 return NT_STATUS_NO_MEMORY;
386 DBG_ERR("Invalid dfs referral version: %d\n",
388 return NT_STATUS_INVALID_LEVEL;
391 if (DEBUGLVL(DBGLVL_DEBUG)) {
392 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
398 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
399 struct files_struct *dirfsp,
400 const struct smb_filename *smb_fname,
401 const struct referral *reflist,
402 size_t referral_count)
404 TALLOC_CTX *frame = talloc_stackframe();
405 NTSTATUS status = NT_STATUS_NO_MEMORY;
407 char *msdfs_link = NULL;
409 /* Form the msdfs_link contents */
410 msdfs_link = msdfs_link_string(frame,
413 if (msdfs_link == NULL) {
417 ret = symlinkat(msdfs_link,
418 fsp_get_pathref_fd(dirfsp),
419 smb_fname->base_name);
421 status = NT_STATUS_OK;
423 status = map_nt_error_from_unix(errno);
433 * Read and return the contents of a DFS redirect given a
434 * pathname. A caller can pass in NULL for ppreflist and
435 * preferral_count but still determine if this was a
436 * DFS redirect point by getting NT_STATUS_OK back
437 * without incurring the overhead of reading and parsing
438 * the referral contents.
441 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
443 struct files_struct *dirfsp,
444 struct smb_filename *smb_fname,
445 struct referral **ppreflist,
446 size_t *preferral_count)
448 NTSTATUS status = NT_STATUS_NO_MEMORY;
450 char *link_target = NULL;
453 #if defined(HAVE_BROKEN_READLINK)
454 char link_target_buf[PATH_MAX];
456 char link_target_buf[7];
460 if (is_named_stream(smb_fname)) {
461 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
465 if (ppreflist == NULL && preferral_count == NULL) {
467 * We're only checking if this is a DFS
468 * redirect. We don't need to return data.
470 bufsize = sizeof(link_target_buf);
471 link_target = link_target_buf;
474 link_target = talloc_array(mem_ctx, char, bufsize);
480 referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
481 smb_fname->base_name,
484 if (referral_len == -1) {
485 if (errno == EINVAL) {
487 * If the path isn't a link, readlinkat
488 * returns EINVAL. Allow the caller to
491 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
492 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
494 status = map_nt_error_from_unix(errno);
495 if (errno == ENOENT) {
496 DBG_NOTICE("Error reading "
497 "msdfs link %s: %s\n",
498 smb_fname->base_name,
501 DBG_ERR("Error reading "
502 "msdfs link %s: %s\n",
503 smb_fname->base_name,
509 link_target[referral_len] = '\0';
511 DBG_INFO("%s -> %s\n",
512 smb_fname->base_name,
515 if (!strnequal(link_target, "msdfs:", 6)) {
516 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
520 ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
521 smb_fname->base_name,
524 lp_fake_directory_create_times(SNUM(handle->conn)));
526 status = map_nt_error_from_unix(errno);
530 if (ppreflist == NULL && preferral_count == NULL) {
531 /* Early return for checking if this is a DFS link. */
535 ok = parse_msdfs_symlink(mem_ctx,
536 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
542 status = NT_STATUS_OK;
544 status = NT_STATUS_NO_MEMORY;
549 if (link_target != link_target_buf) {
550 TALLOC_FREE(link_target);
555 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
557 const char *service_path,
560 return NT_STATUS_NOT_SUPPORTED;
563 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
565 const char *base_volume,
571 return NT_STATUS_NOT_SUPPORTED;
574 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
579 return NT_STATUS_NOT_SUPPORTED;
582 /* Directory operations */
584 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
591 START_PROFILE(syscall_fdopendir);
592 result = sys_fdopendir(fsp_get_io_fd(fsp));
593 END_PROFILE(syscall_fdopendir);
598 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
599 struct files_struct *dirfsp,
601 SMB_STRUCT_STAT *sbuf)
603 struct dirent *result;
604 bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
605 int flags = AT_SYMLINK_NOFOLLOW;
606 SMB_STRUCT_STAT st = {0};
609 START_PROFILE(syscall_readdir);
611 result = readdir(dirp);
612 END_PROFILE(syscall_readdir);
617 if (result == NULL) {
622 * Default Posix readdir() does not give us stat info.
623 * Set to invalid to indicate we didn't return this info.
625 SET_STAT_INVALID(*sbuf);
627 ret = sys_fstatat(dirfd(dirp),
637 * As this is an optimization, ignore it if we stat'ed a
638 * symlink for non-POSIX context. Make the caller do it again
639 * as we don't know if they wanted the link info, or its
642 if (S_ISLNK(st.st_ex_mode) &&
643 !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
652 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
653 struct files_struct *fsp,
655 struct readdir_attr_data **attr_data)
657 return NT_STATUS_NOT_SUPPORTED;
660 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
662 START_PROFILE(syscall_rewinddir);
664 END_PROFILE(syscall_rewinddir);
667 static int vfswrap_mkdirat(vfs_handle_struct *handle,
668 struct files_struct *dirfsp,
669 const struct smb_filename *smb_fname,
674 START_PROFILE(syscall_mkdirat);
676 result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
678 END_PROFILE(syscall_mkdirat);
682 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
686 START_PROFILE(syscall_closedir);
687 result = closedir(dirp);
688 END_PROFILE(syscall_closedir);
692 /* File operations */
694 static int vfswrap_openat(vfs_handle_struct *handle,
695 const struct files_struct *dirfsp,
696 const struct smb_filename *smb_fname,
698 const struct vfs_open_how *how)
700 int flags = how->flags;
701 mode_t mode = how->mode;
702 bool have_opath = false;
703 bool became_root = false;
706 START_PROFILE(syscall_openat);
708 if (how->resolve & ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
714 SMB_ASSERT(!is_named_stream(smb_fname));
718 if (fsp->fsp_flags.is_pathref) {
721 if (flags & O_PATH) {
723 * From "man 2 openat":
725 * When O_PATH is specified in flags, flag bits other than
726 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
728 * From "man 2 openat2":
730 * Whereas openat(2) ignores unknown bits in its flags
731 * argument, openat2() returns an error if unknown or
732 * conflicting flags are specified in how.flags.
734 * So we better clear ignored/invalid flags
735 * and only keep the expected ones.
737 flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
741 if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
742 struct open_how linux_how = {
745 .resolve = RESOLVE_NO_SYMLINKS,
748 result = openat2(fsp_get_pathref_fd(dirfsp),
749 smb_fname->base_name,
753 if (errno == ENOSYS) {
755 * The kernel doesn't support
756 * openat2(), so indicate to
758 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
759 * would just be a waste of time.
761 fsp->conn->open_how_resolve &=
762 ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
770 if (fsp->fsp_flags.is_pathref && !have_opath) {
775 result = openat(fsp_get_pathref_fd(dirfsp),
776 smb_fname->base_name,
785 fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
788 END_PROFILE(syscall_openat);
791 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
792 struct smb_request *req,
793 struct files_struct *dirfsp,
794 struct smb_filename *smb_fname,
795 uint32_t access_mask,
796 uint32_t share_access,
797 uint32_t create_disposition,
798 uint32_t create_options,
799 uint32_t file_attributes,
800 uint32_t oplock_request,
801 const struct smb2_lease *lease,
802 uint64_t allocation_size,
803 uint32_t private_flags,
804 struct security_descriptor *sd,
805 struct ea_list *ea_list,
806 files_struct **result,
808 const struct smb2_create_blobs *in_context_blobs,
809 struct smb2_create_blobs *out_context_blobs)
811 return create_file_default(handle->conn, req, dirfsp, smb_fname,
812 access_mask, share_access,
813 create_disposition, create_options,
814 file_attributes, oplock_request, lease,
815 allocation_size, private_flags,
817 pinfo, in_context_blobs, out_context_blobs);
820 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
824 START_PROFILE(syscall_close);
825 result = fd_close_posix(fsp);
826 END_PROFILE(syscall_close);
830 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
831 size_t n, off_t offset)
835 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
836 START_PROFILE_BYTES(syscall_pread, n);
837 result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
838 END_PROFILE_BYTES(syscall_pread);
840 if (result == -1 && errno == ESPIPE) {
841 /* Maintain the fiction that pipes can be seeked (sought?) on. */
842 result = sys_read(fsp_get_io_fd(fsp), data, n);
843 fh_set_pos(fsp->fh, 0);
846 #else /* HAVE_PREAD */
849 #endif /* HAVE_PREAD */
854 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
855 size_t n, off_t offset)
859 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
860 START_PROFILE_BYTES(syscall_pwrite, n);
861 result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
862 END_PROFILE_BYTES(syscall_pwrite);
864 if (result == -1 && errno == ESPIPE) {
865 /* Maintain the fiction that pipes can be sought on. */
866 result = sys_write(fsp_get_io_fd(fsp), data, n);
869 #else /* HAVE_PWRITE */
872 #endif /* HAVE_PWRITE */
877 struct vfswrap_pread_state {
884 struct vfs_aio_state vfs_aio_state;
885 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
888 static void vfs_pread_do(void *private_data);
889 static void vfs_pread_done(struct tevent_req *subreq);
890 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
892 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
894 struct tevent_context *ev,
895 struct files_struct *fsp,
897 size_t n, off_t offset)
899 struct tevent_req *req, *subreq;
900 struct vfswrap_pread_state *state;
902 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
908 state->fd = fsp_get_io_fd(fsp);
911 state->offset = offset;
913 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
914 state->profile_bytes, n);
915 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
917 subreq = pthreadpool_tevent_job_send(
918 state, ev, handle->conn->sconn->pool,
919 vfs_pread_do, state);
920 if (tevent_req_nomem(subreq, req)) {
921 return tevent_req_post(req, ev);
923 tevent_req_set_callback(subreq, vfs_pread_done, req);
925 talloc_set_destructor(state, vfs_pread_state_destructor);
930 static void vfs_pread_do(void *private_data)
932 struct vfswrap_pread_state *state = talloc_get_type_abort(
933 private_data, struct vfswrap_pread_state);
934 struct timespec start_time;
935 struct timespec end_time;
937 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
939 PROFILE_TIMESTAMP(&start_time);
941 state->ret = sys_pread_full(state->fd,
946 if (state->ret == -1) {
947 state->vfs_aio_state.error = errno;
950 PROFILE_TIMESTAMP(&end_time);
952 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
954 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
957 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
962 static void vfs_pread_done(struct tevent_req *subreq)
964 struct tevent_req *req = tevent_req_callback_data(
965 subreq, struct tevent_req);
966 struct vfswrap_pread_state *state = tevent_req_data(
967 req, struct vfswrap_pread_state);
970 ret = pthreadpool_tevent_job_recv(subreq);
972 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
973 talloc_set_destructor(state, NULL);
976 tevent_req_error(req, ret);
980 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
981 * means the lower level pthreadpool failed to create a new
982 * thread. Fallback to sync processing in that case to allow
983 * some progress for the client.
988 tevent_req_done(req);
991 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
992 struct vfs_aio_state *vfs_aio_state)
994 struct vfswrap_pread_state *state = tevent_req_data(
995 req, struct vfswrap_pread_state);
997 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1001 *vfs_aio_state = state->vfs_aio_state;
1005 struct vfswrap_pwrite_state {
1012 struct vfs_aio_state vfs_aio_state;
1013 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1016 static void vfs_pwrite_do(void *private_data);
1017 static void vfs_pwrite_done(struct tevent_req *subreq);
1018 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
1020 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
1021 TALLOC_CTX *mem_ctx,
1022 struct tevent_context *ev,
1023 struct files_struct *fsp,
1025 size_t n, off_t offset)
1027 struct tevent_req *req, *subreq;
1028 struct vfswrap_pwrite_state *state;
1030 req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1036 state->fd = fsp_get_io_fd(fsp);
1039 state->offset = offset;
1041 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1042 state->profile_bytes, n);
1043 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1045 subreq = pthreadpool_tevent_job_send(
1046 state, ev, handle->conn->sconn->pool,
1047 vfs_pwrite_do, state);
1048 if (tevent_req_nomem(subreq, req)) {
1049 return tevent_req_post(req, ev);
1051 tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1053 talloc_set_destructor(state, vfs_pwrite_state_destructor);
1058 static void vfs_pwrite_do(void *private_data)
1060 struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1061 private_data, struct vfswrap_pwrite_state);
1062 struct timespec start_time;
1063 struct timespec end_time;
1065 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1067 PROFILE_TIMESTAMP(&start_time);
1069 state->ret = sys_pwrite_full(state->fd,
1074 if (state->ret == -1) {
1075 state->vfs_aio_state.error = errno;
1078 PROFILE_TIMESTAMP(&end_time);
1080 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1082 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1085 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1090 static void vfs_pwrite_done(struct tevent_req *subreq)
1092 struct tevent_req *req = tevent_req_callback_data(
1093 subreq, struct tevent_req);
1094 struct vfswrap_pwrite_state *state = tevent_req_data(
1095 req, struct vfswrap_pwrite_state);
1098 ret = pthreadpool_tevent_job_recv(subreq);
1099 TALLOC_FREE(subreq);
1100 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1101 talloc_set_destructor(state, NULL);
1103 if (ret != EAGAIN) {
1104 tevent_req_error(req, ret);
1108 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1109 * means the lower level pthreadpool failed to create a new
1110 * thread. Fallback to sync processing in that case to allow
1111 * some progress for the client.
1113 vfs_pwrite_do(state);
1116 tevent_req_done(req);
1119 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1120 struct vfs_aio_state *vfs_aio_state)
1122 struct vfswrap_pwrite_state *state = tevent_req_data(
1123 req, struct vfswrap_pwrite_state);
1125 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1129 *vfs_aio_state = state->vfs_aio_state;
1133 struct vfswrap_fsync_state {
1137 struct vfs_aio_state vfs_aio_state;
1138 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1141 static void vfs_fsync_do(void *private_data);
1142 static void vfs_fsync_done(struct tevent_req *subreq);
1143 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1145 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1146 TALLOC_CTX *mem_ctx,
1147 struct tevent_context *ev,
1148 struct files_struct *fsp)
1150 struct tevent_req *req, *subreq;
1151 struct vfswrap_fsync_state *state;
1153 req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1159 state->fd = fsp_get_io_fd(fsp);
1161 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1162 state->profile_bytes, 0);
1163 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1165 subreq = pthreadpool_tevent_job_send(
1166 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1167 if (tevent_req_nomem(subreq, req)) {
1168 return tevent_req_post(req, ev);
1170 tevent_req_set_callback(subreq, vfs_fsync_done, req);
1172 talloc_set_destructor(state, vfs_fsync_state_destructor);
1177 static void vfs_fsync_do(void *private_data)
1179 struct vfswrap_fsync_state *state = talloc_get_type_abort(
1180 private_data, struct vfswrap_fsync_state);
1181 struct timespec start_time;
1182 struct timespec end_time;
1184 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1186 PROFILE_TIMESTAMP(&start_time);
1189 state->ret = fsync(state->fd);
1190 } while ((state->ret == -1) && (errno == EINTR));
1192 if (state->ret == -1) {
1193 state->vfs_aio_state.error = errno;
1196 PROFILE_TIMESTAMP(&end_time);
1198 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1200 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1203 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1208 static void vfs_fsync_done(struct tevent_req *subreq)
1210 struct tevent_req *req = tevent_req_callback_data(
1211 subreq, struct tevent_req);
1212 struct vfswrap_fsync_state *state = tevent_req_data(
1213 req, struct vfswrap_fsync_state);
1216 ret = pthreadpool_tevent_job_recv(subreq);
1217 TALLOC_FREE(subreq);
1218 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1219 talloc_set_destructor(state, NULL);
1221 if (ret != EAGAIN) {
1222 tevent_req_error(req, ret);
1226 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1227 * means the lower level pthreadpool failed to create a new
1228 * thread. Fallback to sync processing in that case to allow
1229 * some progress for the client.
1231 vfs_fsync_do(state);
1234 tevent_req_done(req);
1237 static int vfswrap_fsync_recv(struct tevent_req *req,
1238 struct vfs_aio_state *vfs_aio_state)
1240 struct vfswrap_fsync_state *state = tevent_req_data(
1241 req, struct vfswrap_fsync_state);
1243 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1247 *vfs_aio_state = state->vfs_aio_state;
1251 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1255 START_PROFILE(syscall_lseek);
1257 result = lseek(fsp_get_io_fd(fsp), offset, whence);
1259 * We want to maintain the fiction that we can seek
1260 * on a fifo for file system purposes. This allows
1261 * people to set up UNIX fifo's that feed data to Windows
1262 * applications. JRA.
1265 if((result == -1) && (errno == ESPIPE)) {
1270 END_PROFILE(syscall_lseek);
1274 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1275 off_t offset, size_t n)
1279 START_PROFILE_BYTES(syscall_sendfile, n);
1280 result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1281 END_PROFILE_BYTES(syscall_sendfile);
1285 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1287 files_struct *tofsp,
1293 START_PROFILE_BYTES(syscall_recvfile, n);
1294 result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1295 END_PROFILE_BYTES(syscall_recvfile);
1299 static int vfswrap_renameat(vfs_handle_struct *handle,
1300 files_struct *srcfsp,
1301 const struct smb_filename *smb_fname_src,
1302 files_struct *dstfsp,
1303 const struct smb_filename *smb_fname_dst)
1307 START_PROFILE(syscall_renameat);
1309 SMB_ASSERT(!is_named_stream(smb_fname_src));
1310 SMB_ASSERT(!is_named_stream(smb_fname_dst));
1312 result = renameat(fsp_get_pathref_fd(srcfsp),
1313 smb_fname_src->base_name,
1314 fsp_get_pathref_fd(dstfsp),
1315 smb_fname_dst->base_name);
1317 END_PROFILE(syscall_renameat);
1321 static int vfswrap_stat(vfs_handle_struct *handle,
1322 struct smb_filename *smb_fname)
1326 START_PROFILE(syscall_stat);
1328 SMB_ASSERT(!is_named_stream(smb_fname));
1330 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1331 lp_fake_directory_create_times(SNUM(handle->conn)));
1333 END_PROFILE(syscall_stat);
1337 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1341 START_PROFILE(syscall_fstat);
1342 result = sys_fstat(fsp_get_pathref_fd(fsp),
1343 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1344 END_PROFILE(syscall_fstat);
1348 static int vfswrap_lstat(vfs_handle_struct *handle,
1349 struct smb_filename *smb_fname)
1353 START_PROFILE(syscall_lstat);
1355 SMB_ASSERT(!is_named_stream(smb_fname));
1357 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1358 lp_fake_directory_create_times(SNUM(handle->conn)));
1360 END_PROFILE(syscall_lstat);
1364 static int vfswrap_fstatat(
1365 struct vfs_handle_struct *handle,
1366 const struct files_struct *dirfsp,
1367 const struct smb_filename *smb_fname,
1368 SMB_STRUCT_STAT *sbuf,
1373 START_PROFILE(syscall_fstatat);
1375 SMB_ASSERT(!is_named_stream(smb_fname));
1377 result = sys_fstatat(
1378 fsp_get_pathref_fd(dirfsp),
1379 smb_fname->base_name,
1382 lp_fake_directory_create_times(SNUM(handle->conn)));
1384 END_PROFILE(syscall_fstatat);
1388 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1390 enum vfs_translate_direction direction,
1391 TALLOC_CTX *mem_ctx,
1394 return NT_STATUS_NONE_MAPPED;
1398 * Return allocated parent directory and basename of path
1400 * Note: if requesting atname, it is returned as talloc child of the
1401 * parent. Freeing the parent is thus sufficient to free both.
1403 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1404 TALLOC_CTX *mem_ctx,
1405 const struct smb_filename *smb_fname_in,
1406 struct smb_filename **parent_dir_out,
1407 struct smb_filename **atname_out)
1409 struct smb_filename *parent = NULL;
1410 struct smb_filename *name = NULL;
1413 parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1414 if (parent == NULL) {
1415 return NT_STATUS_NO_MEMORY;
1417 SET_STAT_INVALID(parent->st);
1419 p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1421 TALLOC_FREE(parent->base_name);
1422 parent->base_name = talloc_strdup(parent, ".");
1423 if (parent->base_name == NULL) {
1424 TALLOC_FREE(parent);
1425 return NT_STATUS_NO_MEMORY;
1427 p = smb_fname_in->base_name;
1433 if (atname_out == NULL) {
1434 *parent_dir_out = parent;
1435 return NT_STATUS_OK;
1438 name = synthetic_smb_fname(
1441 smb_fname_in->stream_name,
1444 smb_fname_in->flags);
1446 return NT_STATUS_NO_MEMORY;
1449 *parent_dir_out = parent;
1451 return NT_STATUS_OK;
1455 * Implement the default fsctl operation.
1457 static bool vfswrap_logged_ioctl_message = false;
1459 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1460 struct files_struct *fsp,
1463 uint16_t req_flags, /* Needed for UNICODE ... */
1464 const uint8_t *_in_data,
1466 uint8_t **_out_data,
1467 uint32_t max_out_len,
1470 const char *in_data = (const char *)_in_data;
1471 char **out_data = (char **)_out_data;
1475 * Currently all fsctls operate on the base
1476 * file if given an alternate data stream.
1477 * Revisit this if we implement fsctls later
1478 * that need access to the ADS handle.
1480 fsp = metadata_fsp(fsp);
1483 case FSCTL_SET_SPARSE:
1485 bool set_sparse = true;
1487 if (in_len >= 1 && in_data[0] == 0) {
1491 status = file_set_sparse(handle->conn, fsp, set_sparse);
1493 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1494 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1495 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1496 nt_errstr(status)));
1501 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1503 unsigned char objid[16];
1504 char *return_data = NULL;
1506 /* This should return the object-id on this file.
1507 * I think I'll make this be the inode+dev. JRA.
1510 DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1513 *out_len = MIN(max_out_len, 64);
1515 /* Hmmm, will this cause problems if less data asked for? */
1516 return_data = talloc_array(ctx, char, 64);
1517 if (return_data == NULL) {
1518 return NT_STATUS_NO_MEMORY;
1521 /* For backwards compatibility only store the dev/inode. */
1522 push_file_id_16(return_data, &fsp->file_id);
1523 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1524 push_file_id_16(return_data+32, &fsp->file_id);
1525 memset(return_data+48, 0, 16);
1526 *out_data = return_data;
1527 return NT_STATUS_OK;
1530 case FSCTL_GET_REPARSE_POINT:
1532 status = fsctl_get_reparse_point(
1533 fsp, ctx, out_data, max_out_len, out_len);
1537 case FSCTL_SET_REPARSE_POINT:
1539 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1543 case FSCTL_DELETE_REPARSE_POINT:
1545 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1549 case FSCTL_GET_SHADOW_COPY_DATA:
1552 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1553 * and return their volume names. If max_data_count is 16, then it is just
1554 * asking for the number of volumes and length of the combined names.
1556 * pdata is the data allocated by our caller, but that uses
1557 * total_data_count (which is 0 in our case) rather than max_data_count.
1558 * Allocate the correct amount and return the pointer to let
1559 * it be deallocated when we return.
1561 struct shadow_copy_data *shadow_data = NULL;
1562 bool labels = False;
1563 uint32_t labels_data_count = 0;
1565 char *cur_pdata = NULL;
1567 if (max_out_len < 16) {
1568 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1570 return NT_STATUS_INVALID_PARAMETER;
1573 if (max_out_len > 16) {
1577 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1578 if (shadow_data == NULL) {
1579 DBG_ERR("TALLOC_ZERO() failed!\n");
1580 return NT_STATUS_NO_MEMORY;
1584 * Call the VFS routine to actually do the work.
1586 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1587 int log_lev = DBGLVL_ERR;
1589 /* broken module didn't set errno on error */
1590 status = NT_STATUS_UNSUCCESSFUL;
1592 status = map_nt_error_from_unix(errno);
1593 if (NT_STATUS_EQUAL(status,
1594 NT_STATUS_NOT_SUPPORTED)) {
1595 log_lev = DBGLVL_INFO;
1598 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1599 "connectpath %s, failed - %s.\n",
1600 fsp->conn->connectpath,
1601 nt_errstr(status)));
1602 TALLOC_FREE(shadow_data);
1606 labels_data_count = (shadow_data->num_volumes * 2 *
1607 sizeof(SHADOW_COPY_LABEL)) + 2;
1612 *out_len = 12 + labels_data_count;
1615 if (max_out_len < *out_len) {
1616 DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1617 max_out_len, *out_len);
1618 TALLOC_FREE(shadow_data);
1619 return NT_STATUS_BUFFER_TOO_SMALL;
1622 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1623 if (cur_pdata == NULL) {
1624 TALLOC_FREE(shadow_data);
1625 return NT_STATUS_NO_MEMORY;
1628 *out_data = cur_pdata;
1630 /* num_volumes 4 bytes */
1631 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1634 /* num_labels 4 bytes */
1635 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1638 /* needed_data_count 4 bytes */
1639 SIVAL(cur_pdata, 8, labels_data_count);
1643 DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1644 shadow_data->num_volumes, fsp_str_dbg(fsp));
1645 if (labels && shadow_data->labels) {
1646 for (i=0; i<shadow_data->num_volumes; i++) {
1648 status = srvstr_push(cur_pdata, req_flags,
1649 cur_pdata, shadow_data->labels[i],
1650 2 * sizeof(SHADOW_COPY_LABEL),
1651 STR_UNICODE|STR_TERMINATE, &len);
1652 if (!NT_STATUS_IS_OK(status)) {
1653 TALLOC_FREE(*out_data);
1654 TALLOC_FREE(shadow_data);
1657 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1658 DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1662 TALLOC_FREE(shadow_data);
1664 return NT_STATUS_OK;
1667 case FSCTL_FIND_FILES_BY_SID:
1669 /* pretend this succeeded -
1671 * we have to send back a list with all files owned by this SID
1673 * but I have to check that --metze
1677 struct dom_sid_buf buf;
1681 DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1685 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1686 return NT_STATUS_INVALID_PARAMETER;
1689 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1691 /* unknown 4 bytes: this is not the length of the sid :-( */
1692 /*unknown = IVAL(pdata,0);*/
1694 ret = sid_parse(_in_data + 4, sid_len, &sid);
1696 return NT_STATUS_INVALID_PARAMETER;
1698 DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1699 dom_sid_str_buf(&sid, &buf)));
1701 if (!sid_to_uid(&sid, &uid)) {
1702 DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1703 dom_sid_str_buf(&sid, &buf),
1704 (unsigned long)sid_len);
1708 /* we can take a look at the find source :-)
1710 * find ./ -uid $uid -name '*' is what we need here
1713 * and send 4bytes len and then NULL terminated unicode strings
1716 * but I don't know how to deal with the paged results
1717 * (maybe we can hang the result anywhere in the fsp struct)
1719 * but I don't know how to deal with the paged results
1720 * (maybe we can hang the result anywhere in the fsp struct)
1722 * we don't send all files at once
1723 * and at the next we should *not* start from the beginning,
1724 * so we have to cache the result
1729 /* this works for now... */
1730 return NT_STATUS_OK;
1733 case FSCTL_QUERY_ALLOCATED_RANGES:
1735 /* FIXME: This is just a dummy reply, telling that all of the
1736 * file is allocated. MKS cp needs that.
1737 * Adding the real allocated ranges via FIEMAP on Linux
1738 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1739 * this FSCTL correct for sparse files.
1741 uint64_t offset, length;
1742 char *out_data_tmp = NULL;
1745 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1747 return NT_STATUS_INVALID_PARAMETER;
1750 if (max_out_len < 16) {
1751 DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1753 return NT_STATUS_INVALID_PARAMETER;
1756 offset = BVAL(in_data,0);
1757 length = BVAL(in_data,8);
1759 if (offset + length < offset) {
1760 /* No 64-bit integer wrap. */
1761 return NT_STATUS_INVALID_PARAMETER;
1764 /* Shouldn't this be SMB_VFS_STAT ... ? */
1765 status = vfs_stat_fsp(fsp);
1766 if (!NT_STATUS_IS_OK(status)) {
1771 out_data_tmp = talloc_array(ctx, char, *out_len);
1772 if (out_data_tmp == NULL) {
1773 DBG_DEBUG("unable to allocate memory for response\n");
1774 return NT_STATUS_NO_MEMORY;
1777 if (offset > fsp->fsp_name->st.st_ex_size ||
1778 fsp->fsp_name->st.st_ex_size == 0 ||
1780 memset(out_data_tmp, 0, *out_len);
1782 uint64_t end = offset + length;
1783 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1784 SBVAL(out_data_tmp, 0, 0);
1785 SBVAL(out_data_tmp, 8, end);
1788 *out_data = out_data_tmp;
1790 return NT_STATUS_OK;
1793 case FSCTL_IS_VOLUME_DIRTY:
1795 DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1796 "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1798 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1799 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1801 return NT_STATUS_INVALID_PARAMETER;
1806 * Only print once ... unfortunately there could be lots of
1807 * different FSCTLs that are called.
1809 if (!vfswrap_logged_ioctl_message) {
1810 vfswrap_logged_ioctl_message = true;
1811 DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1812 __func__, function);
1816 return NT_STATUS_NOT_SUPPORTED;
1819 static bool vfswrap_is_offline(struct connection_struct *conn,
1820 const struct smb_filename *fname);
1822 struct vfswrap_get_dos_attributes_state {
1823 struct vfs_aio_state aio_state;
1824 connection_struct *conn;
1825 TALLOC_CTX *mem_ctx;
1826 struct tevent_context *ev;
1827 files_struct *dir_fsp;
1828 struct smb_filename *smb_fname;
1833 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1835 static struct tevent_req *vfswrap_get_dos_attributes_send(
1836 TALLOC_CTX *mem_ctx,
1837 struct tevent_context *ev,
1838 struct vfs_handle_struct *handle,
1839 files_struct *dir_fsp,
1840 struct smb_filename *smb_fname)
1842 struct tevent_req *req = NULL;
1843 struct tevent_req *subreq = NULL;
1844 struct vfswrap_get_dos_attributes_state *state = NULL;
1846 SMB_ASSERT(!is_named_stream(smb_fname));
1848 req = tevent_req_create(mem_ctx, &state,
1849 struct vfswrap_get_dos_attributes_state);
1854 *state = (struct vfswrap_get_dos_attributes_state) {
1855 .conn = dir_fsp->conn,
1859 .smb_fname = smb_fname,
1862 if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1863 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1864 "\"store dos attributes\" is disabled\n",
1865 dir_fsp->conn->connectpath);
1866 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1867 return tevent_req_post(req, ev);
1870 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1874 SAMBA_XATTR_DOS_ATTRIB,
1876 if (tevent_req_nomem(subreq, req)) {
1877 return tevent_req_post(req, ev);
1879 tevent_req_set_callback(subreq,
1880 vfswrap_get_dos_attributes_getxattr_done,
1886 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1888 struct tevent_req *req =
1889 tevent_req_callback_data(subreq,
1891 struct vfswrap_get_dos_attributes_state *state =
1892 tevent_req_data(req,
1893 struct vfswrap_get_dos_attributes_state);
1895 DATA_BLOB blob = {0};
1897 char *tofree = NULL;
1898 char pathbuf[PATH_MAX+1];
1900 struct smb_filename smb_fname;
1904 xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1908 TALLOC_FREE(subreq);
1909 if (xattr_size == -1) {
1910 status = map_nt_error_from_unix(state->aio_state.error);
1912 if (state->as_root) {
1913 tevent_req_nterror(req, status);
1916 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1917 tevent_req_nterror(req, status);
1921 state->as_root = true;
1924 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1928 SAMBA_XATTR_DOS_ATTRIB,
1931 if (tevent_req_nomem(subreq, req)) {
1934 tevent_req_set_callback(subreq,
1935 vfswrap_get_dos_attributes_getxattr_done,
1940 blob.length = xattr_size;
1942 status = parse_dos_attribute_blob(state->smb_fname,
1945 if (!NT_STATUS_IS_OK(status)) {
1946 tevent_req_nterror(req, status);
1950 pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1951 state->smb_fname->base_name,
1956 if (pathlen == -1) {
1957 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1961 smb_fname = (struct smb_filename) {
1963 .st = state->smb_fname->st,
1964 .flags = state->smb_fname->flags,
1965 .twrp = state->smb_fname->twrp,
1968 offline = vfswrap_is_offline(state->conn, &smb_fname);
1970 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1972 TALLOC_FREE(tofree);
1974 tevent_req_done(req);
1978 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1979 struct vfs_aio_state *aio_state,
1982 struct vfswrap_get_dos_attributes_state *state =
1983 tevent_req_data(req,
1984 struct vfswrap_get_dos_attributes_state);
1987 if (tevent_req_is_nterror(req, &status)) {
1988 tevent_req_received(req);
1992 *aio_state = state->aio_state;
1993 *dosmode = state->dosmode;
1994 tevent_req_received(req);
1995 return NT_STATUS_OK;
1998 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1999 struct files_struct *fsp,
2004 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2006 offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
2008 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
2011 return fget_ea_dos_attribute(fsp, dosmode);
2014 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
2015 struct files_struct *fsp,
2018 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2020 return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2023 static struct vfs_offload_ctx *vfswrap_offload_ctx;
2025 struct vfswrap_offload_read_state {
2029 static struct tevent_req *vfswrap_offload_read_send(
2030 TALLOC_CTX *mem_ctx,
2031 struct tevent_context *ev,
2032 struct vfs_handle_struct *handle,
2033 struct files_struct *fsp,
2039 struct tevent_req *req = NULL;
2040 struct vfswrap_offload_read_state *state = NULL;
2043 req = tevent_req_create(mem_ctx, &state,
2044 struct vfswrap_offload_read_state);
2049 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2050 &vfswrap_offload_ctx);
2051 if (tevent_req_nterror(req, status)) {
2052 return tevent_req_post(req, ev);
2055 if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2056 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2057 return tevent_req_post(req, ev);
2060 status = vfs_offload_token_create_blob(state, fsp, fsctl,
2062 if (tevent_req_nterror(req, status)) {
2063 return tevent_req_post(req, ev);
2066 status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2068 if (tevent_req_nterror(req, status)) {
2069 return tevent_req_post(req, ev);
2072 tevent_req_done(req);
2073 return tevent_req_post(req, ev);
2076 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2077 struct vfs_handle_struct *handle,
2078 TALLOC_CTX *mem_ctx,
2083 struct vfswrap_offload_read_state *state = tevent_req_data(
2084 req, struct vfswrap_offload_read_state);
2087 if (tevent_req_is_nterror(req, &status)) {
2088 tevent_req_received(req);
2094 token->length = state->token.length;
2095 token->data = talloc_move(mem_ctx, &state->token.data);
2097 tevent_req_received(req);
2098 return NT_STATUS_OK;
2101 struct vfswrap_offload_write_state {
2103 bool read_lck_locked;
2104 bool write_lck_locked;
2106 struct tevent_context *src_ev;
2107 struct files_struct *src_fsp;
2109 struct tevent_context *dst_ev;
2110 struct files_struct *dst_fsp;
2115 size_t next_io_size;
2118 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2119 enum tevent_req_state req_state)
2121 struct vfswrap_offload_write_state *state = tevent_req_data(
2122 req, struct vfswrap_offload_write_state);
2125 if (state->dst_fsp == NULL) {
2129 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2131 state->dst_fsp = NULL;
2134 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2135 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2137 static struct tevent_req *vfswrap_offload_write_send(
2138 struct vfs_handle_struct *handle,
2139 TALLOC_CTX *mem_ctx,
2140 struct tevent_context *ev,
2143 off_t transfer_offset,
2144 struct files_struct *dest_fsp,
2148 struct tevent_req *req;
2149 struct vfswrap_offload_write_state *state = NULL;
2150 /* off_t is signed! */
2151 off_t max_offset = INT64_MAX - to_copy;
2152 size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2153 files_struct *src_fsp = NULL;
2157 req = tevent_req_create(mem_ctx, &state,
2158 struct vfswrap_offload_write_state);
2163 *state = (struct vfswrap_offload_write_state) {
2165 .src_off = transfer_offset,
2167 .dst_fsp = dest_fsp,
2168 .dst_off = dest_off,
2170 .remaining = to_copy,
2173 tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2176 case FSCTL_SRV_COPYCHUNK:
2177 case FSCTL_SRV_COPYCHUNK_WRITE:
2180 case FSCTL_OFFLOAD_WRITE:
2181 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2182 return tevent_req_post(req, ev);
2184 case FSCTL_DUP_EXTENTS_TO_FILE:
2185 DBG_DEBUG("COW clones not supported by vfs_default\n");
2186 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2187 return tevent_req_post(req, ev);
2190 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2191 return tevent_req_post(req, ev);
2195 * From here on we assume a copy-chunk fsctl
2199 tevent_req_done(req);
2200 return tevent_req_post(req, ev);
2203 if (state->src_off > max_offset) {
2205 * Protect integer checks below.
2207 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2208 return tevent_req_post(req, ev);
2210 if (state->src_off < 0) {
2212 * Protect integer checks below.
2214 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2215 return tevent_req_post(req, ev);
2217 if (state->dst_off > max_offset) {
2219 * Protect integer checks below.
2221 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2222 return tevent_req_post(req, ev);
2224 if (state->dst_off < 0) {
2226 * Protect integer checks below.
2228 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2229 return tevent_req_post(req, ev);
2232 status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2234 if (tevent_req_nterror(req, status)) {
2235 return tevent_req_post(req, ev);
2238 DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2240 status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2241 if (!NT_STATUS_IS_OK(status)) {
2242 tevent_req_nterror(req, status);
2243 return tevent_req_post(req, ev);
2246 ok = change_to_user_and_service_by_fsp(src_fsp);
2248 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2249 return tevent_req_post(req, ev);
2252 state->src_ev = src_fsp->conn->sconn->ev_ctx;
2253 state->src_fsp = src_fsp;
2255 status = vfs_stat_fsp(src_fsp);
2256 if (tevent_req_nterror(req, status)) {
2257 return tevent_req_post(req, ev);
2260 if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2262 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2263 * If the SourceOffset or SourceOffset + Length extends beyond
2264 * the end of file, the server SHOULD<240> treat this as a
2265 * STATUS_END_OF_FILE error.
2267 * <240> Section 3.3.5.15.6: Windows servers will return
2268 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2270 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2271 return tevent_req_post(req, ev);
2274 status = vfswrap_offload_copy_file_range(req);
2275 if (NT_STATUS_IS_OK(status)) {
2276 tevent_req_done(req);
2277 return tevent_req_post(req, ev);
2279 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2280 tevent_req_nterror(req, status);
2281 return tevent_req_post(req, ev);
2284 state->buf = talloc_array(state, uint8_t, num);
2285 if (tevent_req_nomem(state->buf, req)) {
2286 return tevent_req_post(req, ev);
2289 status = vfswrap_offload_write_loop(req);
2290 if (!NT_STATUS_IS_OK(status)) {
2291 tevent_req_nterror(req, status);
2292 return tevent_req_post(req, ev);
2298 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2300 struct vfswrap_offload_write_state *state = tevent_req_data(
2301 req, struct vfswrap_offload_write_state);
2302 struct lock_struct lck;
2307 static bool try_copy_file_range = true;
2309 if (!try_copy_file_range) {
2310 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2313 same_file = file_id_equal(&state->src_fsp->file_id,
2314 &state->dst_fsp->file_id);
2316 sys_io_ranges_overlap(state->remaining,
2321 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2324 if (fsp_is_alternate_stream(state->src_fsp) ||
2325 fsp_is_alternate_stream(state->dst_fsp))
2327 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2330 init_strict_lock_struct(state->src_fsp,
2331 state->src_fsp->op->global->open_persistent_id,
2335 lp_posix_cifsu_locktype(state->src_fsp),
2338 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2342 return NT_STATUS_FILE_LOCK_CONFLICT;
2345 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2347 return NT_STATUS_INTERNAL_ERROR;
2350 init_strict_lock_struct(state->dst_fsp,
2351 state->dst_fsp->op->global->open_persistent_id,
2355 lp_posix_cifsu_locktype(state->dst_fsp),
2358 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2362 return NT_STATUS_FILE_LOCK_CONFLICT;
2365 while (state->remaining > 0) {
2366 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2368 fsp_get_io_fd(state->dst_fsp),
2372 if (nwritten == -1) {
2373 DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2374 "n [%jd] failed: %s\n",
2375 fsp_str_dbg(state->src_fsp),
2376 (intmax_t)state->src_off,
2377 fsp_str_dbg(state->dst_fsp),
2378 (intmax_t)state->dst_off,
2379 (intmax_t)state->remaining,
2384 try_copy_file_range = false;
2385 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2388 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2391 status = map_nt_error_from_unix(errno);
2392 if (NT_STATUS_EQUAL(
2394 NT_STATUS_MORE_PROCESSING_REQUIRED))
2396 /* Avoid triggering the fallback */
2397 status = NT_STATUS_INTERNAL_ERROR;
2404 if (state->remaining < nwritten) {
2405 DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2406 "n [%jd] remaining [%jd]\n",
2407 fsp_str_dbg(state->src_fsp),
2408 fsp_str_dbg(state->dst_fsp),
2410 (intmax_t)state->remaining);
2411 return NT_STATUS_INTERNAL_ERROR;
2414 if (nwritten == 0) {
2417 state->copied += nwritten;
2418 state->remaining -= nwritten;
2422 * Tell the req cleanup function there's no need to call
2423 * change_to_user_and_service_by_fsp() on the dst handle.
2425 state->dst_fsp = NULL;
2426 return NT_STATUS_OK;
2429 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2431 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2433 struct vfswrap_offload_write_state *state = tevent_req_data(
2434 req, struct vfswrap_offload_write_state);
2435 struct tevent_req *subreq = NULL;
2436 struct lock_struct read_lck;
2440 * This is called under the context of state->src_fsp.
2443 state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2445 init_strict_lock_struct(state->src_fsp,
2446 state->src_fsp->op->global->open_persistent_id,
2448 state->next_io_size,
2450 lp_posix_cifsu_locktype(state->src_fsp),
2453 ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2457 return NT_STATUS_FILE_LOCK_CONFLICT;
2460 subreq = SMB_VFS_PREAD_SEND(state,
2464 state->next_io_size,
2466 if (subreq == NULL) {
2467 return NT_STATUS_NO_MEMORY;
2469 tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2471 return NT_STATUS_OK;
2474 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2476 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2478 struct tevent_req *req = tevent_req_callback_data(
2479 subreq, struct tevent_req);
2480 struct vfswrap_offload_write_state *state = tevent_req_data(
2481 req, struct vfswrap_offload_write_state);
2482 struct vfs_aio_state aio_state;
2483 struct lock_struct write_lck;
2487 nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2488 TALLOC_FREE(subreq);
2490 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2491 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2494 if (nread != state->next_io_size) {
2495 DBG_ERR("Short read, only %zd of %zu\n",
2496 nread, state->next_io_size);
2497 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2501 state->src_off += nread;
2503 ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2505 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2509 init_strict_lock_struct(state->dst_fsp,
2510 state->dst_fsp->op->global->open_persistent_id,
2512 state->next_io_size,
2514 lp_posix_cifsu_locktype(state->dst_fsp),
2517 ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2521 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2525 subreq = SMB_VFS_PWRITE_SEND(state,
2529 state->next_io_size,
2531 if (subreq == NULL) {
2532 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2535 tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2538 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2540 struct tevent_req *req = tevent_req_callback_data(
2541 subreq, struct tevent_req);
2542 struct vfswrap_offload_write_state *state = tevent_req_data(
2543 req, struct vfswrap_offload_write_state);
2544 struct vfs_aio_state aio_state;
2549 nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2550 TALLOC_FREE(subreq);
2551 if (nwritten == -1) {
2552 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2553 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2556 if (nwritten != state->next_io_size) {
2557 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2558 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2562 state->dst_off += nwritten;
2564 if (state->remaining < nwritten) {
2565 /* Paranoia check */
2566 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2569 state->copied += nwritten;
2570 state->remaining -= nwritten;
2571 if (state->remaining == 0) {
2572 tevent_req_done(req);
2576 ok = change_to_user_and_service_by_fsp(state->src_fsp);
2578 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2582 status = vfswrap_offload_write_loop(req);
2583 if (!NT_STATUS_IS_OK(status)) {
2584 tevent_req_nterror(req, status);
2591 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2592 struct tevent_req *req,
2595 struct vfswrap_offload_write_state *state = tevent_req_data(
2596 req, struct vfswrap_offload_write_state);
2599 if (tevent_req_is_nterror(req, &status)) {
2600 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2602 tevent_req_received(req);
2606 *copied = state->copied;
2607 DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2608 tevent_req_received(req);
2610 return NT_STATUS_OK;
2613 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2614 TALLOC_CTX *mem_ctx,
2615 struct files_struct *fsp,
2616 uint16_t *_compression_fmt)
2618 return NT_STATUS_INVALID_DEVICE_REQUEST;
2621 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2622 TALLOC_CTX *mem_ctx,
2623 struct files_struct *fsp,
2624 uint16_t compression_fmt)
2626 return NT_STATUS_INVALID_DEVICE_REQUEST;
2629 /********************************************************************
2630 Given a stat buffer return the allocated size on disk, taking into
2631 account sparse files.
2632 ********************************************************************/
2633 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2634 struct files_struct *fsp,
2635 const SMB_STRUCT_STAT *sbuf)
2639 START_PROFILE(syscall_get_alloc_size);
2641 if(S_ISDIR(sbuf->st_ex_mode)) {
2646 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2647 /* The type of st_blocksize is blkcnt_t which *MUST* be
2648 signed (according to POSIX) and can be less than 64-bits.
2649 Ensure when we're converting to 64 bits wide we don't
2651 #if defined(SIZEOF_BLKCNT_T_8)
2652 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2653 #elif defined(SIZEOF_BLKCNT_T_4)
2655 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2656 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2659 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2663 * Some file systems do not allocate a block for very
2664 * small files. But for non-empty file should report a
2668 uint64_t filesize = get_file_size_stat(sbuf);
2670 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2674 result = get_file_size_stat(sbuf);
2677 if (fsp && fsp->initial_allocation_size)
2678 result = MAX(result,fsp->initial_allocation_size);
2680 result = smb_roundup(handle->conn, result);
2683 END_PROFILE(syscall_get_alloc_size);
2687 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2688 struct files_struct *dirfsp,
2689 const struct smb_filename *smb_fname,
2694 START_PROFILE(syscall_unlinkat);
2696 SMB_ASSERT(!is_named_stream(smb_fname));
2698 result = unlinkat(fsp_get_pathref_fd(dirfsp),
2699 smb_fname->base_name,
2702 END_PROFILE(syscall_unlinkat);
2706 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2710 START_PROFILE(syscall_fchmod);
2712 if (!fsp->fsp_flags.is_pathref) {
2713 result = fchmod(fsp_get_io_fd(fsp), mode);
2714 END_PROFILE(syscall_fchmod);
2718 if (fsp->fsp_flags.have_proc_fds) {
2719 int fd = fsp_get_pathref_fd(fsp);
2720 const char *p = NULL;
2723 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2725 result = chmod(p, mode);
2729 END_PROFILE(syscall_fchmod);
2734 * This is no longer a handle based call.
2736 result = chmod(fsp->fsp_name->base_name, mode);
2738 END_PROFILE(syscall_fchmod);
2742 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2747 START_PROFILE(syscall_fchown);
2748 if (!fsp->fsp_flags.is_pathref) {
2749 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2750 END_PROFILE(syscall_fchown);
2754 if (fsp->fsp_flags.have_proc_fds) {
2755 int fd = fsp_get_pathref_fd(fsp);
2756 const char *p = NULL;
2759 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2761 result = chown(p, uid, gid);
2765 END_PROFILE(syscall_fchown);
2770 * This is no longer a handle based call.
2772 result = chown(fsp->fsp_name->base_name, uid, gid);
2773 END_PROFILE(syscall_fchown);
2781 static int vfswrap_lchown(vfs_handle_struct *handle,
2782 const struct smb_filename *smb_fname,
2788 START_PROFILE(syscall_lchown);
2789 result = lchown(smb_fname->base_name, uid, gid);
2790 END_PROFILE(syscall_lchown);
2794 static int vfswrap_chdir(vfs_handle_struct *handle,
2795 const struct smb_filename *smb_fname)
2799 START_PROFILE(syscall_chdir);
2800 result = chdir(smb_fname->base_name);
2801 END_PROFILE(syscall_chdir);
2805 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2809 struct smb_filename *smb_fname = NULL;
2811 START_PROFILE(syscall_getwd);
2812 result = sys_getwd();
2813 END_PROFILE(syscall_getwd);
2815 if (result == NULL) {
2818 smb_fname = synthetic_smb_fname(ctx,
2825 * sys_getwd() *always* returns malloced memory.
2826 * We must free here to avoid leaks:
2827 * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2833 /*********************************************************************
2834 nsec timestamp resolution call. Convert down to whatever the underlying
2835 system will support.
2836 **********************************************************************/
2838 static int vfswrap_fntimes(vfs_handle_struct *handle,
2840 struct smb_file_time *ft)
2843 struct timespec ts[2];
2844 struct timespec *times = NULL;
2846 START_PROFILE(syscall_fntimes);
2848 if (fsp_is_alternate_stream(fsp)) {
2854 if (is_omit_timespec(&ft->atime)) {
2855 ft->atime = fsp->fsp_name->st.st_ex_atime;
2858 if (is_omit_timespec(&ft->mtime)) {
2859 ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2862 if (!is_omit_timespec(&ft->create_time)) {
2863 set_create_timespec_ea(fsp,
2867 if ((timespec_compare(&ft->atime,
2868 &fsp->fsp_name->st.st_ex_atime) == 0) &&
2869 (timespec_compare(&ft->mtime,
2870 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2882 if (!fsp->fsp_flags.is_pathref) {
2883 result = futimens(fsp_get_io_fd(fsp), times);
2887 if (fsp->fsp_flags.have_proc_fds) {
2888 int fd = fsp_get_pathref_fd(fsp);
2889 const char *p = NULL;
2892 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2895 * The dirfd argument of utimensat is ignored when
2896 * pathname is an absolute path
2898 result = utimensat(AT_FDCWD, p, times, 0);
2907 * The fd is a pathref (opened with O_PATH) and there isn't fd to
2908 * path translation mechanism. Fallback to path based call.
2910 result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2913 END_PROFILE(syscall_fntimes);
2919 /*********************************************************************
2920 A version of ftruncate that will write the space on disk if strict
2922 **********************************************************************/
2924 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2926 off_t space_to_write;
2927 uint64_t space_avail;
2928 uint64_t bsize,dfree,dsize;
2931 SMB_STRUCT_STAT *pst;
2934 ok = vfs_valid_pwrite_range(len, 0);
2940 status = vfs_stat_fsp(fsp);
2941 if (!NT_STATUS_IS_OK(status)) {
2944 pst = &fsp->fsp_name->st;
2947 if (S_ISFIFO(pst->st_ex_mode))
2951 if (pst->st_ex_size == len)
2954 /* Shrink - just ftruncate. */
2955 if (pst->st_ex_size > len)
2956 return ftruncate(fsp_get_io_fd(fsp), len);
2958 space_to_write = len - pst->st_ex_size;
2960 /* for allocation try fallocate first. This can fail on some
2961 platforms e.g. when the filesystem doesn't support it and no
2962 emulation is being done by the libc (like on AIX with JFS1). In that
2963 case we do our own emulation. fallocate implementations can
2964 return ENOTSUP or EINVAL in cases like that. */
2965 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2966 if (ret == -1 && errno == ENOSPC) {
2972 DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2973 "error %d. Falling back to slow manual allocation\n", errno);
2975 /* available disk space is enough or not? */
2977 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2978 /* space_avail is 1k blocks */
2979 if (space_avail == (uint64_t)-1 ||
2980 ((uint64_t)space_to_write/1024 > space_avail) ) {
2985 /* Write out the real space on disk. */
2986 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2994 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2997 SMB_STRUCT_STAT *pst;
3001 START_PROFILE(syscall_ftruncate);
3003 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
3004 result = strict_allocate_ftruncate(handle, fsp, len);
3005 END_PROFILE(syscall_ftruncate);
3009 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
3010 ftruncate if the system supports it. Then I discovered that
3011 you can have some filesystems that support ftruncate
3012 expansion and some that don't! On Linux fat can't do
3013 ftruncate extend but ext2 can. */
3015 result = ftruncate(fsp_get_io_fd(fsp), len);
3017 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
3018 extend a file with ftruncate. Provide alternate implementation
3021 /* Do an fstat to see if the file is longer than the requested
3022 size in which case the ftruncate above should have
3023 succeeded or shorter, in which case seek to len - 1 and
3024 write 1 byte of zero */
3025 status = vfs_stat_fsp(fsp);
3026 if (!NT_STATUS_IS_OK(status)) {
3030 /* We need to update the files_struct after successful ftruncate */
3035 pst = &fsp->fsp_name->st;
3038 if (S_ISFIFO(pst->st_ex_mode)) {
3044 if (pst->st_ex_size == len) {
3049 if (pst->st_ex_size > len) {
3050 /* the ftruncate should have worked */
3054 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3062 END_PROFILE(syscall_ftruncate);
3066 static int vfswrap_fallocate(vfs_handle_struct *handle,
3074 START_PROFILE(syscall_fallocate);
3076 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3078 * posix_fallocate returns 0 on success, errno on error
3079 * and doesn't set errno. Make it behave like fallocate()
3080 * which returns -1, and sets errno on failure.
3087 /* sys_fallocate handles filtering of unsupported mode flags */
3088 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3090 END_PROFILE(syscall_fallocate);
3094 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3098 START_PROFILE(syscall_fcntl_lock);
3100 if (fsp->fsp_flags.use_ofd_locks) {
3101 op = map_process_lock_to_ofd_lock(op);
3104 result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3105 END_PROFILE(syscall_fcntl_lock);
3109 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3111 uint32_t share_access,
3112 uint32_t access_mask)
3118 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3122 va_list dup_cmd_arg;
3126 START_PROFILE(syscall_fcntl);
3128 va_copy(dup_cmd_arg, cmd_arg);
3134 #if defined(HAVE_OFD_LOCKS)
3139 #if defined(HAVE_F_OWNER_EX)
3143 #if defined(HAVE_RW_HINTS)
3146 case F_GET_FILE_RW_HINT:
3147 case F_SET_FILE_RW_HINT:
3149 argp = va_arg(dup_cmd_arg, void *);
3150 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3153 val = va_arg(dup_cmd_arg, int);
3154 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3157 va_end(dup_cmd_arg);
3159 END_PROFILE(syscall_fcntl);
3163 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3168 START_PROFILE(syscall_fcntl_getlock);
3170 if (fsp->fsp_flags.use_ofd_locks) {
3171 op = map_process_lock_to_ofd_lock(op);
3174 result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3175 END_PROFILE(syscall_fcntl_getlock);
3179 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3184 START_PROFILE(syscall_linux_setlease);
3186 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3188 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3189 result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3193 END_PROFILE(syscall_linux_setlease);
3197 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3198 const struct smb_filename *link_target,
3199 struct files_struct *dirfsp,
3200 const struct smb_filename *new_smb_fname)
3204 START_PROFILE(syscall_symlinkat);
3206 SMB_ASSERT(!is_named_stream(new_smb_fname));
3208 result = symlinkat(link_target->base_name,
3209 fsp_get_pathref_fd(dirfsp),
3210 new_smb_fname->base_name);
3211 END_PROFILE(syscall_symlinkat);
3215 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3216 const struct files_struct *dirfsp,
3217 const struct smb_filename *smb_fname,
3223 START_PROFILE(syscall_readlinkat);
3225 SMB_ASSERT(!is_named_stream(smb_fname));
3227 result = readlinkat(fsp_get_pathref_fd(dirfsp),
3228 smb_fname->base_name,
3232 END_PROFILE(syscall_readlinkat);
3236 static int vfswrap_linkat(vfs_handle_struct *handle,
3237 files_struct *srcfsp,
3238 const struct smb_filename *old_smb_fname,
3239 files_struct *dstfsp,
3240 const struct smb_filename *new_smb_fname,
3245 START_PROFILE(syscall_linkat);
3247 SMB_ASSERT(!is_named_stream(old_smb_fname));
3248 SMB_ASSERT(!is_named_stream(new_smb_fname));
3250 result = linkat(fsp_get_pathref_fd(srcfsp),
3251 old_smb_fname->base_name,
3252 fsp_get_pathref_fd(dstfsp),
3253 new_smb_fname->base_name,
3256 END_PROFILE(syscall_linkat);
3260 static int vfswrap_mknodat(vfs_handle_struct *handle,
3261 files_struct *dirfsp,
3262 const struct smb_filename *smb_fname,
3268 START_PROFILE(syscall_mknodat);
3270 SMB_ASSERT(!is_named_stream(smb_fname));
3272 result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3273 smb_fname->base_name,
3277 END_PROFILE(syscall_mknodat);
3281 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3283 const struct smb_filename *smb_fname)
3286 struct smb_filename *result_fname = NULL;
3288 START_PROFILE(syscall_realpath);
3289 result = sys_realpath(smb_fname->base_name);
3290 END_PROFILE(syscall_realpath);
3292 result_fname = synthetic_smb_fname(ctx,
3300 return result_fname;
3303 static int vfswrap_fchflags(vfs_handle_struct *handle,
3304 struct files_struct *fsp,
3307 #ifdef HAVE_FCHFLAGS
3308 int fd = fsp_get_pathref_fd(fsp);
3310 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3312 if (!fsp->fsp_flags.is_pathref) {
3313 return fchflags(fd, flags);
3316 if (fsp->fsp_flags.have_proc_fds) {
3317 const char *p = NULL;
3320 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3325 return chflags(p, flags);
3329 * This is no longer a handle based call.
3331 return chflags(fsp->fsp_name->base_name, flags);
3338 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3339 const SMB_STRUCT_STAT *sbuf)
3343 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3347 key.devid = sbuf->st_ex_dev;
3348 key.inode = sbuf->st_ex_ino;
3349 /* key.extid is unused by default. */
3354 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3355 const SMB_STRUCT_STAT *psbuf)
3359 if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3360 return (uint64_t)psbuf->st_ex_ino;
3364 file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3367 file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3372 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3373 struct files_struct *fsp,
3374 TALLOC_CTX *mem_ctx,
3375 unsigned int *pnum_streams,
3376 struct stream_struct **pstreams)
3378 struct stream_struct *tmp_streams = NULL;
3379 unsigned int num_streams = *pnum_streams;
3380 struct stream_struct *streams = *pstreams;
3383 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3385 if (fsp->fsp_flags.is_directory) {
3387 * No default streams on directories
3391 status = vfs_stat_fsp(fsp);
3392 if (!NT_STATUS_IS_OK(status)) {
3396 if (num_streams + 1 < 1) {
3398 return NT_STATUS_INVALID_PARAMETER;
3401 tmp_streams = talloc_realloc(mem_ctx,
3403 struct stream_struct,
3405 if (tmp_streams == NULL) {
3406 return NT_STATUS_NO_MEMORY;
3408 tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3409 if (tmp_streams[num_streams].name == NULL) {
3410 return NT_STATUS_NO_MEMORY;
3412 tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3413 tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3416 &fsp->fsp_name->st);
3419 *pnum_streams = num_streams;
3420 *pstreams = tmp_streams;
3422 return NT_STATUS_OK;
3425 static NTSTATUS vfswrap_get_real_filename_at(
3426 struct vfs_handle_struct *handle,
3427 struct files_struct *dirfsp,
3429 TALLOC_CTX *mem_ctx,
3433 * Don't fall back to get_real_filename so callers can differentiate
3434 * between a full directory scan and an actual case-insensitive stat.
3436 return NT_STATUS_NOT_SUPPORTED;
3439 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3440 const struct files_struct *dirfsp,
3441 const struct smb_filename *smb_fname)
3443 return handle->conn->connectpath;
3446 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3447 struct byte_range_lock *br_lck,
3448 struct lock_struct *plock)
3450 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3452 /* Note: blr is not used in the default implementation. */
3453 return brl_lock_windows_default(br_lck, plock);
3456 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3457 struct byte_range_lock *br_lck,
3458 const struct lock_struct *plock)
3460 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3462 return brl_unlock_windows_default(br_lck, plock);
3465 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3467 struct lock_struct *plock)
3469 SMB_ASSERT(plock->lock_type == READ_LOCK ||
3470 plock->lock_type == WRITE_LOCK);
3472 return strict_lock_check_default(fsp, plock);
3475 /* NT ACL operations. */
3477 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3479 uint32_t security_info,
3480 TALLOC_CTX *mem_ctx,
3481 struct security_descriptor **ppdesc)
3485 START_PROFILE(fget_nt_acl);
3487 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3489 result = posix_fget_nt_acl(fsp, security_info,
3491 END_PROFILE(fget_nt_acl);
3495 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3499 START_PROFILE(fset_nt_acl);
3501 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3503 result = set_nt_acl(fsp, security_info_sent, psd);
3504 END_PROFILE(fset_nt_acl);
3508 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3509 struct smb_filename *file,
3510 struct security_acl *sacl,
3511 uint32_t access_requested,
3512 uint32_t access_denied)
3514 return NT_STATUS_OK; /* Nothing to do here ... */
3517 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3519 SMB_ACL_TYPE_T type,
3520 TALLOC_CTX *mem_ctx)
3522 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3524 return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3527 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3529 SMB_ACL_TYPE_T type,
3532 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3534 return sys_acl_set_fd(handle, fsp, type, theacl);
3537 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3540 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3542 return sys_acl_delete_def_fd(handle, fsp);
3545 /****************************************************************
3546 Extended attribute operations.
3547 *****************************************************************/
3549 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3550 struct files_struct *fsp,
3555 int fd = fsp_get_pathref_fd(fsp);
3557 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3559 if (!fsp->fsp_flags.is_pathref) {
3560 return fgetxattr(fd, name, value, size);
3563 if (fsp->fsp_flags.have_proc_fds) {
3564 const char *p = NULL;
3567 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3572 return getxattr(p, name, value, size);
3576 * This is no longer a handle based call.
3578 return getxattr(fsp->fsp_name->base_name, name, value, size);
3581 struct vfswrap_getxattrat_state {
3582 struct tevent_context *ev;
3583 struct vfs_handle_struct *handle;
3584 files_struct *dir_fsp;
3585 const struct smb_filename *smb_fname;
3588 * The following variables are talloced off "state" which is protected
3589 * by a destructor and thus are guaranteed to be safe to be used in the
3590 * job function in the worker thread.
3593 const char *xattr_name;
3594 uint8_t *xattr_value;
3595 struct security_unix_token *token;
3598 struct vfs_aio_state vfs_aio_state;
3599 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3602 static int vfswrap_getxattrat_state_destructor(
3603 struct vfswrap_getxattrat_state *state)
3608 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3609 static void vfswrap_getxattrat_do_async(void *private_data);
3610 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3612 static struct tevent_req *vfswrap_getxattrat_send(
3613 TALLOC_CTX *mem_ctx,
3614 struct tevent_context *ev,
3615 struct vfs_handle_struct *handle,
3616 files_struct *dir_fsp,
3617 const struct smb_filename *smb_fname,
3618 const char *xattr_name,
3621 struct tevent_req *req = NULL;
3622 struct tevent_req *subreq = NULL;
3623 struct vfswrap_getxattrat_state *state = NULL;
3624 size_t max_threads = 0;
3625 bool have_per_thread_cwd = false;
3626 bool have_per_thread_creds = false;
3627 bool do_async = false;
3629 SMB_ASSERT(!is_named_stream(smb_fname));
3631 req = tevent_req_create(mem_ctx, &state,
3632 struct vfswrap_getxattrat_state);
3636 *state = (struct vfswrap_getxattrat_state) {
3640 .smb_fname = smb_fname,
3643 max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3644 if (max_threads >= 1) {
3646 * We need a non sync threadpool!
3648 have_per_thread_cwd = per_thread_cwd_supported();
3650 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3651 have_per_thread_creds = true;
3653 if (have_per_thread_cwd && have_per_thread_creds) {
3657 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3658 state->profile_bytes, 0);
3660 if (fsp_get_pathref_fd(dir_fsp) == -1) {
3661 DBG_ERR("Need a valid directory fd\n");
3662 tevent_req_error(req, EINVAL);
3663 return tevent_req_post(req, ev);
3666 if (alloc_hint > 0) {
3667 state->xattr_value = talloc_zero_array(state,
3670 if (tevent_req_nomem(state->xattr_value, req)) {
3671 return tevent_req_post(req, ev);
3676 vfswrap_getxattrat_do_sync(req);
3677 return tevent_req_post(req, ev);
3681 * Now allocate all parameters from a memory context that won't go away
3682 * no matter what. These parameters will get used in threads and we
3683 * can't reliably cancel threads, so all buffers passed to the threads
3684 * must not be freed before all referencing threads terminate.
3687 state->name = talloc_strdup(state, smb_fname->base_name);
3688 if (tevent_req_nomem(state->name, req)) {
3689 return tevent_req_post(req, ev);
3692 state->xattr_name = talloc_strdup(state, xattr_name);
3693 if (tevent_req_nomem(state->xattr_name, req)) {
3694 return tevent_req_post(req, ev);
3698 * This is a hot codepath so at first glance one might think we should
3699 * somehow optimize away the token allocation and do a
3700 * talloc_reference() or similar black magic instead. But due to the
3701 * talloc_stackframe pool per SMB2 request this should be a simple copy
3702 * without a malloc in most cases.
3704 if (geteuid() == sec_initial_uid()) {
3705 state->token = root_unix_token(state);
3707 state->token = copy_unix_token(
3709 dir_fsp->conn->session_info->unix_token);
3711 if (tevent_req_nomem(state->token, req)) {
3712 return tevent_req_post(req, ev);
3715 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3717 subreq = pthreadpool_tevent_job_send(
3720 dir_fsp->conn->sconn->pool,
3721 vfswrap_getxattrat_do_async,
3723 if (tevent_req_nomem(subreq, req)) {
3724 return tevent_req_post(req, ev);
3726 tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3728 talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3733 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3735 struct vfswrap_getxattrat_state *state = tevent_req_data(
3736 req, struct vfswrap_getxattrat_state);
3738 state->xattr_size = vfswrap_fgetxattr(state->handle,
3739 state->smb_fname->fsp,
3742 talloc_array_length(state->xattr_value));
3743 if (state->xattr_size == -1) {
3744 tevent_req_error(req, errno);
3748 tevent_req_done(req);
3752 static void vfswrap_getxattrat_do_async(void *private_data)
3754 struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3755 private_data, struct vfswrap_getxattrat_state);
3756 struct timespec start_time;
3757 struct timespec end_time;
3760 PROFILE_TIMESTAMP(&start_time);
3761 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3764 * Here we simulate a getxattrat()
3765 * call using fchdir();getxattr()
3768 per_thread_cwd_activate();
3770 /* Become the correct credential on this thread. */
3771 ret = set_thread_credentials(state->token->uid,
3773 (size_t)state->token->ngroups,
3774 state->token->groups);
3776 state->xattr_size = -1;
3777 state->vfs_aio_state.error = errno;
3781 state->xattr_size = vfswrap_fgetxattr(state->handle,
3782 state->smb_fname->fsp,
3785 talloc_array_length(state->xattr_value));
3786 if (state->xattr_size == -1) {
3787 state->vfs_aio_state.error = errno;
3791 PROFILE_TIMESTAMP(&end_time);
3792 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3793 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3796 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3798 struct tevent_req *req = tevent_req_callback_data(
3799 subreq, struct tevent_req);
3800 struct vfswrap_getxattrat_state *state = tevent_req_data(
3801 req, struct vfswrap_getxattrat_state);
3806 * Make sure we run as the user again
3808 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3811 ret = pthreadpool_tevent_job_recv(subreq);
3812 TALLOC_FREE(subreq);
3813 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3814 talloc_set_destructor(state, NULL);
3816 if (ret != EAGAIN) {
3817 tevent_req_error(req, ret);
3821 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3822 * means the lower level pthreadpool failed to create a new
3823 * thread. Fallback to sync processing in that case to allow
3824 * some progress for the client.
3826 vfswrap_getxattrat_do_sync(req);
3830 if (state->xattr_size == -1) {
3831 tevent_req_error(req, state->vfs_aio_state.error);
3835 if (state->xattr_value == NULL) {
3837 * The caller only wanted the size.
3839 tevent_req_done(req);
3844 * shrink the buffer to the returned size.
3845 * (can't fail). It means NULL if size is 0.
3847 state->xattr_value = talloc_realloc(state,
3852 tevent_req_done(req);
3855 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3856 struct vfs_aio_state *aio_state,
3857 TALLOC_CTX *mem_ctx,
3858 uint8_t **xattr_value)
3860 struct vfswrap_getxattrat_state *state = tevent_req_data(
3861 req, struct vfswrap_getxattrat_state);
3864 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3865 tevent_req_received(req);
3869 *aio_state = state->vfs_aio_state;
3870 xattr_size = state->xattr_size;
3871 if (xattr_value != NULL) {
3872 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3875 tevent_req_received(req);
3879 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3881 int fd = fsp_get_pathref_fd(fsp);
3883 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3885 if (!fsp->fsp_flags.is_pathref) {
3886 return flistxattr(fd, list, size);
3889 if (fsp->fsp_flags.have_proc_fds) {
3890 const char *p = NULL;
3893 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3898 return listxattr(p, list, size);
3902 * This is no longer a handle based call.
3904 return listxattr(fsp->fsp_name->base_name, list, size);
3907 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3909 int fd = fsp_get_pathref_fd(fsp);
3911 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3913 if (!fsp->fsp_flags.is_pathref) {
3914 return fremovexattr(fd, name);
3917 if (fsp->fsp_flags.have_proc_fds) {
3918 const char *p = NULL;
3921 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3926 return removexattr(p, name);
3930 * This is no longer a handle based call.
3932 return removexattr(fsp->fsp_name->base_name, name);
3935 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3937 int fd = fsp_get_pathref_fd(fsp);
3939 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3941 if (!fsp->fsp_flags.is_pathref) {
3942 return fsetxattr(fd, name, value, size, flags);
3945 if (fsp->fsp_flags.have_proc_fds) {
3946 const char *p = NULL;
3949 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3954 return setxattr(p, name, value, size, flags);
3958 * This is no longer a handle based call.
3960 return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3963 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3968 static bool vfswrap_is_offline(struct connection_struct *conn,
3969 const struct smb_filename *fname)
3973 bool offline = false;
3975 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3979 if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3980 #if defined(ENOTSUP)
3986 status = get_full_smb_filename(talloc_tos(), fname, &path);
3987 if (!NT_STATUS_IS_OK(status)) {
3988 errno = map_errno_from_nt_status(status);
3992 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3999 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
4000 struct files_struct *fsp,
4001 TALLOC_CTX *mem_ctx,
4004 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
4007 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
4008 struct files_struct *fsp,
4009 const DATA_BLOB old_cookie,
4010 TALLOC_CTX *mem_ctx,
4011 DATA_BLOB *new_cookie)
4013 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
4017 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
4018 struct smb_request *smb1req,
4019 struct smbXsrv_open *op,
4020 const DATA_BLOB old_cookie,
4021 TALLOC_CTX *mem_ctx,
4022 struct files_struct **fsp,
4023 DATA_BLOB *new_cookie)
4025 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
4026 old_cookie, mem_ctx,
4030 static struct vfs_fn_pointers vfs_default_fns = {
4031 /* Disk operations */
4033 .connect_fn = vfswrap_connect,
4034 .disconnect_fn = vfswrap_disconnect,
4035 .disk_free_fn = vfswrap_disk_free,
4036 .get_quota_fn = vfswrap_get_quota,
4037 .set_quota_fn = vfswrap_set_quota,
4038 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
4039 .statvfs_fn = vfswrap_statvfs,
4040 .fs_capabilities_fn = vfswrap_fs_capabilities,
4041 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
4042 .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
4043 .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
4044 .snap_check_path_fn = vfswrap_snap_check_path,
4045 .snap_create_fn = vfswrap_snap_create,
4046 .snap_delete_fn = vfswrap_snap_delete,
4048 /* Directory operations */
4050 .fdopendir_fn = vfswrap_fdopendir,
4051 .readdir_fn = vfswrap_readdir,
4052 .freaddir_attr_fn = vfswrap_freaddir_attr,
4053 .rewind_dir_fn = vfswrap_rewinddir,
4054 .mkdirat_fn = vfswrap_mkdirat,
4055 .closedir_fn = vfswrap_closedir,
4057 /* File operations */
4059 .openat_fn = vfswrap_openat,
4060 .create_file_fn = vfswrap_create_file,
4061 .close_fn = vfswrap_close,
4062 .pread_fn = vfswrap_pread,
4063 .pread_send_fn = vfswrap_pread_send,
4064 .pread_recv_fn = vfswrap_pread_recv,
4065 .pwrite_fn = vfswrap_pwrite,
4066 .pwrite_send_fn = vfswrap_pwrite_send,
4067 .pwrite_recv_fn = vfswrap_pwrite_recv,
4068 .lseek_fn = vfswrap_lseek,
4069 .sendfile_fn = vfswrap_sendfile,
4070 .recvfile_fn = vfswrap_recvfile,
4071 .renameat_fn = vfswrap_renameat,
4072 .fsync_send_fn = vfswrap_fsync_send,
4073 .fsync_recv_fn = vfswrap_fsync_recv,
4074 .stat_fn = vfswrap_stat,
4075 .fstat_fn = vfswrap_fstat,
4076 .lstat_fn = vfswrap_lstat,
4077 .fstatat_fn = vfswrap_fstatat,
4078 .get_alloc_size_fn = vfswrap_get_alloc_size,
4079 .unlinkat_fn = vfswrap_unlinkat,
4080 .fchmod_fn = vfswrap_fchmod,
4081 .fchown_fn = vfswrap_fchown,
4082 .lchown_fn = vfswrap_lchown,
4083 .chdir_fn = vfswrap_chdir,
4084 .getwd_fn = vfswrap_getwd,
4085 .fntimes_fn = vfswrap_fntimes,
4086 .ftruncate_fn = vfswrap_ftruncate,
4087 .fallocate_fn = vfswrap_fallocate,
4088 .lock_fn = vfswrap_lock,
4089 .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4090 .fcntl_fn = vfswrap_fcntl,
4091 .linux_setlease_fn = vfswrap_linux_setlease,
4092 .getlock_fn = vfswrap_getlock,
4093 .symlinkat_fn = vfswrap_symlinkat,
4094 .readlinkat_fn = vfswrap_readlinkat,
4095 .linkat_fn = vfswrap_linkat,
4096 .mknodat_fn = vfswrap_mknodat,
4097 .realpath_fn = vfswrap_realpath,
4098 .fchflags_fn = vfswrap_fchflags,
4099 .file_id_create_fn = vfswrap_file_id_create,
4100 .fs_file_id_fn = vfswrap_fs_file_id,
4101 .fstreaminfo_fn = vfswrap_fstreaminfo,
4102 .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4103 .connectpath_fn = vfswrap_connectpath,
4104 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4105 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4106 .strict_lock_check_fn = vfswrap_strict_lock_check,
4107 .translate_name_fn = vfswrap_translate_name,
4108 .parent_pathname_fn = vfswrap_parent_pathname,
4109 .fsctl_fn = vfswrap_fsctl,
4110 .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4111 .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4112 .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4113 .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4114 .offload_read_send_fn = vfswrap_offload_read_send,
4115 .offload_read_recv_fn = vfswrap_offload_read_recv,
4116 .offload_write_send_fn = vfswrap_offload_write_send,
4117 .offload_write_recv_fn = vfswrap_offload_write_recv,
4118 .fget_compression_fn = vfswrap_fget_compression,
4119 .set_compression_fn = vfswrap_set_compression,
4121 /* NT ACL operations. */
4123 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4124 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4125 .audit_file_fn = vfswrap_audit_file,
4127 /* POSIX ACL operations. */
4129 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4130 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4131 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4132 .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4134 /* EA operations. */
4135 .getxattrat_send_fn = vfswrap_getxattrat_send,
4136 .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4137 .fgetxattr_fn = vfswrap_fgetxattr,
4138 .flistxattr_fn = vfswrap_flistxattr,
4139 .fremovexattr_fn = vfswrap_fremovexattr,
4140 .fsetxattr_fn = vfswrap_fsetxattr,
4142 /* aio operations */
4143 .aio_force_fn = vfswrap_aio_force,
4145 /* durable handle operations */
4146 .durable_cookie_fn = vfswrap_durable_cookie,
4147 .durable_disconnect_fn = vfswrap_durable_disconnect,
4148 .durable_reconnect_fn = vfswrap_durable_reconnect,
4152 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4155 * Here we need to implement every call!
4157 * As this is the end of the vfs module chain.
4159 smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4160 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4161 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);