ctdb-scripts: Memory monitoring uses thresholds expressed as percentages
[Samba.git] / source3 / modules / vfs_default.c
blob9ea630a25ae08883fc7d923272334422ae758295
1 /*
2 Unix SMB/CIFS implementation.
3 Wrap disk only vfs functions to sidestep dodgy compilers.
4 Copyright (C) Tim Potter 1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "ntioctl.h"
27 #include "smbprofile.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/lookup_sid.h"
30 #include "source3/include/msdfs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/asys/asys.h"
34 #include "lib/util/tevent_ntstatus.h"
35 #include "lib/sys_rw.h"
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_VFS
40 /* Check for NULL pointer parameters in vfswrap_* functions */
42 /* We don't want to have NULL function pointers lying around. Someone
43 is sure to try and execute them. These stubs are used to prevent
44 this possibility. */
46 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
48 return 0; /* Return >= 0 for success */
51 static void vfswrap_disconnect(vfs_handle_struct *handle)
55 /* Disk operations */
57 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle, const char *path,
58 uint64_t *bsize, uint64_t *dfree,
59 uint64_t *dsize)
61 uint64_t result;
63 result = sys_disk_free(handle->conn, path, bsize, dfree, dsize);
64 return result;
67 static int vfswrap_get_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
69 #ifdef HAVE_SYS_QUOTAS
70 int result;
72 START_PROFILE(syscall_get_quota);
73 result = sys_get_quota(handle->conn->connectpath, qtype, id, qt);
74 END_PROFILE(syscall_get_quota);
75 return result;
76 #else
77 errno = ENOSYS;
78 return -1;
79 #endif
82 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
84 #ifdef HAVE_SYS_QUOTAS
85 int result;
87 START_PROFILE(syscall_set_quota);
88 result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
89 END_PROFILE(syscall_set_quota);
90 return result;
91 #else
92 errno = ENOSYS;
93 return -1;
94 #endif
97 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
98 struct files_struct *fsp,
99 struct shadow_copy_data *shadow_copy_data,
100 bool labels)
102 errno = ENOSYS;
103 return -1; /* Not implemented. */
106 static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
108 return sys_statvfs(path, statbuf);
111 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
112 enum timestamp_set_resolution *p_ts_res)
114 connection_struct *conn = handle->conn;
115 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
116 struct smb_filename *smb_fname_cpath = NULL;
117 struct vfs_statvfs_struct statbuf;
118 int ret;
120 ZERO_STRUCT(statbuf);
121 ret = sys_statvfs(conn->connectpath, &statbuf);
122 if (ret == 0) {
123 caps = statbuf.FsCapabilities;
126 *p_ts_res = TIMESTAMP_SET_SECONDS;
128 /* Work out what timestamp resolution we can
129 * use when setting a timestamp. */
131 smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
132 NULL, NULL);
133 if (smb_fname_cpath == NULL) {
134 return caps;
137 ret = SMB_VFS_STAT(conn, smb_fname_cpath);
138 if (ret == -1) {
139 TALLOC_FREE(smb_fname_cpath);
140 return caps;
143 if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
144 smb_fname_cpath->st.st_ex_atime.tv_nsec ||
145 smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
146 /* If any of the normal UNIX directory timestamps
147 * have a non-zero tv_nsec component assume
148 * we might be able to set sub-second timestamps.
149 * See what filetime set primitives we have.
151 #if defined(HAVE_UTIMENSAT)
152 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
153 #elif defined(HAVE_UTIMES)
154 /* utimes allows msec timestamps to be set. */
155 *p_ts_res = TIMESTAMP_SET_MSEC;
156 #elif defined(HAVE_UTIME)
157 /* utime only allows sec timestamps to be set. */
158 *p_ts_res = TIMESTAMP_SET_SECONDS;
159 #endif
161 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
162 "resolution of %s "
163 "available on share %s, directory %s\n",
164 *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
165 lp_servicename(talloc_tos(), conn->params->service),
166 conn->connectpath ));
168 TALLOC_FREE(smb_fname_cpath);
169 return caps;
172 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
173 struct dfs_GetDFSReferral *r)
175 struct junction_map *junction = NULL;
176 int consumedcnt = 0;
177 bool self_referral = false;
178 char *pathnamep = NULL;
179 char *local_dfs_path = NULL;
180 NTSTATUS status;
181 int i;
182 uint16_t max_referral_level = r->in.req.max_referral_level;
184 if (DEBUGLVL(10)) {
185 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
188 /* get the junction entry */
189 if (r->in.req.servername == NULL) {
190 return NT_STATUS_NOT_FOUND;
194 * Trim pathname sent by client so it begins with only one backslash.
195 * Two backslashes confuse some dfs clients
198 local_dfs_path = talloc_strdup(r, r->in.req.servername);
199 if (local_dfs_path == NULL) {
200 return NT_STATUS_NO_MEMORY;
202 pathnamep = local_dfs_path;
203 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
204 IS_DIRECTORY_SEP(pathnamep[1])) {
205 pathnamep++;
208 junction = talloc_zero(r, struct junction_map);
209 if (junction == NULL) {
210 return NT_STATUS_NO_MEMORY;
213 /* The following call can change cwd. */
214 status = get_referred_path(r, pathnamep,
215 !handle->conn->sconn->using_smb2,
216 junction, &consumedcnt, &self_referral);
217 if (!NT_STATUS_IS_OK(status)) {
218 vfs_ChDir(handle->conn, handle->conn->connectpath);
219 return status;
221 vfs_ChDir(handle->conn, handle->conn->connectpath);
223 if (!self_referral) {
224 pathnamep[consumedcnt] = '\0';
226 if (DEBUGLVL(3)) {
227 dbgtext("Path %s to alternate path(s):",
228 pathnamep);
229 for (i=0; i < junction->referral_count; i++) {
230 dbgtext(" %s",
231 junction->referral_list[i].alternate_path);
233 dbgtext(".\n");
237 if (r->in.req.max_referral_level <= 2) {
238 max_referral_level = 2;
240 if (r->in.req.max_referral_level >= 3) {
241 max_referral_level = 3;
244 r->out.resp = talloc_zero(r, struct dfs_referral_resp);
245 if (r->out.resp == NULL) {
246 return NT_STATUS_NO_MEMORY;
249 r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
250 r->out.resp->nb_referrals = junction->referral_count;
252 r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
253 if (self_referral) {
254 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
257 r->out.resp->referral_entries = talloc_zero_array(r,
258 struct dfs_referral_type,
259 r->out.resp->nb_referrals);
260 if (r->out.resp->referral_entries == NULL) {
261 return NT_STATUS_NO_MEMORY;
264 switch (max_referral_level) {
265 case 2:
266 for(i=0; i < junction->referral_count; i++) {
267 struct referral *ref = &junction->referral_list[i];
268 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
269 struct dfs_referral_type *t =
270 &r->out.resp->referral_entries[i];
271 struct dfs_referral_v2 *v2 = &t->referral.v2;
273 t->version = 2;
274 v2->size = VERSION2_REFERRAL_SIZE;
275 if (self_referral) {
276 v2->server_type = DFS_SERVER_ROOT;
277 } else {
278 v2->server_type = DFS_SERVER_NON_ROOT;
280 v2->entry_flags = 0;
281 v2->proximity = ref->proximity;
282 v2->ttl = ref->ttl;
283 v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
284 if (v2->DFS_path == NULL) {
285 return NT_STATUS_NO_MEMORY;
287 v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
288 if (v2->DFS_alt_path == NULL) {
289 return NT_STATUS_NO_MEMORY;
291 v2->netw_address = talloc_strdup(mem_ctx,
292 ref->alternate_path);
293 if (v2->netw_address == NULL) {
294 return NT_STATUS_NO_MEMORY;
298 break;
299 case 3:
300 for(i=0; i < junction->referral_count; i++) {
301 struct referral *ref = &junction->referral_list[i];
302 TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
303 struct dfs_referral_type *t =
304 &r->out.resp->referral_entries[i];
305 struct dfs_referral_v3 *v3 = &t->referral.v3;
306 struct dfs_normal_referral *r1 = &v3->referrals.r1;
308 t->version = 3;
309 v3->size = VERSION3_REFERRAL_SIZE;
310 if (self_referral) {
311 v3->server_type = DFS_SERVER_ROOT;
312 } else {
313 v3->server_type = DFS_SERVER_NON_ROOT;
315 v3->entry_flags = 0;
316 v3->ttl = ref->ttl;
317 r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
318 if (r1->DFS_path == NULL) {
319 return NT_STATUS_NO_MEMORY;
321 r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
322 if (r1->DFS_alt_path == NULL) {
323 return NT_STATUS_NO_MEMORY;
325 r1->netw_address = talloc_strdup(mem_ctx,
326 ref->alternate_path);
327 if (r1->netw_address == NULL) {
328 return NT_STATUS_NO_MEMORY;
331 break;
332 default:
333 DEBUG(0,("Invalid dfs referral version: %d\n",
334 max_referral_level));
335 return NT_STATUS_INVALID_LEVEL;
338 if (DEBUGLVL(10)) {
339 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
342 return NT_STATUS_OK;
345 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
346 TALLOC_CTX *mem_ctx,
347 const char *service_path,
348 char **base_volume)
350 return NT_STATUS_NOT_SUPPORTED;
353 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
354 TALLOC_CTX *mem_ctx,
355 const char *base_volume,
356 time_t *tstamp,
357 bool rw,
358 char **base_path,
359 char **snap_path)
361 return NT_STATUS_NOT_SUPPORTED;
364 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
365 TALLOC_CTX *mem_ctx,
366 char *base_path,
367 char *snap_path)
369 return NT_STATUS_NOT_SUPPORTED;
372 /* Directory operations */
374 static DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32_t attr)
376 DIR *result;
378 START_PROFILE(syscall_opendir);
379 result = opendir(fname);
380 END_PROFILE(syscall_opendir);
381 return result;
384 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
385 files_struct *fsp,
386 const char *mask,
387 uint32_t attr)
389 DIR *result;
391 START_PROFILE(syscall_fdopendir);
392 result = sys_fdopendir(fsp->fh->fd);
393 END_PROFILE(syscall_fdopendir);
394 return result;
398 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
399 DIR *dirp,
400 SMB_STRUCT_STAT *sbuf)
402 struct dirent *result;
404 START_PROFILE(syscall_readdir);
405 result = readdir(dirp);
406 END_PROFILE(syscall_readdir);
407 if (sbuf) {
408 /* Default Posix readdir() does not give us stat info.
409 * Set to invalid to indicate we didn't return this info. */
410 SET_STAT_INVALID(*sbuf);
411 #if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
412 if (result != NULL) {
413 /* See if we can efficiently return this. */
414 struct stat st;
415 int flags = (lp_posix_pathnames() ?
416 AT_SYMLINK_NOFOLLOW : 0);
417 int ret = fstatat(dirfd(dirp),
418 result->d_name,
419 &st,
420 flags);
421 if (ret == 0) {
422 init_stat_ex_from_stat(sbuf,
423 &st,
424 lp_fake_directory_create_times(
425 SNUM(handle->conn)));
428 #endif
430 return result;
433 static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
434 const struct smb_filename *fname,
435 TALLOC_CTX *mem_ctx,
436 struct readdir_attr_data **attr_data)
438 return NT_STATUS_NOT_SUPPORTED;
441 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
443 START_PROFILE(syscall_seekdir);
444 seekdir(dirp, offset);
445 END_PROFILE(syscall_seekdir);
448 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
450 long result;
451 START_PROFILE(syscall_telldir);
452 result = telldir(dirp);
453 END_PROFILE(syscall_telldir);
454 return result;
457 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
459 START_PROFILE(syscall_rewinddir);
460 rewinddir(dirp);
461 END_PROFILE(syscall_rewinddir);
464 static int vfswrap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
466 int result;
467 bool has_dacl = False;
468 char *parent = NULL;
470 START_PROFILE(syscall_mkdir);
472 if (lp_inherit_acls(SNUM(handle->conn))
473 && parent_dirname(talloc_tos(), path, &parent, NULL)
474 && (has_dacl = directory_has_default_acl(handle->conn, parent))) {
475 mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
478 TALLOC_FREE(parent);
480 result = mkdir(path, mode);
482 if (result == 0 && !has_dacl) {
484 * We need to do this as the default behavior of POSIX ACLs
485 * is to set the mask to be the requested group permission
486 * bits, not the group permission bits to be the requested
487 * group permission bits. This is not what we want, as it will
488 * mess up any inherited ACL bits that were set. JRA.
490 int saved_errno = errno; /* We may get ENOSYS */
491 if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
492 errno = saved_errno;
495 END_PROFILE(syscall_mkdir);
496 return result;
499 static int vfswrap_rmdir(vfs_handle_struct *handle, const char *path)
501 int result;
503 START_PROFILE(syscall_rmdir);
504 result = rmdir(path);
505 END_PROFILE(syscall_rmdir);
506 return result;
509 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
511 int result;
513 START_PROFILE(syscall_closedir);
514 result = closedir(dirp);
515 END_PROFILE(syscall_closedir);
516 return result;
519 static void vfswrap_init_search_op(vfs_handle_struct *handle,
520 DIR *dirp)
522 /* Default behavior is a NOOP */
525 /* File operations */
527 static int vfswrap_open(vfs_handle_struct *handle,
528 struct smb_filename *smb_fname,
529 files_struct *fsp, int flags, mode_t mode)
531 int result = -1;
533 START_PROFILE(syscall_open);
535 if (smb_fname->stream_name) {
536 errno = ENOENT;
537 goto out;
540 result = open(smb_fname->base_name, flags, mode);
541 out:
542 END_PROFILE(syscall_open);
543 return result;
546 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
547 struct smb_request *req,
548 uint16_t root_dir_fid,
549 struct smb_filename *smb_fname,
550 uint32_t access_mask,
551 uint32_t share_access,
552 uint32_t create_disposition,
553 uint32_t create_options,
554 uint32_t file_attributes,
555 uint32_t oplock_request,
556 struct smb2_lease *lease,
557 uint64_t allocation_size,
558 uint32_t private_flags,
559 struct security_descriptor *sd,
560 struct ea_list *ea_list,
561 files_struct **result,
562 int *pinfo,
563 const struct smb2_create_blobs *in_context_blobs,
564 struct smb2_create_blobs *out_context_blobs)
566 struct smb2_create_blob *svhdx = NULL;
569 * It might be empty ... and smb2_create_blob_find does not handle that
571 if (in_context_blobs) {
572 svhdx = smb2_create_blob_find(in_context_blobs,
573 SVHDX_OPEN_DEVICE_CONTEXT);
576 if (svhdx != NULL) {
577 /* SharedVHD is not yet supported */
578 DEBUG(10, ("Shared VHD not yet supported, INVALID_DEVICE_REQUEST\n"));
579 return NT_STATUS_INVALID_DEVICE_REQUEST;
582 return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
583 access_mask, share_access,
584 create_disposition, create_options,
585 file_attributes, oplock_request, lease,
586 allocation_size, private_flags,
587 sd, ea_list, result,
588 pinfo, in_context_blobs, out_context_blobs);
591 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
593 int result;
595 START_PROFILE(syscall_close);
596 result = fd_close_posix(fsp);
597 END_PROFILE(syscall_close);
598 return result;
601 static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
603 ssize_t result;
605 START_PROFILE_BYTES(syscall_read, n);
606 result = sys_read(fsp->fh->fd, data, n);
607 END_PROFILE_BYTES(syscall_read);
608 return result;
611 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
612 size_t n, off_t offset)
614 ssize_t result;
616 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
617 START_PROFILE_BYTES(syscall_pread, n);
618 result = sys_pread(fsp->fh->fd, data, n, offset);
619 END_PROFILE_BYTES(syscall_pread);
621 if (result == -1 && errno == ESPIPE) {
622 /* Maintain the fiction that pipes can be seeked (sought?) on. */
623 result = SMB_VFS_READ(fsp, data, n);
624 fsp->fh->pos = 0;
627 #else /* HAVE_PREAD */
628 off_t curr;
629 int lerrno;
631 curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
632 if (curr == -1 && errno == ESPIPE) {
633 /* Maintain the fiction that pipes can be seeked (sought?) on. */
634 result = SMB_VFS_READ(fsp, data, n);
635 fsp->fh->pos = 0;
636 return result;
639 if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
640 return -1;
643 errno = 0;
644 result = SMB_VFS_READ(fsp, data, n);
645 lerrno = errno;
647 SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
648 errno = lerrno;
650 #endif /* HAVE_PREAD */
652 return result;
655 static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
657 ssize_t result;
659 START_PROFILE_BYTES(syscall_write, n);
660 result = sys_write(fsp->fh->fd, data, n);
661 END_PROFILE_BYTES(syscall_write);
662 return result;
665 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
666 size_t n, off_t offset)
668 ssize_t result;
670 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
671 START_PROFILE_BYTES(syscall_pwrite, n);
672 result = sys_pwrite(fsp->fh->fd, data, n, offset);
673 END_PROFILE_BYTES(syscall_pwrite);
675 if (result == -1 && errno == ESPIPE) {
676 /* Maintain the fiction that pipes can be sought on. */
677 result = SMB_VFS_WRITE(fsp, data, n);
680 #else /* HAVE_PWRITE */
681 off_t curr;
682 int lerrno;
684 curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
685 if (curr == -1) {
686 return -1;
689 if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
690 return -1;
693 result = SMB_VFS_WRITE(fsp, data, n);
694 lerrno = errno;
696 SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
697 errno = lerrno;
699 #endif /* HAVE_PWRITE */
701 return result;
704 static void vfswrap_asys_finished(struct tevent_context *ev,
705 struct tevent_fd *fde,
706 uint16_t flags, void *p);
708 static bool vfswrap_init_asys_ctx(struct smbd_server_connection *conn)
710 struct asys_context *ctx;
711 struct tevent_fd *fde;
712 int ret;
713 int fd;
715 if (conn->asys_ctx != NULL) {
716 return true;
719 ret = asys_context_init(&ctx, aio_pending_size);
720 if (ret != 0) {
721 DEBUG(1, ("asys_context_init failed: %s\n", strerror(ret)));
722 return false;
725 fd = asys_signalfd(ctx);
727 ret = set_blocking(fd, false);
728 if (ret != 0) {
729 DBG_WARNING("set_blocking failed: %s\n", strerror(errno));
730 goto fail;
733 fde = tevent_add_fd(conn->ev_ctx, conn, fd, TEVENT_FD_READ,
734 vfswrap_asys_finished, ctx);
735 if (fde == NULL) {
736 DEBUG(1, ("tevent_add_fd failed\n"));
737 goto fail;
740 conn->asys_ctx = ctx;
741 conn->asys_fde = fde;
742 return true;
744 fail:
745 asys_context_destroy(ctx);
746 return false;
749 struct vfswrap_asys_state {
750 struct asys_context *asys_ctx;
751 struct tevent_req *req;
752 ssize_t ret;
753 int err;
754 SMBPROFILE_BASIC_ASYNC_STATE(profile_basic);
755 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
758 static int vfswrap_asys_state_destructor(struct vfswrap_asys_state *s)
760 asys_cancel(s->asys_ctx, s->req);
761 return 0;
764 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
765 TALLOC_CTX *mem_ctx,
766 struct tevent_context *ev,
767 struct files_struct *fsp,
768 void *data,
769 size_t n, off_t offset)
771 struct tevent_req *req;
772 struct vfswrap_asys_state *state;
773 int ret;
775 req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
776 if (req == NULL) {
777 return NULL;
779 if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
780 tevent_req_oom(req);
781 return tevent_req_post(req, ev);
783 state->asys_ctx = handle->conn->sconn->asys_ctx;
784 state->req = req;
786 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
787 state->profile_bytes, n);
788 ret = asys_pread(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
789 if (ret != 0) {
790 tevent_req_error(req, ret);
791 return tevent_req_post(req, ev);
793 talloc_set_destructor(state, vfswrap_asys_state_destructor);
795 return req;
798 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
799 TALLOC_CTX *mem_ctx,
800 struct tevent_context *ev,
801 struct files_struct *fsp,
802 const void *data,
803 size_t n, off_t offset)
805 struct tevent_req *req;
806 struct vfswrap_asys_state *state;
807 int ret;
809 req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
810 if (req == NULL) {
811 return NULL;
813 if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
814 tevent_req_oom(req);
815 return tevent_req_post(req, ev);
817 state->asys_ctx = handle->conn->sconn->asys_ctx;
818 state->req = req;
820 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
821 state->profile_bytes, n);
822 ret = asys_pwrite(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
823 if (ret != 0) {
824 tevent_req_error(req, ret);
825 return tevent_req_post(req, ev);
827 talloc_set_destructor(state, vfswrap_asys_state_destructor);
829 return req;
832 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
833 TALLOC_CTX *mem_ctx,
834 struct tevent_context *ev,
835 struct files_struct *fsp)
837 struct tevent_req *req;
838 struct vfswrap_asys_state *state;
839 int ret;
841 req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
842 if (req == NULL) {
843 return NULL;
845 if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
846 tevent_req_oom(req);
847 return tevent_req_post(req, ev);
849 state->asys_ctx = handle->conn->sconn->asys_ctx;
850 state->req = req;
852 SMBPROFILE_BASIC_ASYNC_START(syscall_asys_fsync, profile_p,
853 state->profile_basic);
854 ret = asys_fsync(state->asys_ctx, fsp->fh->fd, req);
855 if (ret != 0) {
856 tevent_req_error(req, ret);
857 return tevent_req_post(req, ev);
859 talloc_set_destructor(state, vfswrap_asys_state_destructor);
861 return req;
864 static void vfswrap_asys_finished(struct tevent_context *ev,
865 struct tevent_fd *fde,
866 uint16_t flags, void *p)
868 struct asys_context *asys_ctx = (struct asys_context *)p;
869 struct asys_result results[outstanding_aio_calls];
870 int i, ret;
872 if ((flags & TEVENT_FD_READ) == 0) {
873 return;
876 ret = asys_results(asys_ctx, results, outstanding_aio_calls);
877 if (ret < 0) {
878 DEBUG(1, ("asys_results returned %s\n", strerror(-ret)));
879 return;
882 for (i=0; i<ret; i++) {
883 struct asys_result *result = &results[i];
884 struct tevent_req *req;
885 struct vfswrap_asys_state *state;
887 if ((result->ret == -1) && (result->err == ECANCELED)) {
888 continue;
891 req = talloc_get_type_abort(result->private_data,
892 struct tevent_req);
893 state = tevent_req_data(req, struct vfswrap_asys_state);
895 talloc_set_destructor(state, NULL);
897 SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
898 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
899 state->ret = result->ret;
900 state->err = result->err;
901 tevent_req_defer_callback(req, ev);
902 tevent_req_done(req);
906 static ssize_t vfswrap_asys_ssize_t_recv(struct tevent_req *req, int *err)
908 struct vfswrap_asys_state *state = tevent_req_data(
909 req, struct vfswrap_asys_state);
911 if (tevent_req_is_unix_error(req, err)) {
912 return -1;
914 *err = state->err;
915 return state->ret;
918 static int vfswrap_asys_int_recv(struct tevent_req *req, int *err)
920 struct vfswrap_asys_state *state = tevent_req_data(
921 req, struct vfswrap_asys_state);
923 if (tevent_req_is_unix_error(req, err)) {
924 return -1;
926 *err = state->err;
927 return state->ret;
930 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
932 off_t result = 0;
934 START_PROFILE(syscall_lseek);
936 /* Cope with 'stat' file opens. */
937 if (fsp->fh->fd != -1)
938 result = lseek(fsp->fh->fd, offset, whence);
941 * We want to maintain the fiction that we can seek
942 * on a fifo for file system purposes. This allows
943 * people to set up UNIX fifo's that feed data to Windows
944 * applications. JRA.
947 if((result == -1) && (errno == ESPIPE)) {
948 result = 0;
949 errno = 0;
952 END_PROFILE(syscall_lseek);
953 return result;
956 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
957 off_t offset, size_t n)
959 ssize_t result;
961 START_PROFILE_BYTES(syscall_sendfile, n);
962 result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
963 END_PROFILE_BYTES(syscall_sendfile);
964 return result;
967 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
968 int fromfd,
969 files_struct *tofsp,
970 off_t offset,
971 size_t n)
973 ssize_t result;
975 START_PROFILE_BYTES(syscall_recvfile, n);
976 result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
977 END_PROFILE_BYTES(syscall_recvfile);
978 return result;
981 static int vfswrap_rename(vfs_handle_struct *handle,
982 const struct smb_filename *smb_fname_src,
983 const struct smb_filename *smb_fname_dst)
985 int result = -1;
987 START_PROFILE(syscall_rename);
989 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
990 errno = ENOENT;
991 goto out;
994 result = rename(smb_fname_src->base_name, smb_fname_dst->base_name);
996 out:
997 END_PROFILE(syscall_rename);
998 return result;
1001 static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp)
1003 #ifdef HAVE_FSYNC
1004 int result;
1006 START_PROFILE(syscall_fsync);
1007 result = fsync(fsp->fh->fd);
1008 END_PROFILE(syscall_fsync);
1009 return result;
1010 #else
1011 return 0;
1012 #endif
1015 static int vfswrap_stat(vfs_handle_struct *handle,
1016 struct smb_filename *smb_fname)
1018 int result = -1;
1020 START_PROFILE(syscall_stat);
1022 if (smb_fname->stream_name) {
1023 errno = ENOENT;
1024 goto out;
1027 result = sys_stat(smb_fname->base_name, &smb_fname->st,
1028 lp_fake_directory_create_times(SNUM(handle->conn)));
1029 out:
1030 END_PROFILE(syscall_stat);
1031 return result;
1034 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1036 int result;
1038 START_PROFILE(syscall_fstat);
1039 result = sys_fstat(fsp->fh->fd,
1040 sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1041 END_PROFILE(syscall_fstat);
1042 return result;
1045 static int vfswrap_lstat(vfs_handle_struct *handle,
1046 struct smb_filename *smb_fname)
1048 int result = -1;
1050 START_PROFILE(syscall_lstat);
1052 if (smb_fname->stream_name) {
1053 errno = ENOENT;
1054 goto out;
1057 result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1058 lp_fake_directory_create_times(SNUM(handle->conn)));
1059 out:
1060 END_PROFILE(syscall_lstat);
1061 return result;
1064 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1065 const char *name,
1066 enum vfs_translate_direction direction,
1067 TALLOC_CTX *mem_ctx,
1068 char **mapped_name)
1070 return NT_STATUS_NONE_MAPPED;
1074 * Implement the default fsctl operation.
1076 static bool vfswrap_logged_ioctl_message = false;
1078 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1079 struct files_struct *fsp,
1080 TALLOC_CTX *ctx,
1081 uint32_t function,
1082 uint16_t req_flags, /* Needed for UNICODE ... */
1083 const uint8_t *_in_data,
1084 uint32_t in_len,
1085 uint8_t **_out_data,
1086 uint32_t max_out_len,
1087 uint32_t *out_len)
1089 const char *in_data = (const char *)_in_data;
1090 char **out_data = (char **)_out_data;
1091 NTSTATUS status;
1093 switch (function) {
1094 case FSCTL_SET_SPARSE:
1096 bool set_sparse = true;
1098 if (in_len >= 1 && in_data[0] == 0) {
1099 set_sparse = false;
1102 status = file_set_sparse(handle->conn, fsp, set_sparse);
1104 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1105 ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1106 smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1107 nt_errstr(status)));
1109 return status;
1112 case FSCTL_CREATE_OR_GET_OBJECT_ID:
1114 unsigned char objid[16];
1115 char *return_data = NULL;
1117 /* This should return the object-id on this file.
1118 * I think I'll make this be the inode+dev. JRA.
1121 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1122 fsp_fnum_dbg(fsp)));
1124 *out_len = MIN(max_out_len, 64);
1126 /* Hmmm, will this cause problems if less data asked for? */
1127 return_data = talloc_array(ctx, char, 64);
1128 if (return_data == NULL) {
1129 return NT_STATUS_NO_MEMORY;
1132 /* For backwards compatibility only store the dev/inode. */
1133 push_file_id_16(return_data, &fsp->file_id);
1134 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1135 push_file_id_16(return_data+32, &fsp->file_id);
1136 memset(return_data+48, 0, 16);
1137 *out_data = return_data;
1138 return NT_STATUS_OK;
1141 case FSCTL_GET_REPARSE_POINT:
1143 /* Fail it with STATUS_NOT_A_REPARSE_POINT */
1144 DEBUG(10, ("FSCTL_GET_REPARSE_POINT: called on %s. "
1145 "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
1146 return NT_STATUS_NOT_A_REPARSE_POINT;
1149 case FSCTL_SET_REPARSE_POINT:
1151 /* Fail it with STATUS_NOT_A_REPARSE_POINT */
1152 DEBUG(10, ("FSCTL_SET_REPARSE_POINT: called on %s. "
1153 "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
1154 return NT_STATUS_NOT_A_REPARSE_POINT;
1157 case FSCTL_GET_SHADOW_COPY_DATA:
1160 * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1161 * and return their volume names. If max_data_count is 16, then it is just
1162 * asking for the number of volumes and length of the combined names.
1164 * pdata is the data allocated by our caller, but that uses
1165 * total_data_count (which is 0 in our case) rather than max_data_count.
1166 * Allocate the correct amount and return the pointer to let
1167 * it be deallocated when we return.
1169 struct shadow_copy_data *shadow_data = NULL;
1170 bool labels = False;
1171 uint32_t labels_data_count = 0;
1172 uint32_t i;
1173 char *cur_pdata = NULL;
1175 if (max_out_len < 16) {
1176 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1177 max_out_len));
1178 return NT_STATUS_INVALID_PARAMETER;
1181 if (max_out_len > 16) {
1182 labels = True;
1185 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1186 if (shadow_data == NULL) {
1187 DEBUG(0,("TALLOC_ZERO() failed!\n"));
1188 return NT_STATUS_NO_MEMORY;
1192 * Call the VFS routine to actually do the work.
1194 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1195 int log_lev = 0;
1196 if (errno == 0) {
1197 /* broken module didn't set errno on error */
1198 status = NT_STATUS_UNSUCCESSFUL;
1199 } else {
1200 status = map_nt_error_from_unix(errno);
1201 if (NT_STATUS_EQUAL(status,
1202 NT_STATUS_NOT_SUPPORTED)) {
1203 log_lev = 5;
1206 DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1207 "connectpath %s, failed - %s.\n",
1208 fsp->conn->connectpath,
1209 nt_errstr(status)));
1210 TALLOC_FREE(shadow_data);
1211 return status;
1214 labels_data_count = (shadow_data->num_volumes * 2 *
1215 sizeof(SHADOW_COPY_LABEL)) + 2;
1217 if (!labels) {
1218 *out_len = 16;
1219 } else {
1220 *out_len = 12 + labels_data_count;
1223 if (max_out_len < *out_len) {
1224 DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1225 max_out_len, *out_len));
1226 TALLOC_FREE(shadow_data);
1227 return NT_STATUS_BUFFER_TOO_SMALL;
1230 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1231 if (cur_pdata == NULL) {
1232 TALLOC_FREE(shadow_data);
1233 return NT_STATUS_NO_MEMORY;
1236 *out_data = cur_pdata;
1238 /* num_volumes 4 bytes */
1239 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1241 if (labels) {
1242 /* num_labels 4 bytes */
1243 SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1246 /* needed_data_count 4 bytes */
1247 SIVAL(cur_pdata, 8, labels_data_count);
1249 cur_pdata += 12;
1251 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1252 shadow_data->num_volumes, fsp_str_dbg(fsp)));
1253 if (labels && shadow_data->labels) {
1254 for (i=0; i<shadow_data->num_volumes; i++) {
1255 size_t len = 0;
1256 status = srvstr_push(cur_pdata, req_flags,
1257 cur_pdata, shadow_data->labels[i],
1258 2 * sizeof(SHADOW_COPY_LABEL),
1259 STR_UNICODE|STR_TERMINATE, &len);
1260 if (!NT_STATUS_IS_OK(status)) {
1261 TALLOC_FREE(*out_data);
1262 TALLOC_FREE(shadow_data);
1263 return status;
1265 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1266 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1270 TALLOC_FREE(shadow_data);
1272 return NT_STATUS_OK;
1275 case FSCTL_FIND_FILES_BY_SID:
1277 /* pretend this succeeded -
1279 * we have to send back a list with all files owned by this SID
1281 * but I have to check that --metze
1283 struct dom_sid sid;
1284 uid_t uid;
1285 size_t sid_len;
1287 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1288 fsp_fnum_dbg(fsp)));
1290 if (in_len < 8) {
1291 /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1292 return NT_STATUS_INVALID_PARAMETER;
1295 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1297 /* unknown 4 bytes: this is not the length of the sid :-( */
1298 /*unknown = IVAL(pdata,0);*/
1300 if (!sid_parse(_in_data + 4, sid_len, &sid)) {
1301 return NT_STATUS_INVALID_PARAMETER;
1303 DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid)));
1305 if (!sid_to_uid(&sid, &uid)) {
1306 DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1307 sid_string_dbg(&sid),
1308 (unsigned long)sid_len));
1309 uid = (-1);
1312 /* we can take a look at the find source :-)
1314 * find ./ -uid $uid -name '*' is what we need here
1317 * and send 4bytes len and then NULL terminated unicode strings
1318 * for each file
1320 * but I don't know how to deal with the paged results
1321 * (maybe we can hang the result anywhere in the fsp struct)
1323 * but I don't know how to deal with the paged results
1324 * (maybe we can hang the result anywhere in the fsp struct)
1326 * we don't send all files at once
1327 * and at the next we should *not* start from the beginning,
1328 * so we have to cache the result
1330 * --metze
1333 /* this works for now... */
1334 return NT_STATUS_OK;
1337 case FSCTL_QUERY_ALLOCATED_RANGES:
1339 /* FIXME: This is just a dummy reply, telling that all of the
1340 * file is allocated. MKS cp needs that.
1341 * Adding the real allocated ranges via FIEMAP on Linux
1342 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1343 * this FSCTL correct for sparse files.
1345 uint64_t offset, length;
1346 char *out_data_tmp = NULL;
1348 if (in_len != 16) {
1349 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1350 in_len));
1351 return NT_STATUS_INVALID_PARAMETER;
1354 if (max_out_len < 16) {
1355 DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1356 max_out_len));
1357 return NT_STATUS_INVALID_PARAMETER;
1360 offset = BVAL(in_data,0);
1361 length = BVAL(in_data,8);
1363 if (offset + length < offset) {
1364 /* No 64-bit integer wrap. */
1365 return NT_STATUS_INVALID_PARAMETER;
1368 /* Shouldn't this be SMB_VFS_STAT ... ? */
1369 status = vfs_stat_fsp(fsp);
1370 if (!NT_STATUS_IS_OK(status)) {
1371 return status;
1374 *out_len = 16;
1375 out_data_tmp = talloc_array(ctx, char, *out_len);
1376 if (out_data_tmp == NULL) {
1377 DEBUG(10, ("unable to allocate memory for response\n"));
1378 return NT_STATUS_NO_MEMORY;
1381 if (offset > fsp->fsp_name->st.st_ex_size ||
1382 fsp->fsp_name->st.st_ex_size == 0 ||
1383 length == 0) {
1384 memset(out_data_tmp, 0, *out_len);
1385 } else {
1386 uint64_t end = offset + length;
1387 end = MIN(end, fsp->fsp_name->st.st_ex_size);
1388 SBVAL(out_data_tmp, 0, 0);
1389 SBVAL(out_data_tmp, 8, end);
1392 *out_data = out_data_tmp;
1394 return NT_STATUS_OK;
1397 case FSCTL_IS_VOLUME_DIRTY:
1399 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1400 "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1402 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1403 * says we have to respond with NT_STATUS_INVALID_PARAMETER
1405 return NT_STATUS_INVALID_PARAMETER;
1408 default:
1410 * Only print once ... unfortunately there could be lots of
1411 * different FSCTLs that are called.
1413 if (!vfswrap_logged_ioctl_message) {
1414 vfswrap_logged_ioctl_message = true;
1415 DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1416 __func__, function));
1420 return NT_STATUS_NOT_SUPPORTED;
1423 struct vfs_cc_state {
1424 off_t copied;
1425 uint8_t *buf;
1428 static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *handle,
1429 TALLOC_CTX *mem_ctx,
1430 struct tevent_context *ev,
1431 struct files_struct *src_fsp,
1432 off_t src_off,
1433 struct files_struct *dest_fsp,
1434 off_t dest_off,
1435 off_t num)
1437 struct tevent_req *req;
1438 struct vfs_cc_state *vfs_cc_state;
1439 NTSTATUS status;
1441 DEBUG(10, ("performing server side copy chunk of length %lu\n",
1442 (unsigned long)num));
1444 req = tevent_req_create(mem_ctx, &vfs_cc_state, struct vfs_cc_state);
1445 if (req == NULL) {
1446 return NULL;
1449 vfs_cc_state->buf = talloc_array(vfs_cc_state, uint8_t,
1450 MIN(num, 8*1024*1024));
1451 if (tevent_req_nomem(vfs_cc_state->buf, req)) {
1452 return tevent_req_post(req, ev);
1455 status = vfs_stat_fsp(src_fsp);
1456 if (tevent_req_nterror(req, status)) {
1457 return tevent_req_post(req, ev);
1460 if (src_fsp->fsp_name->st.st_ex_size < src_off + num) {
1462 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
1463 * If the SourceOffset or SourceOffset + Length extends beyond
1464 * the end of file, the server SHOULD<240> treat this as a
1465 * STATUS_END_OF_FILE error.
1466 * ...
1467 * <240> Section 3.3.5.15.6: Windows servers will return
1468 * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
1470 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
1471 return tevent_req_post(req, ev);
1474 /* could use 2.6.33+ sendfile here to do this in kernel */
1475 while (vfs_cc_state->copied < num) {
1476 ssize_t ret;
1477 struct lock_struct lck;
1478 int saved_errno;
1480 off_t this_num = MIN(talloc_array_length(vfs_cc_state->buf),
1481 num - vfs_cc_state->copied);
1483 if (src_fsp->op == NULL) {
1484 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1485 return tevent_req_post(req, ev);
1487 init_strict_lock_struct(src_fsp,
1488 src_fsp->op->global->open_persistent_id,
1489 src_off,
1490 this_num,
1491 READ_LOCK,
1492 &lck);
1494 if (!SMB_VFS_STRICT_LOCK(src_fsp->conn, src_fsp, &lck)) {
1495 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
1496 return tevent_req_post(req, ev);
1499 ret = SMB_VFS_PREAD(src_fsp, vfs_cc_state->buf,
1500 this_num, src_off);
1501 if (ret == -1) {
1502 saved_errno = errno;
1505 SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &lck);
1507 if (ret == -1) {
1508 errno = saved_errno;
1509 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1510 return tevent_req_post(req, ev);
1512 if (ret != this_num) {
1513 /* zero tolerance for short reads */
1514 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
1515 return tevent_req_post(req, ev);
1518 src_off += ret;
1520 if (dest_fsp->op == NULL) {
1521 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1522 return tevent_req_post(req, ev);
1525 init_strict_lock_struct(dest_fsp,
1526 dest_fsp->op->global->open_persistent_id,
1527 dest_off,
1528 this_num,
1529 WRITE_LOCK,
1530 &lck);
1532 if (!SMB_VFS_STRICT_LOCK(dest_fsp->conn, dest_fsp, &lck)) {
1533 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
1534 return tevent_req_post(req, ev);
1537 ret = SMB_VFS_PWRITE(dest_fsp, vfs_cc_state->buf,
1538 this_num, dest_off);
1539 if (ret == -1) {
1540 saved_errno = errno;
1543 SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &lck);
1545 if (ret == -1) {
1546 errno = saved_errno;
1547 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1548 return tevent_req_post(req, ev);
1550 if (ret != this_num) {
1551 /* zero tolerance for short writes */
1552 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
1553 return tevent_req_post(req, ev);
1555 dest_off += ret;
1557 vfs_cc_state->copied += this_num;
1560 tevent_req_done(req);
1561 return tevent_req_post(req, ev);
1564 static NTSTATUS vfswrap_copy_chunk_recv(struct vfs_handle_struct *handle,
1565 struct tevent_req *req,
1566 off_t *copied)
1568 struct vfs_cc_state *vfs_cc_state = tevent_req_data(req,
1569 struct vfs_cc_state);
1570 NTSTATUS status;
1572 if (tevent_req_is_nterror(req, &status)) {
1573 DEBUG(2, ("server side copy chunk failed: %s\n",
1574 nt_errstr(status)));
1575 *copied = 0;
1576 tevent_req_received(req);
1577 return status;
1580 *copied = vfs_cc_state->copied;
1581 DEBUG(10, ("server side copy chunk copied %lu\n",
1582 (unsigned long)*copied));
1583 tevent_req_received(req);
1585 return NT_STATUS_OK;
1588 static NTSTATUS vfswrap_get_compression(struct vfs_handle_struct *handle,
1589 TALLOC_CTX *mem_ctx,
1590 struct files_struct *fsp,
1591 struct smb_filename *smb_fname,
1592 uint16_t *_compression_fmt)
1594 return NT_STATUS_INVALID_DEVICE_REQUEST;
1597 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
1598 TALLOC_CTX *mem_ctx,
1599 struct files_struct *fsp,
1600 uint16_t compression_fmt)
1602 return NT_STATUS_INVALID_DEVICE_REQUEST;
1605 /********************************************************************
1606 Given a stat buffer return the allocated size on disk, taking into
1607 account sparse files.
1608 ********************************************************************/
1609 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
1610 struct files_struct *fsp,
1611 const SMB_STRUCT_STAT *sbuf)
1613 uint64_t result;
1615 START_PROFILE(syscall_get_alloc_size);
1617 if(S_ISDIR(sbuf->st_ex_mode)) {
1618 result = 0;
1619 goto out;
1622 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
1623 /* The type of st_blocksize is blkcnt_t which *MUST* be
1624 signed (according to POSIX) and can be less than 64-bits.
1625 Ensure when we're converting to 64 bits wide we don't
1626 sign extend. */
1627 #if defined(SIZEOF_BLKCNT_T_8)
1628 result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
1629 #elif defined(SIZEOF_BLKCNT_T_4)
1631 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
1632 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
1634 #else
1635 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
1636 #endif
1637 if (result == 0) {
1639 * Some file systems do not allocate a block for very
1640 * small files. But for non-empty file should report a
1641 * positive size.
1644 uint64_t filesize = get_file_size_stat(sbuf);
1645 if (filesize > 0) {
1646 result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
1649 #else
1650 result = get_file_size_stat(sbuf);
1651 #endif
1653 if (fsp && fsp->initial_allocation_size)
1654 result = MAX(result,fsp->initial_allocation_size);
1656 result = smb_roundup(handle->conn, result);
1658 out:
1659 END_PROFILE(syscall_get_alloc_size);
1660 return result;
1663 static int vfswrap_unlink(vfs_handle_struct *handle,
1664 const struct smb_filename *smb_fname)
1666 int result = -1;
1668 START_PROFILE(syscall_unlink);
1670 if (smb_fname->stream_name) {
1671 errno = ENOENT;
1672 goto out;
1674 result = unlink(smb_fname->base_name);
1676 out:
1677 END_PROFILE(syscall_unlink);
1678 return result;
1681 static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
1683 int result;
1685 START_PROFILE(syscall_chmod);
1688 * We need to do this due to the fact that the default POSIX ACL
1689 * chmod modifies the ACL *mask* for the group owner, not the
1690 * group owner bits directly. JRA.
1695 int saved_errno = errno; /* We might get ENOSYS */
1696 if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
1697 END_PROFILE(syscall_chmod);
1698 return result;
1700 /* Error - return the old errno. */
1701 errno = saved_errno;
1704 result = chmod(path, mode);
1705 END_PROFILE(syscall_chmod);
1706 return result;
1709 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
1711 int result;
1713 START_PROFILE(syscall_fchmod);
1716 * We need to do this due to the fact that the default POSIX ACL
1717 * chmod modifies the ACL *mask* for the group owner, not the
1718 * group owner bits directly. JRA.
1722 int saved_errno = errno; /* We might get ENOSYS */
1723 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
1724 END_PROFILE(syscall_fchmod);
1725 return result;
1727 /* Error - return the old errno. */
1728 errno = saved_errno;
1731 #if defined(HAVE_FCHMOD)
1732 result = fchmod(fsp->fh->fd, mode);
1733 #else
1734 result = -1;
1735 errno = ENOSYS;
1736 #endif
1738 END_PROFILE(syscall_fchmod);
1739 return result;
1742 static int vfswrap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
1744 int result;
1746 START_PROFILE(syscall_chown);
1747 result = chown(path, uid, gid);
1748 END_PROFILE(syscall_chown);
1749 return result;
1752 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
1754 #ifdef HAVE_FCHOWN
1755 int result;
1757 START_PROFILE(syscall_fchown);
1758 result = fchown(fsp->fh->fd, uid, gid);
1759 END_PROFILE(syscall_fchown);
1760 return result;
1761 #else
1762 errno = ENOSYS;
1763 return -1;
1764 #endif
1767 static int vfswrap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
1769 int result;
1771 START_PROFILE(syscall_lchown);
1772 result = lchown(path, uid, gid);
1773 END_PROFILE(syscall_lchown);
1774 return result;
1777 static int vfswrap_chdir(vfs_handle_struct *handle, const char *path)
1779 int result;
1781 START_PROFILE(syscall_chdir);
1782 result = chdir(path);
1783 END_PROFILE(syscall_chdir);
1784 return result;
1787 static char *vfswrap_getwd(vfs_handle_struct *handle)
1789 char *result;
1791 START_PROFILE(syscall_getwd);
1792 result = sys_getwd();
1793 END_PROFILE(syscall_getwd);
1794 return result;
1797 /*********************************************************************
1798 nsec timestamp resolution call. Convert down to whatever the underlying
1799 system will support.
1800 **********************************************************************/
1802 static int vfswrap_ntimes(vfs_handle_struct *handle,
1803 const struct smb_filename *smb_fname,
1804 struct smb_file_time *ft)
1806 int result = -1;
1808 START_PROFILE(syscall_ntimes);
1810 if (smb_fname->stream_name) {
1811 errno = ENOENT;
1812 goto out;
1815 if (ft != NULL) {
1816 if (null_timespec(ft->atime)) {
1817 ft->atime= smb_fname->st.st_ex_atime;
1820 if (null_timespec(ft->mtime)) {
1821 ft->mtime = smb_fname->st.st_ex_mtime;
1824 if (!null_timespec(ft->create_time)) {
1825 set_create_timespec_ea(handle->conn,
1826 smb_fname,
1827 ft->create_time);
1830 if ((timespec_compare(&ft->atime,
1831 &smb_fname->st.st_ex_atime) == 0) &&
1832 (timespec_compare(&ft->mtime,
1833 &smb_fname->st.st_ex_mtime) == 0)) {
1834 return 0;
1838 #if defined(HAVE_UTIMENSAT)
1839 if (ft != NULL) {
1840 struct timespec ts[2];
1841 ts[0] = ft->atime;
1842 ts[1] = ft->mtime;
1843 result = utimensat(AT_FDCWD, smb_fname->base_name, ts, 0);
1844 } else {
1845 result = utimensat(AT_FDCWD, smb_fname->base_name, NULL, 0);
1847 if (!((result == -1) && (errno == ENOSYS))) {
1848 goto out;
1850 #endif
1851 #if defined(HAVE_UTIMES)
1852 if (ft != NULL) {
1853 struct timeval tv[2];
1854 tv[0] = convert_timespec_to_timeval(ft->atime);
1855 tv[1] = convert_timespec_to_timeval(ft->mtime);
1856 result = utimes(smb_fname->base_name, tv);
1857 } else {
1858 result = utimes(smb_fname->base_name, NULL);
1860 if (!((result == -1) && (errno == ENOSYS))) {
1861 goto out;
1863 #endif
1864 #if defined(HAVE_UTIME)
1865 if (ft != NULL) {
1866 struct utimbuf times;
1867 times.actime = convert_timespec_to_time_t(ft->atime);
1868 times.modtime = convert_timespec_to_time_t(ft->mtime);
1869 result = utime(smb_fname->base_name, &times);
1870 } else {
1871 result = utime(smb_fname->base_name, NULL);
1873 if (!((result == -1) && (errno == ENOSYS))) {
1874 goto out;
1876 #endif
1877 errno = ENOSYS;
1878 result = -1;
1880 out:
1881 END_PROFILE(syscall_ntimes);
1882 return result;
1885 /*********************************************************************
1886 A version of ftruncate that will write the space on disk if strict
1887 allocate is set.
1888 **********************************************************************/
1890 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
1892 off_t space_to_write;
1893 uint64_t space_avail;
1894 uint64_t bsize,dfree,dsize;
1895 int ret;
1896 NTSTATUS status;
1897 SMB_STRUCT_STAT *pst;
1899 status = vfs_stat_fsp(fsp);
1900 if (!NT_STATUS_IS_OK(status)) {
1901 return -1;
1903 pst = &fsp->fsp_name->st;
1905 #ifdef S_ISFIFO
1906 if (S_ISFIFO(pst->st_ex_mode))
1907 return 0;
1908 #endif
1910 if (pst->st_ex_size == len)
1911 return 0;
1913 /* Shrink - just ftruncate. */
1914 if (pst->st_ex_size > len)
1915 return ftruncate(fsp->fh->fd, len);
1917 space_to_write = len - pst->st_ex_size;
1919 /* for allocation try fallocate first. This can fail on some
1920 platforms e.g. when the filesystem doesn't support it and no
1921 emulation is being done by the libc (like on AIX with JFS1). In that
1922 case we do our own emulation. fallocate implementations can
1923 return ENOTSUP or EINVAL in cases like that. */
1924 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1925 if (ret == -1 && errno == ENOSPC) {
1926 return -1;
1928 if (ret == 0) {
1929 return 0;
1931 DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1932 "error %d. Falling back to slow manual allocation\n", errno));
1934 /* available disk space is enough or not? */
1935 space_avail = get_dfree_info(fsp->conn,
1936 fsp->fsp_name->base_name,
1937 &bsize, &dfree, &dsize);
1938 /* space_avail is 1k blocks */
1939 if (space_avail == (uint64_t)-1 ||
1940 ((uint64_t)space_to_write/1024 > space_avail) ) {
1941 errno = ENOSPC;
1942 return -1;
1945 /* Write out the real space on disk. */
1946 ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1947 if (ret != 0) {
1948 return -1;
1951 return 0;
1954 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
1956 int result = -1;
1957 SMB_STRUCT_STAT *pst;
1958 NTSTATUS status;
1959 char c = 0;
1961 START_PROFILE(syscall_ftruncate);
1963 if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->is_sparse) {
1964 result = strict_allocate_ftruncate(handle, fsp, len);
1965 END_PROFILE(syscall_ftruncate);
1966 return result;
1969 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1970 ftruncate if the system supports it. Then I discovered that
1971 you can have some filesystems that support ftruncate
1972 expansion and some that don't! On Linux fat can't do
1973 ftruncate extend but ext2 can. */
1975 result = ftruncate(fsp->fh->fd, len);
1977 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1978 extend a file with ftruncate. Provide alternate implementation
1979 for this */
1981 /* Do an fstat to see if the file is longer than the requested
1982 size in which case the ftruncate above should have
1983 succeeded or shorter, in which case seek to len - 1 and
1984 write 1 byte of zero */
1985 status = vfs_stat_fsp(fsp);
1986 if (!NT_STATUS_IS_OK(status)) {
1987 goto done;
1990 /* We need to update the files_struct after successful ftruncate */
1991 if (result == 0) {
1992 goto done;
1995 pst = &fsp->fsp_name->st;
1997 #ifdef S_ISFIFO
1998 if (S_ISFIFO(pst->st_ex_mode)) {
1999 result = 0;
2000 goto done;
2002 #endif
2004 if (pst->st_ex_size == len) {
2005 result = 0;
2006 goto done;
2009 if (pst->st_ex_size > len) {
2010 /* the ftruncate should have worked */
2011 goto done;
2014 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
2015 goto done;
2018 result = 0;
2020 done:
2022 END_PROFILE(syscall_ftruncate);
2023 return result;
2026 static int vfswrap_fallocate(vfs_handle_struct *handle,
2027 files_struct *fsp,
2028 uint32_t mode,
2029 off_t offset,
2030 off_t len)
2032 int result;
2034 START_PROFILE(syscall_fallocate);
2035 if (mode == 0) {
2036 result = sys_posix_fallocate(fsp->fh->fd, offset, len);
2038 * posix_fallocate returns 0 on success, errno on error
2039 * and doesn't set errno. Make it behave like fallocate()
2040 * which returns -1, and sets errno on failure.
2042 if (result != 0) {
2043 errno = result;
2044 result = -1;
2046 } else {
2047 /* sys_fallocate handles filtering of unsupported mode flags */
2048 result = sys_fallocate(fsp->fh->fd, mode, offset, len);
2050 END_PROFILE(syscall_fallocate);
2051 return result;
2054 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
2056 bool result;
2058 START_PROFILE(syscall_fcntl_lock);
2059 result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
2060 END_PROFILE(syscall_fcntl_lock);
2061 return result;
2064 static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
2065 uint32_t share_mode, uint32_t access_mask)
2067 START_PROFILE(syscall_kernel_flock);
2068 kernel_flock(fsp->fh->fd, share_mode, access_mask);
2069 END_PROFILE(syscall_kernel_flock);
2070 return 0;
2073 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
2075 bool result;
2077 START_PROFILE(syscall_fcntl_getlock);
2078 result = fcntl_getlock(fsp->fh->fd, poffset, pcount, ptype, ppid);
2079 END_PROFILE(syscall_fcntl_getlock);
2080 return result;
2083 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
2084 int leasetype)
2086 int result = -1;
2088 START_PROFILE(syscall_linux_setlease);
2090 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
2091 result = linux_setlease(fsp->fh->fd, leasetype);
2092 #else
2093 errno = ENOSYS;
2094 #endif
2095 END_PROFILE(syscall_linux_setlease);
2096 return result;
2099 static int vfswrap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
2101 int result;
2103 START_PROFILE(syscall_symlink);
2104 result = symlink(oldpath, newpath);
2105 END_PROFILE(syscall_symlink);
2106 return result;
2109 static int vfswrap_readlink(vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
2111 int result;
2113 START_PROFILE(syscall_readlink);
2114 result = readlink(path, buf, bufsiz);
2115 END_PROFILE(syscall_readlink);
2116 return result;
2119 static int vfswrap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
2121 int result;
2123 START_PROFILE(syscall_link);
2124 result = link(oldpath, newpath);
2125 END_PROFILE(syscall_link);
2126 return result;
2129 static int vfswrap_mknod(vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
2131 int result;
2133 START_PROFILE(syscall_mknod);
2134 result = sys_mknod(pathname, mode, dev);
2135 END_PROFILE(syscall_mknod);
2136 return result;
2139 static char *vfswrap_realpath(vfs_handle_struct *handle, const char *path)
2141 char *result;
2143 START_PROFILE(syscall_realpath);
2144 #ifdef REALPATH_TAKES_NULL
2145 result = realpath(path, NULL);
2146 #else
2147 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
2148 if (result) {
2149 char *resolved_path = realpath(path, result);
2150 if (!resolved_path) {
2151 SAFE_FREE(result);
2152 } else {
2153 /* SMB_ASSERT(result == resolved_path) ? */
2154 result = resolved_path;
2157 #endif
2158 END_PROFILE(syscall_realpath);
2159 return result;
2162 static int vfswrap_chflags(vfs_handle_struct *handle, const char *path,
2163 unsigned int flags)
2165 #ifdef HAVE_CHFLAGS
2166 return chflags(path, flags);
2167 #else
2168 errno = ENOSYS;
2169 return -1;
2170 #endif
2173 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
2174 const SMB_STRUCT_STAT *sbuf)
2176 struct file_id key;
2178 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
2179 * blob */
2180 ZERO_STRUCT(key);
2182 key.devid = sbuf->st_ex_dev;
2183 key.inode = sbuf->st_ex_ino;
2184 /* key.extid is unused by default. */
2186 return key;
2189 static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
2190 struct files_struct *fsp,
2191 const char *fname,
2192 TALLOC_CTX *mem_ctx,
2193 unsigned int *pnum_streams,
2194 struct stream_struct **pstreams)
2196 SMB_STRUCT_STAT sbuf;
2197 struct stream_struct *tmp_streams = NULL;
2198 int ret;
2200 if ((fsp != NULL) && (fsp->is_directory)) {
2202 * No default streams on directories
2204 goto done;
2207 if ((fsp != NULL) && (fsp->fh->fd != -1)) {
2208 ret = SMB_VFS_FSTAT(fsp, &sbuf);
2210 else {
2211 struct smb_filename smb_fname;
2213 ZERO_STRUCT(smb_fname);
2214 smb_fname.base_name = discard_const_p(char, fname);
2216 if (lp_posix_pathnames()) {
2217 ret = SMB_VFS_LSTAT(handle->conn, &smb_fname);
2218 } else {
2219 ret = SMB_VFS_STAT(handle->conn, &smb_fname);
2221 sbuf = smb_fname.st;
2224 if (ret == -1) {
2225 return map_nt_error_from_unix(errno);
2228 if (S_ISDIR(sbuf.st_ex_mode)) {
2229 goto done;
2232 tmp_streams = talloc_realloc(mem_ctx, *pstreams, struct stream_struct,
2233 (*pnum_streams) + 1);
2234 if (tmp_streams == NULL) {
2235 return NT_STATUS_NO_MEMORY;
2237 tmp_streams[*pnum_streams].name = talloc_strdup(tmp_streams, "::$DATA");
2238 if (tmp_streams[*pnum_streams].name == NULL) {
2239 return NT_STATUS_NO_MEMORY;
2241 tmp_streams[*pnum_streams].size = sbuf.st_ex_size;
2242 tmp_streams[*pnum_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, &sbuf);
2244 *pnum_streams += 1;
2245 *pstreams = tmp_streams;
2246 done:
2247 return NT_STATUS_OK;
2250 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
2251 const char *path,
2252 const char *name,
2253 TALLOC_CTX *mem_ctx,
2254 char **found_name)
2257 * Don't fall back to get_real_filename so callers can differentiate
2258 * between a full directory scan and an actual case-insensitive stat.
2260 errno = EOPNOTSUPP;
2261 return -1;
2264 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
2265 const char *fname)
2267 return handle->conn->connectpath;
2270 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
2271 struct byte_range_lock *br_lck,
2272 struct lock_struct *plock,
2273 bool blocking_lock)
2275 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
2277 /* Note: blr is not used in the default implementation. */
2278 return brl_lock_windows_default(br_lck, plock, blocking_lock);
2281 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
2282 struct messaging_context *msg_ctx,
2283 struct byte_range_lock *br_lck,
2284 const struct lock_struct *plock)
2286 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
2288 return brl_unlock_windows_default(msg_ctx, br_lck, plock);
2291 static bool vfswrap_brl_cancel_windows(struct vfs_handle_struct *handle,
2292 struct byte_range_lock *br_lck,
2293 struct lock_struct *plock)
2295 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
2297 /* Note: blr is not used in the default implementation. */
2298 return brl_lock_cancel_default(br_lck, plock);
2301 static bool vfswrap_strict_lock(struct vfs_handle_struct *handle,
2302 files_struct *fsp,
2303 struct lock_struct *plock)
2305 SMB_ASSERT(plock->lock_type == READ_LOCK ||
2306 plock->lock_type == WRITE_LOCK);
2308 return strict_lock_default(fsp, plock);
2311 static void vfswrap_strict_unlock(struct vfs_handle_struct *handle,
2312 files_struct *fsp,
2313 struct lock_struct *plock)
2315 SMB_ASSERT(plock->lock_type == READ_LOCK ||
2316 plock->lock_type == WRITE_LOCK);
2318 strict_unlock_default(fsp, plock);
2321 /* NT ACL operations. */
2323 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
2324 files_struct *fsp,
2325 uint32_t security_info,
2326 TALLOC_CTX *mem_ctx,
2327 struct security_descriptor **ppdesc)
2329 NTSTATUS result;
2331 START_PROFILE(fget_nt_acl);
2332 result = posix_fget_nt_acl(fsp, security_info,
2333 mem_ctx, ppdesc);
2334 END_PROFILE(fget_nt_acl);
2335 return result;
2338 static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
2339 const char *name,
2340 uint32_t security_info,
2341 TALLOC_CTX *mem_ctx,
2342 struct security_descriptor **ppdesc)
2344 NTSTATUS result;
2346 START_PROFILE(get_nt_acl);
2347 result = posix_get_nt_acl(handle->conn, name, security_info,
2348 mem_ctx, ppdesc);
2349 END_PROFILE(get_nt_acl);
2350 return result;
2353 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
2355 NTSTATUS result;
2357 START_PROFILE(fset_nt_acl);
2358 result = set_nt_acl(fsp, security_info_sent, psd);
2359 END_PROFILE(fset_nt_acl);
2360 return result;
2363 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
2364 struct smb_filename *file,
2365 struct security_acl *sacl,
2366 uint32_t access_requested,
2367 uint32_t access_denied)
2369 return NT_STATUS_OK; /* Nothing to do here ... */
2372 static int vfswrap_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode)
2374 #ifdef HAVE_NO_ACL
2375 errno = ENOSYS;
2376 return -1;
2377 #else
2378 int result;
2380 START_PROFILE(chmod_acl);
2381 result = chmod_acl(handle->conn, name, mode);
2382 END_PROFILE(chmod_acl);
2383 return result;
2384 #endif
2387 static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2389 #ifdef HAVE_NO_ACL
2390 errno = ENOSYS;
2391 return -1;
2392 #else
2393 int result;
2395 START_PROFILE(fchmod_acl);
2396 result = fchmod_acl(fsp, mode);
2397 END_PROFILE(fchmod_acl);
2398 return result;
2399 #endif
2402 static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle,
2403 const char *path_p,
2404 SMB_ACL_TYPE_T type,
2405 TALLOC_CTX *mem_ctx)
2407 return sys_acl_get_file(handle, path_p, type, mem_ctx);
2410 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
2411 files_struct *fsp,
2412 TALLOC_CTX *mem_ctx)
2414 return sys_acl_get_fd(handle, fsp, mem_ctx);
2417 static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2419 return sys_acl_set_file(handle, name, acltype, theacl);
2422 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
2424 return sys_acl_set_fd(handle, fsp, theacl);
2427 static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
2429 return sys_acl_delete_def_file(handle, path);
2432 /****************************************************************
2433 Extended attribute operations.
2434 *****************************************************************/
2436 static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
2438 return getxattr(path, name, value, size);
2441 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
2443 return fgetxattr(fsp->fh->fd, name, value, size);
2446 static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
2448 return listxattr(path, list, size);
2451 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
2453 return flistxattr(fsp->fh->fd, list, size);
2456 static int vfswrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
2458 return removexattr(path, name);
2461 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
2463 return fremovexattr(fsp->fh->fd, name);
2466 static int vfswrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
2468 return setxattr(path, name, value, size, flags);
2471 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
2473 return fsetxattr(fsp->fh->fd, name, value, size, flags);
2476 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
2478 return false;
2481 static bool vfswrap_is_offline(struct vfs_handle_struct *handle,
2482 const struct smb_filename *fname,
2483 SMB_STRUCT_STAT *sbuf)
2485 NTSTATUS status;
2486 char *path;
2487 bool offline = false;
2489 if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
2490 return false;
2493 if (!lp_dmapi_support(SNUM(handle->conn)) || !dmapi_have_session()) {
2494 #if defined(ENOTSUP)
2495 errno = ENOTSUP;
2496 #endif
2497 return false;
2500 status = get_full_smb_filename(talloc_tos(), fname, &path);
2501 if (!NT_STATUS_IS_OK(status)) {
2502 errno = map_errno_from_nt_status(status);
2503 return false;
2506 offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
2508 TALLOC_FREE(path);
2510 return offline;
2513 static int vfswrap_set_offline(struct vfs_handle_struct *handle,
2514 const struct smb_filename *fname)
2516 /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
2517 #if defined(ENOTSUP)
2518 errno = ENOTSUP;
2519 #endif
2520 return -1;
2523 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
2524 struct files_struct *fsp,
2525 TALLOC_CTX *mem_ctx,
2526 DATA_BLOB *cookie)
2528 return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
2531 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
2532 struct files_struct *fsp,
2533 const DATA_BLOB old_cookie,
2534 TALLOC_CTX *mem_ctx,
2535 DATA_BLOB *new_cookie)
2537 return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
2538 new_cookie);
2541 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
2542 struct smb_request *smb1req,
2543 struct smbXsrv_open *op,
2544 const DATA_BLOB old_cookie,
2545 TALLOC_CTX *mem_ctx,
2546 struct files_struct **fsp,
2547 DATA_BLOB *new_cookie)
2549 return vfs_default_durable_reconnect(handle->conn, smb1req, op,
2550 old_cookie, mem_ctx,
2551 fsp, new_cookie);
2554 static struct vfs_fn_pointers vfs_default_fns = {
2555 /* Disk operations */
2557 .connect_fn = vfswrap_connect,
2558 .disconnect_fn = vfswrap_disconnect,
2559 .disk_free_fn = vfswrap_disk_free,
2560 .get_quota_fn = vfswrap_get_quota,
2561 .set_quota_fn = vfswrap_set_quota,
2562 .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
2563 .statvfs_fn = vfswrap_statvfs,
2564 .fs_capabilities_fn = vfswrap_fs_capabilities,
2565 .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
2566 .snap_check_path_fn = vfswrap_snap_check_path,
2567 .snap_create_fn = vfswrap_snap_create,
2568 .snap_delete_fn = vfswrap_snap_delete,
2570 /* Directory operations */
2572 .opendir_fn = vfswrap_opendir,
2573 .fdopendir_fn = vfswrap_fdopendir,
2574 .readdir_fn = vfswrap_readdir,
2575 .readdir_attr_fn = vfswrap_readdir_attr,
2576 .seekdir_fn = vfswrap_seekdir,
2577 .telldir_fn = vfswrap_telldir,
2578 .rewind_dir_fn = vfswrap_rewinddir,
2579 .mkdir_fn = vfswrap_mkdir,
2580 .rmdir_fn = vfswrap_rmdir,
2581 .closedir_fn = vfswrap_closedir,
2582 .init_search_op_fn = vfswrap_init_search_op,
2584 /* File operations */
2586 .open_fn = vfswrap_open,
2587 .create_file_fn = vfswrap_create_file,
2588 .close_fn = vfswrap_close,
2589 .read_fn = vfswrap_read,
2590 .pread_fn = vfswrap_pread,
2591 .pread_send_fn = vfswrap_pread_send,
2592 .pread_recv_fn = vfswrap_asys_ssize_t_recv,
2593 .write_fn = vfswrap_write,
2594 .pwrite_fn = vfswrap_pwrite,
2595 .pwrite_send_fn = vfswrap_pwrite_send,
2596 .pwrite_recv_fn = vfswrap_asys_ssize_t_recv,
2597 .lseek_fn = vfswrap_lseek,
2598 .sendfile_fn = vfswrap_sendfile,
2599 .recvfile_fn = vfswrap_recvfile,
2600 .rename_fn = vfswrap_rename,
2601 .fsync_fn = vfswrap_fsync,
2602 .fsync_send_fn = vfswrap_fsync_send,
2603 .fsync_recv_fn = vfswrap_asys_int_recv,
2604 .stat_fn = vfswrap_stat,
2605 .fstat_fn = vfswrap_fstat,
2606 .lstat_fn = vfswrap_lstat,
2607 .get_alloc_size_fn = vfswrap_get_alloc_size,
2608 .unlink_fn = vfswrap_unlink,
2609 .chmod_fn = vfswrap_chmod,
2610 .fchmod_fn = vfswrap_fchmod,
2611 .chown_fn = vfswrap_chown,
2612 .fchown_fn = vfswrap_fchown,
2613 .lchown_fn = vfswrap_lchown,
2614 .chdir_fn = vfswrap_chdir,
2615 .getwd_fn = vfswrap_getwd,
2616 .ntimes_fn = vfswrap_ntimes,
2617 .ftruncate_fn = vfswrap_ftruncate,
2618 .fallocate_fn = vfswrap_fallocate,
2619 .lock_fn = vfswrap_lock,
2620 .kernel_flock_fn = vfswrap_kernel_flock,
2621 .linux_setlease_fn = vfswrap_linux_setlease,
2622 .getlock_fn = vfswrap_getlock,
2623 .symlink_fn = vfswrap_symlink,
2624 .readlink_fn = vfswrap_readlink,
2625 .link_fn = vfswrap_link,
2626 .mknod_fn = vfswrap_mknod,
2627 .realpath_fn = vfswrap_realpath,
2628 .chflags_fn = vfswrap_chflags,
2629 .file_id_create_fn = vfswrap_file_id_create,
2630 .streaminfo_fn = vfswrap_streaminfo,
2631 .get_real_filename_fn = vfswrap_get_real_filename,
2632 .connectpath_fn = vfswrap_connectpath,
2633 .brl_lock_windows_fn = vfswrap_brl_lock_windows,
2634 .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
2635 .brl_cancel_windows_fn = vfswrap_brl_cancel_windows,
2636 .strict_lock_fn = vfswrap_strict_lock,
2637 .strict_unlock_fn = vfswrap_strict_unlock,
2638 .translate_name_fn = vfswrap_translate_name,
2639 .fsctl_fn = vfswrap_fsctl,
2640 .copy_chunk_send_fn = vfswrap_copy_chunk_send,
2641 .copy_chunk_recv_fn = vfswrap_copy_chunk_recv,
2642 .get_compression_fn = vfswrap_get_compression,
2643 .set_compression_fn = vfswrap_set_compression,
2645 /* NT ACL operations. */
2647 .fget_nt_acl_fn = vfswrap_fget_nt_acl,
2648 .get_nt_acl_fn = vfswrap_get_nt_acl,
2649 .fset_nt_acl_fn = vfswrap_fset_nt_acl,
2650 .audit_file_fn = vfswrap_audit_file,
2652 /* POSIX ACL operations. */
2654 .chmod_acl_fn = vfswrap_chmod_acl,
2655 .fchmod_acl_fn = vfswrap_fchmod_acl,
2657 .sys_acl_get_file_fn = vfswrap_sys_acl_get_file,
2658 .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
2659 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
2660 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2661 .sys_acl_set_file_fn = vfswrap_sys_acl_set_file,
2662 .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
2663 .sys_acl_delete_def_file_fn = vfswrap_sys_acl_delete_def_file,
2665 /* EA operations. */
2666 .getxattr_fn = vfswrap_getxattr,
2667 .fgetxattr_fn = vfswrap_fgetxattr,
2668 .listxattr_fn = vfswrap_listxattr,
2669 .flistxattr_fn = vfswrap_flistxattr,
2670 .removexattr_fn = vfswrap_removexattr,
2671 .fremovexattr_fn = vfswrap_fremovexattr,
2672 .setxattr_fn = vfswrap_setxattr,
2673 .fsetxattr_fn = vfswrap_fsetxattr,
2675 /* aio operations */
2676 .aio_force_fn = vfswrap_aio_force,
2678 /* offline operations */
2679 .is_offline_fn = vfswrap_is_offline,
2680 .set_offline_fn = vfswrap_set_offline,
2682 /* durable handle operations */
2683 .durable_cookie_fn = vfswrap_durable_cookie,
2684 .durable_disconnect_fn = vfswrap_durable_disconnect,
2685 .durable_reconnect_fn = vfswrap_durable_reconnect,
2688 NTSTATUS vfs_default_init(void);
2689 NTSTATUS vfs_default_init(void)
2691 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2692 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);