s3: VFS: default. Fix vfswrap_readdir() to use sys_fstatat().
[samba.git] / source3 / modules / vfs_default.c
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
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "ntioctl.h"
27 #include "smbprofile.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/lookup_sid.h"
30 #include "source3/include/msdfs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "lib/util/sys_rw.h"
35 #include "lib/pthreadpool/pthreadpool_tevent.h"
36 #include "librpc/gen_ndr/ndr_ioctl.h"
37 #include "offload_token.h"
38 #include "util_reparse.h"
39 #include "lib/util/string_wrappers.h"
40
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_VFS
43
44 /* Check for NULL pointer parameters in vfswrap_* functions */
45
46 /* We don't want to have NULL function pointers lying around.  Someone
47    is sure to try and execute them.  These stubs are used to prevent
48    this possibility. */
49
50 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
51 {
52         handle->conn->have_proc_fds = sys_have_proc_fds();
53         return 0;    /* Return >= 0 for success */
54 }
55
56 static void vfswrap_disconnect(vfs_handle_struct *handle)
57 {
58 }
59
60 /* Disk operations */
61
62 static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
63                                 const struct smb_filename *smb_fname,
64                                 uint64_t *bsize,
65                                 uint64_t *dfree,
66                                 uint64_t *dsize)
67 {
68         if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
69                 return (uint64_t)-1;
70         }
71
72         *bsize = 512;
73         return *dfree / 2;
74 }
75
76 static int vfswrap_get_quota(struct vfs_handle_struct *handle,
77                                 const struct smb_filename *smb_fname,
78                                 enum SMB_QUOTA_TYPE qtype,
79                                 unid_t id,
80                                 SMB_DISK_QUOTA *qt)
81 {
82 #ifdef HAVE_SYS_QUOTAS
83         int result;
84
85         START_PROFILE(syscall_get_quota);
86         result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
87         END_PROFILE(syscall_get_quota);
88         return result;
89 #else
90         errno = ENOSYS;
91         return -1;
92 #endif
93 }
94
95 static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
96 {
97 #ifdef HAVE_SYS_QUOTAS
98         int result;
99
100         START_PROFILE(syscall_set_quota);
101         result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
102         END_PROFILE(syscall_set_quota);
103         return result;
104 #else
105         errno = ENOSYS;
106         return -1;
107 #endif
108 }
109
110 static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
111                                         struct files_struct *fsp,
112                                         struct shadow_copy_data *shadow_copy_data,
113                                         bool labels)
114 {
115         errno = ENOSYS;
116         return -1;  /* Not implemented. */
117 }
118
119 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
120                                 const struct smb_filename *smb_fname,
121                                 vfs_statvfs_struct *statbuf)
122 {
123         return sys_statvfs(smb_fname->base_name, statbuf);
124 }
125
126 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
127                 enum timestamp_set_resolution *p_ts_res)
128 {
129         const struct loadparm_substitution *lp_sub =
130                 loadparm_s3_global_substitution();
131         connection_struct *conn = handle->conn;
132         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
133         struct smb_filename *smb_fname_cpath = NULL;
134         struct vfs_statvfs_struct statbuf;
135         int ret;
136
137         smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
138                                               conn->connectpath,
139                                               NULL,
140                                               NULL,
141                                               0,
142                                               0);
143         if (smb_fname_cpath == NULL) {
144                 return caps;
145         }
146
147         ZERO_STRUCT(statbuf);
148         ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
149         if (ret == 0) {
150                 caps = statbuf.FsCapabilities;
151         }
152
153         *p_ts_res = TIMESTAMP_SET_SECONDS;
154
155         /* Work out what timestamp resolution we can
156          * use when setting a timestamp. */
157
158         ret = SMB_VFS_STAT(conn, smb_fname_cpath);
159         if (ret == -1) {
160                 TALLOC_FREE(smb_fname_cpath);
161                 return caps;
162         }
163
164         if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
165                         smb_fname_cpath->st.st_ex_atime.tv_nsec ||
166                         smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
167                 /* If any of the normal UNIX directory timestamps
168                  * have a non-zero tv_nsec component assume
169                  * we might be able to set sub-second timestamps.
170                  * See what filetime set primitives we have.
171                  */
172 #if defined(HAVE_UTIMENSAT)
173                 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
174 #elif defined(HAVE_UTIMES)
175                 /* utimes allows msec timestamps to be set. */
176                 *p_ts_res = TIMESTAMP_SET_MSEC;
177 #elif defined(HAVE_UTIME)
178                 /* utime only allows sec timestamps to be set. */
179                 *p_ts_res = TIMESTAMP_SET_SECONDS;
180 #endif
181
182                 DEBUG(10,("vfswrap_fs_capabilities: timestamp "
183                         "resolution of %s "
184                         "available on share %s, directory %s\n",
185                         *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
186                         lp_servicename(talloc_tos(), lp_sub, conn->params->service),
187                         conn->connectpath ));
188         }
189         TALLOC_FREE(smb_fname_cpath);
190         return caps;
191 }
192
193 static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
194                                           struct dfs_GetDFSReferral *r)
195 {
196         struct junction_map *junction = NULL;
197         int consumedcnt = 0;
198         bool self_referral = false;
199         char *pathnamep = NULL;
200         char *local_dfs_path = NULL;
201         NTSTATUS status;
202         size_t i;
203         uint16_t max_referral_level = r->in.req.max_referral_level;
204
205         if (DEBUGLVL(10)) {
206                 NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
207         }
208
209         /* get the junction entry */
210         if (r->in.req.servername == NULL) {
211                 return NT_STATUS_NOT_FOUND;
212         }
213
214         /*
215          * Trim pathname sent by client so it begins with only one backslash.
216          * Two backslashes confuse some dfs clients
217          */
218
219         local_dfs_path = talloc_strdup(r, r->in.req.servername);
220         if (local_dfs_path == NULL) {
221                 return NT_STATUS_NO_MEMORY;
222         }
223         pathnamep = local_dfs_path;
224         while (IS_DIRECTORY_SEP(pathnamep[0]) &&
225                IS_DIRECTORY_SEP(pathnamep[1])) {
226                 pathnamep++;
227         }
228
229         junction = talloc_zero(r, struct junction_map);
230         if (junction == NULL) {
231                 return NT_STATUS_NO_MEMORY;
232         }
233
234         /* The following call can change cwd. */
235         status = get_referred_path(r,
236                                    handle->conn->session_info,
237                                    pathnamep,
238                                    handle->conn->sconn->remote_address,
239                                    handle->conn->sconn->local_address,
240                                    !handle->conn->sconn->using_smb2,
241                                    junction, &consumedcnt, &self_referral);
242         if (!NT_STATUS_IS_OK(status)) {
243                 struct smb_filename connectpath_fname = {
244                         .base_name = handle->conn->connectpath
245                 };
246                 vfs_ChDir(handle->conn, &connectpath_fname);
247                 return status;
248         }
249         {
250                 struct smb_filename connectpath_fname = {
251                         .base_name = handle->conn->connectpath
252                 };
253                 vfs_ChDir(handle->conn, &connectpath_fname);
254         }
255
256         if (!self_referral) {
257                 pathnamep[consumedcnt] = '\0';
258
259                 if (DEBUGLVL(3)) {
260                         dbgtext("Path %s to alternate path(s):",
261                                 pathnamep);
262                         for (i=0; i < junction->referral_count; i++) {
263                                 dbgtext(" %s",
264                                 junction->referral_list[i].alternate_path);
265                         }
266                         dbgtext(".\n");
267                 }
268         }
269
270         if (r->in.req.max_referral_level <= 2) {
271                 max_referral_level = 2;
272         }
273         if (r->in.req.max_referral_level >= 3) {
274                 max_referral_level = 3;
275         }
276
277         r->out.resp = talloc_zero(r, struct dfs_referral_resp);
278         if (r->out.resp == NULL) {
279                 return NT_STATUS_NO_MEMORY;
280         }
281
282         r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
283         r->out.resp->nb_referrals = junction->referral_count;
284
285         r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
286         if (self_referral) {
287                 r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
288         }
289
290         r->out.resp->referral_entries = talloc_zero_array(r,
291                                 struct dfs_referral_type,
292                                 r->out.resp->nb_referrals);
293         if (r->out.resp->referral_entries == NULL) {
294                 return NT_STATUS_NO_MEMORY;
295         }
296
297         switch (max_referral_level) {
298         case 2:
299                 for(i=0; i < junction->referral_count; i++) {
300                         struct referral *ref = &junction->referral_list[i];
301                         TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
302                         struct dfs_referral_type *t =
303                                 &r->out.resp->referral_entries[i];
304                         struct dfs_referral_v2 *v2 = &t->referral.v2;
305
306                         t->version = 2;
307                         v2->size = VERSION2_REFERRAL_SIZE;
308                         if (self_referral) {
309                                 v2->server_type = DFS_SERVER_ROOT;
310                         } else {
311                                 v2->server_type = DFS_SERVER_NON_ROOT;
312                         }
313                         v2->entry_flags = 0;
314                         v2->proximity = ref->proximity;
315                         v2->ttl = ref->ttl;
316                         v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
317                         if (v2->DFS_path == NULL) {
318                                 return NT_STATUS_NO_MEMORY;
319                         }
320                         v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
321                         if (v2->DFS_alt_path == NULL) {
322                                 return NT_STATUS_NO_MEMORY;
323                         }
324                         v2->netw_address = talloc_strdup(mem_ctx,
325                                                          ref->alternate_path);
326                         if (v2->netw_address == NULL) {
327                                 return NT_STATUS_NO_MEMORY;
328                         }
329                 }
330
331                 break;
332         case 3:
333                 for(i=0; i < junction->referral_count; i++) {
334                         struct referral *ref = &junction->referral_list[i];
335                         TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
336                         struct dfs_referral_type *t =
337                                 &r->out.resp->referral_entries[i];
338                         struct dfs_referral_v3 *v3 = &t->referral.v3;
339                         struct dfs_normal_referral *r1 = &v3->referrals.r1;
340
341                         t->version = 3;
342                         v3->size = VERSION3_REFERRAL_SIZE;
343                         if (self_referral) {
344                                 v3->server_type = DFS_SERVER_ROOT;
345                         } else {
346                                 v3->server_type = DFS_SERVER_NON_ROOT;
347                         }
348                         v3->entry_flags = 0;
349                         v3->ttl = ref->ttl;
350                         r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
351                         if (r1->DFS_path == NULL) {
352                                 return NT_STATUS_NO_MEMORY;
353                         }
354                         r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
355                         if (r1->DFS_alt_path == NULL) {
356                                 return NT_STATUS_NO_MEMORY;
357                         }
358                         r1->netw_address = talloc_strdup(mem_ctx,
359                                                          ref->alternate_path);
360                         if (r1->netw_address == NULL) {
361                                 return NT_STATUS_NO_MEMORY;
362                         }
363                 }
364                 break;
365         default:
366                 DEBUG(0,("Invalid dfs referral version: %d\n",
367                         max_referral_level));
368                 return NT_STATUS_INVALID_LEVEL;
369         }
370
371         if (DEBUGLVL(10)) {
372                 NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
373         }
374
375         return NT_STATUS_OK;
376 }
377
378 static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
379                                 struct files_struct *dirfsp,
380                                 const struct smb_filename *smb_fname,
381                                 const struct referral *reflist,
382                                 size_t referral_count)
383 {
384         TALLOC_CTX *frame = talloc_stackframe();
385         NTSTATUS status = NT_STATUS_NO_MEMORY;
386         int ret;
387         char *msdfs_link = NULL;
388
389         /* Form the msdfs_link contents */
390         msdfs_link = msdfs_link_string(frame,
391                                         reflist,
392                                         referral_count);
393         if (msdfs_link == NULL) {
394                 goto out;
395         }
396
397         ret = symlinkat(msdfs_link,
398                         fsp_get_pathref_fd(dirfsp),
399                         smb_fname->base_name);
400         if (ret == 0) {
401                 status = NT_STATUS_OK;
402         } else {
403                 status = map_nt_error_from_unix(errno);
404         }
405
406   out:
407
408         TALLOC_FREE(frame);
409         return status;
410 }
411
412 /*
413  * Read and return the contents of a DFS redirect given a
414  * pathname. A caller can pass in NULL for ppreflist and
415  * preferral_count but still determine if this was a
416  * DFS redirect point by getting NT_STATUS_OK back
417  * without incurring the overhead of reading and parsing
418  * the referral contents.
419  */
420
421 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
422                                 TALLOC_CTX *mem_ctx,
423                                 struct files_struct *dirfsp,
424                                 struct smb_filename *smb_fname,
425                                 struct referral **ppreflist,
426                                 size_t *preferral_count)
427 {
428         NTSTATUS status = NT_STATUS_NO_MEMORY;
429         size_t bufsize;
430         char *link_target = NULL;
431         int referral_len;
432         bool ok;
433 #if defined(HAVE_BROKEN_READLINK)
434         char link_target_buf[PATH_MAX];
435 #else
436         char link_target_buf[7];
437 #endif
438         int ret;
439
440         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
441
442         if (is_named_stream(smb_fname)) {
443                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
444                 goto err;
445         }
446
447         if (ppreflist == NULL && preferral_count == NULL) {
448                 /*
449                  * We're only checking if this is a DFS
450                  * redirect. We don't need to return data.
451                  */
452                 bufsize = sizeof(link_target_buf);
453                 link_target = link_target_buf;
454         } else {
455                 bufsize = PATH_MAX;
456                 link_target = talloc_array(mem_ctx, char, bufsize);
457                 if (!link_target) {
458                         goto err;
459                 }
460         }
461
462         referral_len = readlinkat(fsp_get_io_fd(dirfsp),
463                                 smb_fname->base_name,
464                                 link_target,
465                                 bufsize - 1);
466         if (referral_len == -1) {
467                 if (errno == EINVAL) {
468                         /*
469                          * If the path isn't a link, readlinkat
470                          * returns EINVAL. Allow the caller to
471                          * detect this.
472                          */
473                         DBG_INFO("%s is not a link.\n", smb_fname->base_name);
474                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
475                 } else {
476                         status = map_nt_error_from_unix(errno);
477                         if (errno == ENOENT) {
478                                 DBG_NOTICE("Error reading "
479                                          "msdfs link %s: %s\n",
480                                          smb_fname->base_name,
481                                          strerror(errno));
482                         } else {
483                                 DBG_ERR("Error reading "
484                                         "msdfs link %s: %s\n",
485                                         smb_fname->base_name,
486                                         strerror(errno));
487                         }
488                 }
489                 goto err;
490         }
491         link_target[referral_len] = '\0';
492
493         DBG_INFO("%s -> %s\n",
494                         smb_fname->base_name,
495                         link_target);
496
497         if (!strnequal(link_target, "msdfs:", 6)) {
498                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
499                 goto err;
500         }
501
502         ret = sys_lstat(smb_fname->base_name,
503                         &smb_fname->st,
504                         lp_fake_directory_create_times(SNUM(handle->conn)));
505         if (ret < 0) {
506                 status = map_nt_error_from_unix(errno);
507                 goto err;
508         }
509
510         if (ppreflist == NULL && preferral_count == NULL) {
511                 /* Early return for checking if this is a DFS link. */
512                 return NT_STATUS_OK;
513         }
514
515         ok = parse_msdfs_symlink(mem_ctx,
516                         lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
517                         link_target,
518                         ppreflist,
519                         preferral_count);
520
521         if (ok) {
522                 status = NT_STATUS_OK;
523         } else {
524                 status = NT_STATUS_NO_MEMORY;
525         }
526
527   err:
528
529         if (link_target != link_target_buf) {
530                 TALLOC_FREE(link_target);
531         }
532         return status;
533 }
534
535 static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
536                                         TALLOC_CTX *mem_ctx,
537                                         const char *service_path,
538                                         char **base_volume)
539 {
540         return NT_STATUS_NOT_SUPPORTED;
541 }
542
543 static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
544                                     TALLOC_CTX *mem_ctx,
545                                     const char *base_volume,
546                                     time_t *tstamp,
547                                     bool rw,
548                                     char **base_path,
549                                     char **snap_path)
550 {
551         return NT_STATUS_NOT_SUPPORTED;
552 }
553
554 static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
555                                     TALLOC_CTX *mem_ctx,
556                                     char *base_path,
557                                     char *snap_path)
558 {
559         return NT_STATUS_NOT_SUPPORTED;
560 }
561
562 /* Directory operations */
563
564 static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
565                         files_struct *fsp,
566                         const char *mask,
567                         uint32_t attr)
568 {
569         DIR *result;
570
571         START_PROFILE(syscall_fdopendir);
572         result = sys_fdopendir(fsp_get_io_fd(fsp));
573         END_PROFILE(syscall_fdopendir);
574         return result;
575 }
576
577
578 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
579                                       struct files_struct *dirfsp,
580                                       DIR *dirp,
581                                       SMB_STRUCT_STAT *sbuf)
582 {
583         struct dirent *result;
584         bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
585         int flags = AT_SYMLINK_NOFOLLOW;
586         SMB_STRUCT_STAT st;
587         int ret;
588
589         START_PROFILE(syscall_readdir);
590
591         result = readdir(dirp);
592         END_PROFILE(syscall_readdir);
593
594         if (sbuf == NULL) {
595                 return result;
596         }
597         if (result == NULL) {
598                 return NULL;
599         }
600
601         /*
602          * Default Posix readdir() does not give us stat info.
603          * Set to invalid to indicate we didn't return this info.
604          */
605         SET_STAT_INVALID(*sbuf);
606
607         ret = sys_fstatat(dirfd(dirp),
608                       result->d_name,
609                       &st,
610                       flags,
611                       fake_ctime);
612         if (ret != 0) {
613                 return result;
614         }
615
616         /*
617          * As this is an optimization, ignore it if we stat'ed a
618          * symlink for non-POSIX context. Make the caller do it again
619          * as we don't know if they wanted the link info, or its
620          * target info.
621          */
622         if (S_ISLNK(st.st_ex_mode) &&
623             !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
624         {
625                 return result;
626         }
627         *sbuf = st;
628
629         return result;
630 }
631
632 static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
633                                       struct files_struct *fsp,
634                                       TALLOC_CTX *mem_ctx,
635                                       struct readdir_attr_data **attr_data)
636 {
637         return NT_STATUS_NOT_SUPPORTED;
638 }
639
640 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
641 {
642         START_PROFILE(syscall_seekdir);
643         seekdir(dirp, offset);
644         END_PROFILE(syscall_seekdir);
645 }
646
647 static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
648 {
649         long result;
650         START_PROFILE(syscall_telldir);
651         result = telldir(dirp);
652         END_PROFILE(syscall_telldir);
653         return result;
654 }
655
656 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
657 {
658         START_PROFILE(syscall_rewinddir);
659         rewinddir(dirp);
660         END_PROFILE(syscall_rewinddir);
661 }
662
663 static int vfswrap_mkdirat(vfs_handle_struct *handle,
664                         struct files_struct *dirfsp,
665                         const struct smb_filename *smb_fname,
666                         mode_t mode)
667 {
668         int result;
669
670         START_PROFILE(syscall_mkdirat);
671
672         result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
673
674         END_PROFILE(syscall_mkdirat);
675         return result;
676 }
677
678 static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
679 {
680         int result;
681
682         START_PROFILE(syscall_closedir);
683         result = closedir(dirp);
684         END_PROFILE(syscall_closedir);
685         return result;
686 }
687
688 /* File operations */
689
690 static int vfswrap_openat(vfs_handle_struct *handle,
691                           const struct files_struct *dirfsp,
692                           const struct smb_filename *smb_fname,
693                           files_struct *fsp,
694                           int flags,
695                           mode_t mode)
696 {
697         bool have_opath = false;
698         bool became_root = false;
699         int result;
700
701         START_PROFILE(syscall_openat);
702
703         if (is_named_stream(smb_fname)) {
704                 errno = ENOENT;
705                 result = -1;
706                 goto out;
707         }
708
709 #ifdef O_PATH
710         have_opath = true;
711         if (fsp->fsp_flags.is_pathref) {
712                 flags |= O_PATH;
713         }
714 #endif
715
716         if (fsp->fsp_flags.is_pathref && !have_opath) {
717                 become_root();
718                 became_root = true;
719         }
720
721         result = openat(fsp_get_pathref_fd(dirfsp),
722                         smb_fname->base_name,
723                         flags,
724                         mode);
725
726         if (became_root) {
727                 unbecome_root();
728         }
729
730         fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
731
732 out:
733         END_PROFILE(syscall_openat);
734         return result;
735 }
736 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
737                                     struct smb_request *req,
738                                     struct smb_filename *smb_fname,
739                                     uint32_t access_mask,
740                                     uint32_t share_access,
741                                     uint32_t create_disposition,
742                                     uint32_t create_options,
743                                     uint32_t file_attributes,
744                                     uint32_t oplock_request,
745                                     const struct smb2_lease *lease,
746                                     uint64_t allocation_size,
747                                     uint32_t private_flags,
748                                     struct security_descriptor *sd,
749                                     struct ea_list *ea_list,
750                                     files_struct **result,
751                                     int *pinfo,
752                                     const struct smb2_create_blobs *in_context_blobs,
753                                     struct smb2_create_blobs *out_context_blobs)
754 {
755         return create_file_default(handle->conn, req, smb_fname,
756                                    access_mask, share_access,
757                                    create_disposition, create_options,
758                                    file_attributes, oplock_request, lease,
759                                    allocation_size, private_flags,
760                                    sd, ea_list, result,
761                                    pinfo, in_context_blobs, out_context_blobs);
762 }
763
764 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
765 {
766         int result;
767
768         START_PROFILE(syscall_close);
769         result = fd_close_posix(fsp);
770         END_PROFILE(syscall_close);
771         return result;
772 }
773
774 static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
775                         size_t n, off_t offset)
776 {
777         ssize_t result;
778
779 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
780         START_PROFILE_BYTES(syscall_pread, n);
781         result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
782         END_PROFILE_BYTES(syscall_pread);
783
784         if (result == -1 && errno == ESPIPE) {
785                 /* Maintain the fiction that pipes can be seeked (sought?) on. */
786                 result = sys_read(fsp_get_io_fd(fsp), data, n);
787                 fh_set_pos(fsp->fh, 0);
788         }
789
790 #else /* HAVE_PREAD */
791         errno = ENOSYS;
792         result = -1;
793 #endif /* HAVE_PREAD */
794
795         return result;
796 }
797
798 static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
799                         size_t n, off_t offset)
800 {
801         ssize_t result;
802
803 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
804         START_PROFILE_BYTES(syscall_pwrite, n);
805         result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
806         END_PROFILE_BYTES(syscall_pwrite);
807
808         if (result == -1 && errno == ESPIPE) {
809                 /* Maintain the fiction that pipes can be sought on. */
810                 result = sys_write(fsp_get_io_fd(fsp), data, n);
811         }
812
813 #else /* HAVE_PWRITE */
814         errno = ENOSYS;
815         result = -1;
816 #endif /* HAVE_PWRITE */
817
818         return result;
819 }
820
821 struct vfswrap_pread_state {
822         ssize_t ret;
823         int fd;
824         void *buf;
825         size_t count;
826         off_t offset;
827
828         struct vfs_aio_state vfs_aio_state;
829         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
830 };
831
832 static void vfs_pread_do(void *private_data);
833 static void vfs_pread_done(struct tevent_req *subreq);
834 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
835
836 static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
837                                              TALLOC_CTX *mem_ctx,
838                                              struct tevent_context *ev,
839                                              struct files_struct *fsp,
840                                              void *data,
841                                              size_t n, off_t offset)
842 {
843         struct tevent_req *req, *subreq;
844         struct vfswrap_pread_state *state;
845
846         req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
847         if (req == NULL) {
848                 return NULL;
849         }
850
851         state->ret = -1;
852         state->fd = fsp_get_io_fd(fsp);
853         state->buf = data;
854         state->count = n;
855         state->offset = offset;
856
857         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
858                                      state->profile_bytes, n);
859         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
860
861         subreq = pthreadpool_tevent_job_send(
862                 state, ev, handle->conn->sconn->pool,
863                 vfs_pread_do, state);
864         if (tevent_req_nomem(subreq, req)) {
865                 return tevent_req_post(req, ev);
866         }
867         tevent_req_set_callback(subreq, vfs_pread_done, req);
868
869         talloc_set_destructor(state, vfs_pread_state_destructor);
870
871         return req;
872 }
873
874 static void vfs_pread_do(void *private_data)
875 {
876         struct vfswrap_pread_state *state = talloc_get_type_abort(
877                 private_data, struct vfswrap_pread_state);
878         struct timespec start_time;
879         struct timespec end_time;
880
881         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
882
883         PROFILE_TIMESTAMP(&start_time);
884
885         state->ret = sys_pread_full(state->fd,
886                                     state->buf,
887                                     state->count,
888                                     state->offset);
889
890         if (state->ret == -1) {
891                 state->vfs_aio_state.error = errno;
892         }
893
894         PROFILE_TIMESTAMP(&end_time);
895
896         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
897
898         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
899 }
900
901 static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
902 {
903         return -1;
904 }
905
906 static void vfs_pread_done(struct tevent_req *subreq)
907 {
908         struct tevent_req *req = tevent_req_callback_data(
909                 subreq, struct tevent_req);
910         struct vfswrap_pread_state *state = tevent_req_data(
911                 req, struct vfswrap_pread_state);
912         int ret;
913
914         ret = pthreadpool_tevent_job_recv(subreq);
915         TALLOC_FREE(subreq);
916         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
917         talloc_set_destructor(state, NULL);
918         if (ret != 0) {
919                 if (ret != EAGAIN) {
920                         tevent_req_error(req, ret);
921                         return;
922                 }
923                 /*
924                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
925                  * means the lower level pthreadpool failed to create a new
926                  * thread. Fallback to sync processing in that case to allow
927                  * some progress for the client.
928                  */
929                 vfs_pread_do(state);
930         }
931
932         tevent_req_done(req);
933 }
934
935 static ssize_t vfswrap_pread_recv(struct tevent_req *req,
936                                   struct vfs_aio_state *vfs_aio_state)
937 {
938         struct vfswrap_pread_state *state = tevent_req_data(
939                 req, struct vfswrap_pread_state);
940
941         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
942                 return -1;
943         }
944
945         *vfs_aio_state = state->vfs_aio_state;
946         return state->ret;
947 }
948
949 struct vfswrap_pwrite_state {
950         ssize_t ret;
951         int fd;
952         const void *buf;
953         size_t count;
954         off_t offset;
955
956         struct vfs_aio_state vfs_aio_state;
957         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
958 };
959
960 static void vfs_pwrite_do(void *private_data);
961 static void vfs_pwrite_done(struct tevent_req *subreq);
962 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
963
964 static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
965                                               TALLOC_CTX *mem_ctx,
966                                               struct tevent_context *ev,
967                                               struct files_struct *fsp,
968                                               const void *data,
969                                               size_t n, off_t offset)
970 {
971         struct tevent_req *req, *subreq;
972         struct vfswrap_pwrite_state *state;
973
974         req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
975         if (req == NULL) {
976                 return NULL;
977         }
978
979         state->ret = -1;
980         state->fd = fsp_get_io_fd(fsp);
981         state->buf = data;
982         state->count = n;
983         state->offset = offset;
984
985         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
986                                      state->profile_bytes, n);
987         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
988
989         subreq = pthreadpool_tevent_job_send(
990                 state, ev, handle->conn->sconn->pool,
991                 vfs_pwrite_do, state);
992         if (tevent_req_nomem(subreq, req)) {
993                 return tevent_req_post(req, ev);
994         }
995         tevent_req_set_callback(subreq, vfs_pwrite_done, req);
996
997         talloc_set_destructor(state, vfs_pwrite_state_destructor);
998
999         return req;
1000 }
1001
1002 static void vfs_pwrite_do(void *private_data)
1003 {
1004         struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1005                 private_data, struct vfswrap_pwrite_state);
1006         struct timespec start_time;
1007         struct timespec end_time;
1008
1009         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1010
1011         PROFILE_TIMESTAMP(&start_time);
1012
1013         state->ret = sys_pwrite_full(state->fd,
1014                                      state->buf,
1015                                      state->count,
1016                                      state->offset);
1017
1018         if (state->ret == -1) {
1019                 state->vfs_aio_state.error = errno;
1020         }
1021
1022         PROFILE_TIMESTAMP(&end_time);
1023
1024         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1025
1026         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1027 }
1028
1029 static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1030 {
1031         return -1;
1032 }
1033
1034 static void vfs_pwrite_done(struct tevent_req *subreq)
1035 {
1036         struct tevent_req *req = tevent_req_callback_data(
1037                 subreq, struct tevent_req);
1038         struct vfswrap_pwrite_state *state = tevent_req_data(
1039                 req, struct vfswrap_pwrite_state);
1040         int ret;
1041
1042         ret = pthreadpool_tevent_job_recv(subreq);
1043         TALLOC_FREE(subreq);
1044         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1045         talloc_set_destructor(state, NULL);
1046         if (ret != 0) {
1047                 if (ret != EAGAIN) {
1048                         tevent_req_error(req, ret);
1049                         return;
1050                 }
1051                 /*
1052                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1053                  * means the lower level pthreadpool failed to create a new
1054                  * thread. Fallback to sync processing in that case to allow
1055                  * some progress for the client.
1056                  */
1057                 vfs_pwrite_do(state);
1058         }
1059
1060         tevent_req_done(req);
1061 }
1062
1063 static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1064                                    struct vfs_aio_state *vfs_aio_state)
1065 {
1066         struct vfswrap_pwrite_state *state = tevent_req_data(
1067                 req, struct vfswrap_pwrite_state);
1068
1069         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1070                 return -1;
1071         }
1072
1073         *vfs_aio_state = state->vfs_aio_state;
1074         return state->ret;
1075 }
1076
1077 struct vfswrap_fsync_state {
1078         ssize_t ret;
1079         int fd;
1080
1081         struct vfs_aio_state vfs_aio_state;
1082         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1083 };
1084
1085 static void vfs_fsync_do(void *private_data);
1086 static void vfs_fsync_done(struct tevent_req *subreq);
1087 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1088
1089 static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1090                                              TALLOC_CTX *mem_ctx,
1091                                              struct tevent_context *ev,
1092                                              struct files_struct *fsp)
1093 {
1094         struct tevent_req *req, *subreq;
1095         struct vfswrap_fsync_state *state;
1096
1097         req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1098         if (req == NULL) {
1099                 return NULL;
1100         }
1101
1102         state->ret = -1;
1103         state->fd = fsp_get_io_fd(fsp);
1104
1105         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1106                                      state->profile_bytes, 0);
1107         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1108
1109         subreq = pthreadpool_tevent_job_send(
1110                 state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1111         if (tevent_req_nomem(subreq, req)) {
1112                 return tevent_req_post(req, ev);
1113         }
1114         tevent_req_set_callback(subreq, vfs_fsync_done, req);
1115
1116         talloc_set_destructor(state, vfs_fsync_state_destructor);
1117
1118         return req;
1119 }
1120
1121 static void vfs_fsync_do(void *private_data)
1122 {
1123         struct vfswrap_fsync_state *state = talloc_get_type_abort(
1124                 private_data, struct vfswrap_fsync_state);
1125         struct timespec start_time;
1126         struct timespec end_time;
1127
1128         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1129
1130         PROFILE_TIMESTAMP(&start_time);
1131
1132         do {
1133                 state->ret = fsync(state->fd);
1134         } while ((state->ret == -1) && (errno == EINTR));
1135
1136         if (state->ret == -1) {
1137                 state->vfs_aio_state.error = errno;
1138         }
1139
1140         PROFILE_TIMESTAMP(&end_time);
1141
1142         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1143
1144         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1145 }
1146
1147 static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1148 {
1149         return -1;
1150 }
1151
1152 static void vfs_fsync_done(struct tevent_req *subreq)
1153 {
1154         struct tevent_req *req = tevent_req_callback_data(
1155                 subreq, struct tevent_req);
1156         struct vfswrap_fsync_state *state = tevent_req_data(
1157                 req, struct vfswrap_fsync_state);
1158         int ret;
1159
1160         ret = pthreadpool_tevent_job_recv(subreq);
1161         TALLOC_FREE(subreq);
1162         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1163         talloc_set_destructor(state, NULL);
1164         if (ret != 0) {
1165                 if (ret != EAGAIN) {
1166                         tevent_req_error(req, ret);
1167                         return;
1168                 }
1169                 /*
1170                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1171                  * means the lower level pthreadpool failed to create a new
1172                  * thread. Fallback to sync processing in that case to allow
1173                  * some progress for the client.
1174                  */
1175                 vfs_fsync_do(state);
1176         }
1177
1178         tevent_req_done(req);
1179 }
1180
1181 static int vfswrap_fsync_recv(struct tevent_req *req,
1182                               struct vfs_aio_state *vfs_aio_state)
1183 {
1184         struct vfswrap_fsync_state *state = tevent_req_data(
1185                 req, struct vfswrap_fsync_state);
1186
1187         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1188                 return -1;
1189         }
1190
1191         *vfs_aio_state = state->vfs_aio_state;
1192         return state->ret;
1193 }
1194
1195 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1196 {
1197         off_t result = 0;
1198
1199         START_PROFILE(syscall_lseek);
1200
1201         result = lseek(fsp_get_io_fd(fsp), offset, whence);
1202         /*
1203          * We want to maintain the fiction that we can seek
1204          * on a fifo for file system purposes. This allows
1205          * people to set up UNIX fifo's that feed data to Windows
1206          * applications. JRA.
1207          */
1208
1209         if((result == -1) && (errno == ESPIPE)) {
1210                 result = 0;
1211                 errno = 0;
1212         }
1213
1214         END_PROFILE(syscall_lseek);
1215         return result;
1216 }
1217
1218 static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1219                         off_t offset, size_t n)
1220 {
1221         ssize_t result;
1222
1223         START_PROFILE_BYTES(syscall_sendfile, n);
1224         result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1225         END_PROFILE_BYTES(syscall_sendfile);
1226         return result;
1227 }
1228
1229 static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1230                         int fromfd,
1231                         files_struct *tofsp,
1232                         off_t offset,
1233                         size_t n)
1234 {
1235         ssize_t result;
1236
1237         START_PROFILE_BYTES(syscall_recvfile, n);
1238         result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1239         END_PROFILE_BYTES(syscall_recvfile);
1240         return result;
1241 }
1242
1243 static int vfswrap_renameat(vfs_handle_struct *handle,
1244                           files_struct *srcfsp,
1245                           const struct smb_filename *smb_fname_src,
1246                           files_struct *dstfsp,
1247                           const struct smb_filename *smb_fname_dst)
1248 {
1249         int result = -1;
1250
1251         START_PROFILE(syscall_renameat);
1252
1253         if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) {
1254                 errno = ENOENT;
1255                 goto out;
1256         }
1257
1258         result = renameat(fsp_get_pathref_fd(srcfsp),
1259                         smb_fname_src->base_name,
1260                         fsp_get_pathref_fd(dstfsp),
1261                         smb_fname_dst->base_name);
1262
1263  out:
1264         END_PROFILE(syscall_renameat);
1265         return result;
1266 }
1267
1268 static int vfswrap_stat(vfs_handle_struct *handle,
1269                         struct smb_filename *smb_fname)
1270 {
1271         int result = -1;
1272
1273         START_PROFILE(syscall_stat);
1274
1275         if (is_named_stream(smb_fname)) {
1276                 errno = ENOENT;
1277                 goto out;
1278         }
1279
1280         result = sys_stat(smb_fname->base_name, &smb_fname->st,
1281                           lp_fake_directory_create_times(SNUM(handle->conn)));
1282  out:
1283         END_PROFILE(syscall_stat);
1284         return result;
1285 }
1286
1287 static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1288 {
1289         int result;
1290
1291         START_PROFILE(syscall_fstat);
1292         result = sys_fstat(fsp_get_pathref_fd(fsp),
1293                            sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1294         END_PROFILE(syscall_fstat);
1295         return result;
1296 }
1297
1298 static int vfswrap_lstat(vfs_handle_struct *handle,
1299                          struct smb_filename *smb_fname)
1300 {
1301         int result = -1;
1302
1303         START_PROFILE(syscall_lstat);
1304
1305         if (is_named_stream(smb_fname)) {
1306                 errno = ENOENT;
1307                 goto out;
1308         }
1309
1310         result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1311                            lp_fake_directory_create_times(SNUM(handle->conn)));
1312  out:
1313         END_PROFILE(syscall_lstat);
1314         return result;
1315 }
1316
1317 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1318                                        const char *name,
1319                                        enum vfs_translate_direction direction,
1320                                        TALLOC_CTX *mem_ctx,
1321                                        char **mapped_name)
1322 {
1323         return NT_STATUS_NONE_MAPPED;
1324 }
1325
1326 /**
1327  * Return allocated parent directory and basename of path
1328  *
1329  * Note: if requesting name, it is returned as talloc child of the
1330  * parent. Freeing the parent is thus sufficient to free both.
1331  */
1332 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1333                                         TALLOC_CTX *mem_ctx,
1334                                         const struct smb_filename *smb_fname_in,
1335                                         struct smb_filename **parent_dir_out,
1336                                         struct smb_filename **atname_out)
1337 {
1338         TALLOC_CTX *frame = talloc_stackframe();
1339         struct smb_filename *parent = NULL;
1340         struct smb_filename *name = NULL;
1341         char *p = NULL;
1342
1343         parent = cp_smb_filename(frame, smb_fname_in);
1344         if (parent == NULL) {
1345                 TALLOC_FREE(frame);
1346                 return NT_STATUS_NO_MEMORY;
1347         }
1348         TALLOC_FREE(parent->stream_name);
1349         SET_STAT_INVALID(parent->st);
1350
1351         p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1352         if (p == NULL) {
1353                 TALLOC_FREE(parent->base_name);
1354                 parent->base_name = talloc_strdup(parent, ".");
1355                 if (parent->base_name == NULL) {
1356                         TALLOC_FREE(frame);
1357                         return NT_STATUS_NO_MEMORY;
1358                 }
1359                 p = smb_fname_in->base_name;
1360         } else {
1361                 *p = '\0';
1362                 p++;
1363         }
1364
1365         if (atname_out == NULL) {
1366                 *parent_dir_out = talloc_move(mem_ctx, &parent);
1367                 TALLOC_FREE(frame);
1368                 return NT_STATUS_OK;
1369         }
1370
1371         name = cp_smb_filename(frame, smb_fname_in);
1372         if (name == NULL) {
1373                 TALLOC_FREE(frame);
1374                 return NT_STATUS_NO_MEMORY;
1375         }
1376         TALLOC_FREE(name->base_name);
1377
1378         name->base_name = talloc_strdup(name, p);
1379         if (name->base_name == NULL) {
1380                 TALLOC_FREE(frame);
1381                 return NT_STATUS_NO_MEMORY;
1382         }
1383
1384         *parent_dir_out = talloc_move(mem_ctx, &parent);
1385         *atname_out = talloc_move(*parent_dir_out, &name);
1386         TALLOC_FREE(frame);
1387         return NT_STATUS_OK;
1388 }
1389
1390 /*
1391  * Implement the default fsctl operation.
1392  */
1393 static bool vfswrap_logged_ioctl_message = false;
1394
1395 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1396                               struct files_struct *fsp,
1397                               TALLOC_CTX *ctx,
1398                               uint32_t function,
1399                               uint16_t req_flags, /* Needed for UNICODE ... */
1400                               const uint8_t *_in_data,
1401                               uint32_t in_len,
1402                               uint8_t **_out_data,
1403                               uint32_t max_out_len,
1404                               uint32_t *out_len)
1405 {
1406         const char *in_data = (const char *)_in_data;
1407         char **out_data = (char **)_out_data;
1408         NTSTATUS status;
1409
1410         switch (function) {
1411         case FSCTL_SET_SPARSE:
1412         {
1413                 bool set_sparse = true;
1414
1415                 if (in_len >= 1 && in_data[0] == 0) {
1416                         set_sparse = false;
1417                 }
1418
1419                 status = file_set_sparse(handle->conn, fsp, set_sparse);
1420
1421                 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1422                       ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1423                        smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1424                        nt_errstr(status)));
1425
1426                 return status;
1427         }
1428
1429         case FSCTL_CREATE_OR_GET_OBJECT_ID:
1430         {
1431                 unsigned char objid[16];
1432                 char *return_data = NULL;
1433
1434                 /* This should return the object-id on this file.
1435                  * I think I'll make this be the inode+dev. JRA.
1436                  */
1437
1438                 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1439                           fsp_fnum_dbg(fsp)));
1440
1441                 *out_len = MIN(max_out_len, 64);
1442
1443                 /* Hmmm, will this cause problems if less data asked for? */
1444                 return_data = talloc_array(ctx, char, 64);
1445                 if (return_data == NULL) {
1446                         return NT_STATUS_NO_MEMORY;
1447                 }
1448
1449                 /* For backwards compatibility only store the dev/inode. */
1450                 push_file_id_16(return_data, &fsp->file_id);
1451                 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1452                 push_file_id_16(return_data+32, &fsp->file_id);
1453                 memset(return_data+48, 0, 16);
1454                 *out_data = return_data;
1455                 return NT_STATUS_OK;
1456         }
1457
1458         case FSCTL_GET_REPARSE_POINT:
1459         {
1460                 status = fsctl_get_reparse_point(
1461                         fsp, ctx, out_data, max_out_len, out_len);
1462                 return status;
1463         }
1464
1465         case FSCTL_SET_REPARSE_POINT:
1466         {
1467                 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1468                 return status;
1469         }
1470
1471         case FSCTL_DELETE_REPARSE_POINT:
1472         {
1473                 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1474                 return status;
1475         }
1476
1477         case FSCTL_GET_SHADOW_COPY_DATA:
1478         {
1479                 /*
1480                  * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1481                  * and return their volume names.  If max_data_count is 16, then it is just
1482                  * asking for the number of volumes and length of the combined names.
1483                  *
1484                  * pdata is the data allocated by our caller, but that uses
1485                  * total_data_count (which is 0 in our case) rather than max_data_count.
1486                  * Allocate the correct amount and return the pointer to let
1487                  * it be deallocated when we return.
1488                  */
1489                 struct shadow_copy_data *shadow_data = NULL;
1490                 bool labels = False;
1491                 uint32_t labels_data_count = 0;
1492                 uint32_t i;
1493                 char *cur_pdata = NULL;
1494
1495                 if (max_out_len < 16) {
1496                         DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1497                                 max_out_len));
1498                         return NT_STATUS_INVALID_PARAMETER;
1499                 }
1500
1501                 if (max_out_len > 16) {
1502                         labels = True;
1503                 }
1504
1505                 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1506                 if (shadow_data == NULL) {
1507                         DEBUG(0,("TALLOC_ZERO() failed!\n"));
1508                         return NT_STATUS_NO_MEMORY;
1509                 }
1510
1511                 /*
1512                  * Call the VFS routine to actually do the work.
1513                  */
1514                 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1515                         int log_lev = 0;
1516                         if (errno == 0) {
1517                                 /* broken module didn't set errno on error */
1518                                 status = NT_STATUS_UNSUCCESSFUL;
1519                         } else {
1520                                 status = map_nt_error_from_unix(errno);
1521                                 if (NT_STATUS_EQUAL(status,
1522                                                     NT_STATUS_NOT_SUPPORTED)) {
1523                                         log_lev = 5;
1524                                 }
1525                         }
1526                         DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1527                                         "connectpath %s, failed - %s.\n",
1528                                         fsp->conn->connectpath,
1529                                         nt_errstr(status)));
1530                         TALLOC_FREE(shadow_data);
1531                         return status;
1532                 }
1533
1534                 labels_data_count = (shadow_data->num_volumes * 2 *
1535                                         sizeof(SHADOW_COPY_LABEL)) + 2;
1536
1537                 if (!labels) {
1538                         *out_len = 16;
1539                 } else {
1540                         *out_len = 12 + labels_data_count;
1541                 }
1542
1543                 if (max_out_len < *out_len) {
1544                         DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1545                                 max_out_len, *out_len));
1546                         TALLOC_FREE(shadow_data);
1547                         return NT_STATUS_BUFFER_TOO_SMALL;
1548                 }
1549
1550                 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1551                 if (cur_pdata == NULL) {
1552                         TALLOC_FREE(shadow_data);
1553                         return NT_STATUS_NO_MEMORY;
1554                 }
1555
1556                 *out_data = cur_pdata;
1557
1558                 /* num_volumes 4 bytes */
1559                 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1560
1561                 if (labels) {
1562                         /* num_labels 4 bytes */
1563                         SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1564                 }
1565
1566                 /* needed_data_count 4 bytes */
1567                 SIVAL(cur_pdata, 8, labels_data_count);
1568
1569                 cur_pdata += 12;
1570
1571                 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1572                           shadow_data->num_volumes, fsp_str_dbg(fsp)));
1573                 if (labels && shadow_data->labels) {
1574                         for (i=0; i<shadow_data->num_volumes; i++) {
1575                                 size_t len = 0;
1576                                 status = srvstr_push(cur_pdata, req_flags,
1577                                             cur_pdata, shadow_data->labels[i],
1578                                             2 * sizeof(SHADOW_COPY_LABEL),
1579                                             STR_UNICODE|STR_TERMINATE, &len);
1580                                 if (!NT_STATUS_IS_OK(status)) {
1581                                         TALLOC_FREE(*out_data);
1582                                         TALLOC_FREE(shadow_data);
1583                                         return status;
1584                                 }
1585                                 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1586                                 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1587                         }
1588                 }
1589
1590                 TALLOC_FREE(shadow_data);
1591
1592                 return NT_STATUS_OK;
1593         }
1594
1595         case FSCTL_FIND_FILES_BY_SID:
1596         {
1597                 /* pretend this succeeded -
1598                  *
1599                  * we have to send back a list with all files owned by this SID
1600                  *
1601                  * but I have to check that --metze
1602                  */
1603                 ssize_t ret;
1604                 struct dom_sid sid;
1605                 struct dom_sid_buf buf;
1606                 uid_t uid;
1607                 size_t sid_len;
1608
1609                 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1610                            fsp_fnum_dbg(fsp)));
1611
1612                 if (in_len < 8) {
1613                         /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1614                         return NT_STATUS_INVALID_PARAMETER;
1615                 }
1616
1617                 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1618
1619                 /* unknown 4 bytes: this is not the length of the sid :-(  */
1620                 /*unknown = IVAL(pdata,0);*/
1621
1622                 ret = sid_parse(_in_data + 4, sid_len, &sid);
1623                 if (ret == -1) {
1624                         return NT_STATUS_INVALID_PARAMETER;
1625                 }
1626                 DEBUGADD(10, ("for SID: %s\n",
1627                               dom_sid_str_buf(&sid, &buf)));
1628
1629                 if (!sid_to_uid(&sid, &uid)) {
1630                         DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1631                                  dom_sid_str_buf(&sid, &buf),
1632                                  (unsigned long)sid_len));
1633                         uid = (-1);
1634                 }
1635
1636                 /* we can take a look at the find source :-)
1637                  *
1638                  * find ./ -uid $uid  -name '*'   is what we need here
1639                  *
1640                  *
1641                  * and send 4bytes len and then NULL terminated unicode strings
1642                  * for each file
1643                  *
1644                  * but I don't know how to deal with the paged results
1645                  * (maybe we can hang the result anywhere in the fsp struct)
1646                  *
1647                  * but I don't know how to deal with the paged results
1648                  * (maybe we can hang the result anywhere in the fsp struct)
1649                  *
1650                  * we don't send all files at once
1651                  * and at the next we should *not* start from the beginning,
1652                  * so we have to cache the result
1653                  *
1654                  * --metze
1655                  */
1656
1657                 /* this works for now... */
1658                 return NT_STATUS_OK;
1659         }
1660
1661         case FSCTL_QUERY_ALLOCATED_RANGES:
1662         {
1663                 /* FIXME: This is just a dummy reply, telling that all of the
1664                  * file is allocated. MKS cp needs that.
1665                  * Adding the real allocated ranges via FIEMAP on Linux
1666                  * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1667                  * this FSCTL correct for sparse files.
1668                  */
1669                 uint64_t offset, length;
1670                 char *out_data_tmp = NULL;
1671
1672                 if (in_len != 16) {
1673                         DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1674                                 in_len));
1675                         return NT_STATUS_INVALID_PARAMETER;
1676                 }
1677
1678                 if (max_out_len < 16) {
1679                         DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1680                                 max_out_len));
1681                         return NT_STATUS_INVALID_PARAMETER;
1682                 }
1683
1684                 offset = BVAL(in_data,0);
1685                 length = BVAL(in_data,8);
1686
1687                 if (offset + length < offset) {
1688                         /* No 64-bit integer wrap. */
1689                         return NT_STATUS_INVALID_PARAMETER;
1690                 }
1691
1692                 /* Shouldn't this be SMB_VFS_STAT ... ? */
1693                 status = vfs_stat_fsp(fsp);
1694                 if (!NT_STATUS_IS_OK(status)) {
1695                         return status;
1696                 }
1697
1698                 *out_len = 16;
1699                 out_data_tmp = talloc_array(ctx, char, *out_len);
1700                 if (out_data_tmp == NULL) {
1701                         DEBUG(10, ("unable to allocate memory for response\n"));
1702                         return NT_STATUS_NO_MEMORY;
1703                 }
1704
1705                 if (offset > fsp->fsp_name->st.st_ex_size ||
1706                                 fsp->fsp_name->st.st_ex_size == 0 ||
1707                                 length == 0) {
1708                         memset(out_data_tmp, 0, *out_len);
1709                 } else {
1710                         uint64_t end = offset + length;
1711                         end = MIN(end, fsp->fsp_name->st.st_ex_size);
1712                         SBVAL(out_data_tmp, 0, 0);
1713                         SBVAL(out_data_tmp, 8, end);
1714                 }
1715
1716                 *out_data = out_data_tmp;
1717
1718                 return NT_STATUS_OK;
1719         }
1720
1721         case FSCTL_IS_VOLUME_DIRTY:
1722         {
1723                 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1724                           "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1725                 /*
1726                  * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1727                  * says we have to respond with NT_STATUS_INVALID_PARAMETER
1728                  */
1729                 return NT_STATUS_INVALID_PARAMETER;
1730         }
1731
1732         default:
1733                 /*
1734                  * Only print once ... unfortunately there could be lots of
1735                  * different FSCTLs that are called.
1736                  */
1737                 if (!vfswrap_logged_ioctl_message) {
1738                         vfswrap_logged_ioctl_message = true;
1739                         DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1740                         __func__, function));
1741                 }
1742         }
1743
1744         return NT_STATUS_NOT_SUPPORTED;
1745 }
1746
1747 static bool vfswrap_is_offline(struct connection_struct *conn,
1748                                const struct smb_filename *fname);
1749
1750 struct vfswrap_get_dos_attributes_state {
1751         struct vfs_aio_state aio_state;
1752         connection_struct *conn;
1753         TALLOC_CTX *mem_ctx;
1754         struct tevent_context *ev;
1755         files_struct *dir_fsp;
1756         struct smb_filename *smb_fname;
1757         uint32_t dosmode;
1758         bool as_root;
1759 };
1760
1761 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1762
1763 static struct tevent_req *vfswrap_get_dos_attributes_send(
1764                         TALLOC_CTX *mem_ctx,
1765                         struct tevent_context *ev,
1766                         struct vfs_handle_struct *handle,
1767                         files_struct *dir_fsp,
1768                         struct smb_filename *smb_fname)
1769 {
1770         struct tevent_req *req = NULL;
1771         struct tevent_req *subreq = NULL;
1772         struct vfswrap_get_dos_attributes_state *state = NULL;
1773
1774         req = tevent_req_create(mem_ctx, &state,
1775                                 struct vfswrap_get_dos_attributes_state);
1776         if (req == NULL) {
1777                 return NULL;
1778         }
1779
1780         *state = (struct vfswrap_get_dos_attributes_state) {
1781                 .conn = dir_fsp->conn,
1782                 .mem_ctx = mem_ctx,
1783                 .ev = ev,
1784                 .dir_fsp = dir_fsp,
1785                 .smb_fname = smb_fname,
1786         };
1787
1788         subreq = SMB_VFS_GETXATTRAT_SEND(state,
1789                                          ev,
1790                                          dir_fsp,
1791                                          smb_fname,
1792                                          SAMBA_XATTR_DOS_ATTRIB,
1793                                          sizeof(fstring));
1794         if (tevent_req_nomem(subreq, req)) {
1795                 return tevent_req_post(req, ev);
1796         }
1797         tevent_req_set_callback(subreq,
1798                                 vfswrap_get_dos_attributes_getxattr_done,
1799                                 req);
1800
1801         return req;
1802 }
1803
1804 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1805 {
1806         struct tevent_req *req =
1807                 tevent_req_callback_data(subreq,
1808                 struct tevent_req);
1809         struct vfswrap_get_dos_attributes_state *state =
1810                 tevent_req_data(req,
1811                 struct vfswrap_get_dos_attributes_state);
1812         ssize_t xattr_size;
1813         DATA_BLOB blob = {0};
1814         char *path = NULL;
1815         char *tofree = NULL;
1816         char pathbuf[PATH_MAX+1];
1817         ssize_t pathlen;
1818         struct smb_filename smb_fname;
1819         bool offline;
1820         NTSTATUS status;
1821
1822         xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1823                                              &state->aio_state,
1824                                              state,
1825                                              &blob.data);
1826         TALLOC_FREE(subreq);
1827         if (xattr_size == -1) {
1828                 status = map_nt_error_from_unix(state->aio_state.error);
1829
1830                 if (state->as_root) {
1831                         tevent_req_nterror(req, status);
1832                         return;
1833                 }
1834                 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1835                         tevent_req_nterror(req, status);
1836                         return;
1837                 }
1838
1839                 state->as_root = true;
1840
1841                 become_root();
1842                 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1843                                                  state->ev,
1844                                                  state->dir_fsp,
1845                                                  state->smb_fname,
1846                                                  SAMBA_XATTR_DOS_ATTRIB,
1847                                                  sizeof(fstring));
1848                 unbecome_root();
1849                 if (tevent_req_nomem(subreq, req)) {
1850                         return;
1851                 }
1852                 tevent_req_set_callback(subreq,
1853                                         vfswrap_get_dos_attributes_getxattr_done,
1854                                         req);
1855                 return;
1856         }
1857
1858         blob.length = xattr_size;
1859
1860         status = parse_dos_attribute_blob(state->smb_fname,
1861                                           blob,
1862                                           &state->dosmode);
1863         if (!NT_STATUS_IS_OK(status)) {
1864                 tevent_req_nterror(req, status);
1865                 return;
1866         }
1867
1868         pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1869                                 state->smb_fname->base_name,
1870                                 pathbuf,
1871                                 sizeof(pathbuf),
1872                                 &path,
1873                                 &tofree);
1874         if (pathlen == -1) {
1875                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1876                 return;
1877         }
1878
1879         smb_fname = (struct smb_filename) {
1880                 .base_name = path,
1881                 .st = state->smb_fname->st,
1882                 .flags = state->smb_fname->flags,
1883                 .twrp = state->smb_fname->twrp,
1884         };
1885
1886         offline = vfswrap_is_offline(state->conn, &smb_fname);
1887         if (offline) {
1888                 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1889         }
1890         TALLOC_FREE(tofree);
1891
1892         tevent_req_done(req);
1893         return;
1894 }
1895
1896 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1897                                                 struct vfs_aio_state *aio_state,
1898                                                 uint32_t *dosmode)
1899 {
1900         struct vfswrap_get_dos_attributes_state *state =
1901                 tevent_req_data(req,
1902                 struct vfswrap_get_dos_attributes_state);
1903         NTSTATUS status;
1904
1905         if (tevent_req_is_nterror(req, &status)) {
1906                 tevent_req_received(req);
1907                 return status;
1908         }
1909
1910         *aio_state = state->aio_state;
1911         *dosmode = state->dosmode;
1912         tevent_req_received(req);
1913         return NT_STATUS_OK;
1914 }
1915
1916 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1917                                             struct files_struct *fsp,
1918                                             uint32_t *dosmode)
1919 {
1920         bool offline;
1921
1922         offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1923         if (offline) {
1924                 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1925         }
1926
1927         return fget_ea_dos_attribute(fsp, dosmode);
1928 }
1929
1930 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1931                                             struct files_struct *fsp,
1932                                             uint32_t dosmode)
1933 {
1934         return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1935 }
1936
1937 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1938
1939 struct vfswrap_offload_read_state {
1940         DATA_BLOB token;
1941 };
1942
1943 static struct tevent_req *vfswrap_offload_read_send(
1944         TALLOC_CTX *mem_ctx,
1945         struct tevent_context *ev,
1946         struct vfs_handle_struct *handle,
1947         struct files_struct *fsp,
1948         uint32_t fsctl,
1949         uint32_t ttl,
1950         off_t offset,
1951         size_t to_copy)
1952 {
1953         struct tevent_req *req = NULL;
1954         struct vfswrap_offload_read_state *state = NULL;
1955         NTSTATUS status;
1956
1957         req = tevent_req_create(mem_ctx, &state,
1958                                 struct vfswrap_offload_read_state);
1959         if (req == NULL) {
1960                 return NULL;
1961         }
1962
1963         status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
1964                                             &vfswrap_offload_ctx);
1965         if (tevent_req_nterror(req, status)) {
1966                 return tevent_req_post(req, ev);
1967         }
1968
1969         if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
1970                 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
1971                 return tevent_req_post(req, ev);
1972         }
1973
1974         status = vfs_offload_token_create_blob(state, fsp, fsctl,
1975                                                &state->token);
1976         if (tevent_req_nterror(req, status)) {
1977                 return tevent_req_post(req, ev);
1978         }
1979
1980         status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
1981                                                 &state->token);
1982         if (tevent_req_nterror(req, status)) {
1983                 return tevent_req_post(req, ev);
1984         }
1985
1986         tevent_req_done(req);
1987         return tevent_req_post(req, ev);
1988 }
1989
1990 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
1991                                           struct vfs_handle_struct *handle,
1992                                           TALLOC_CTX *mem_ctx,
1993                                           DATA_BLOB *token)
1994 {
1995         struct vfswrap_offload_read_state *state = tevent_req_data(
1996                 req, struct vfswrap_offload_read_state);
1997         NTSTATUS status;
1998
1999         if (tevent_req_is_nterror(req, &status)) {
2000                 tevent_req_received(req);
2001                 return status;
2002         }
2003
2004         token->length = state->token.length;
2005         token->data = talloc_move(mem_ctx, &state->token.data);
2006
2007         tevent_req_received(req);
2008         return NT_STATUS_OK;
2009 }
2010
2011 struct vfswrap_offload_write_state {
2012         uint8_t *buf;
2013         bool read_lck_locked;
2014         bool write_lck_locked;
2015         DATA_BLOB *token;
2016         struct tevent_context *src_ev;
2017         struct files_struct *src_fsp;
2018         off_t src_off;
2019         struct tevent_context *dst_ev;
2020         struct files_struct *dst_fsp;
2021         off_t dst_off;
2022         off_t to_copy;
2023         off_t remaining;
2024         off_t copied;
2025         size_t next_io_size;
2026 };
2027
2028 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2029                                           enum tevent_req_state req_state)
2030 {
2031         struct vfswrap_offload_write_state *state = tevent_req_data(
2032                 req, struct vfswrap_offload_write_state);
2033         bool ok;
2034
2035         if (state->dst_fsp == NULL) {
2036                 return;
2037         }
2038
2039         ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2040         SMB_ASSERT(ok);
2041         state->dst_fsp = NULL;
2042 }
2043
2044 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2045 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2046
2047 static struct tevent_req *vfswrap_offload_write_send(
2048         struct vfs_handle_struct *handle,
2049         TALLOC_CTX *mem_ctx,
2050         struct tevent_context *ev,
2051         uint32_t fsctl,
2052         DATA_BLOB *token,
2053         off_t transfer_offset,
2054         struct files_struct *dest_fsp,
2055         off_t dest_off,
2056         off_t to_copy)
2057 {
2058         struct tevent_req *req;
2059         struct vfswrap_offload_write_state *state = NULL;
2060         /* off_t is signed! */
2061         off_t max_offset = INT64_MAX - to_copy;
2062         size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2063         files_struct *src_fsp = NULL;
2064         NTSTATUS status;
2065         bool ok;
2066
2067         req = tevent_req_create(mem_ctx, &state,
2068                                 struct vfswrap_offload_write_state);
2069         if (req == NULL) {
2070                 return NULL;
2071         }
2072
2073         *state = (struct vfswrap_offload_write_state) {
2074                 .token = token,
2075                 .src_off = transfer_offset,
2076                 .dst_ev = ev,
2077                 .dst_fsp = dest_fsp,
2078                 .dst_off = dest_off,
2079                 .to_copy = to_copy,
2080                 .remaining = to_copy,
2081         };
2082
2083         tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2084
2085         switch (fsctl) {
2086         case FSCTL_SRV_COPYCHUNK:
2087         case FSCTL_SRV_COPYCHUNK_WRITE:
2088                 break;
2089
2090         case FSCTL_OFFLOAD_WRITE:
2091                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2092                 return tevent_req_post(req, ev);
2093
2094         case FSCTL_DUP_EXTENTS_TO_FILE:
2095                 DBG_DEBUG("COW clones not supported by vfs_default\n");
2096                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2097                 return tevent_req_post(req, ev);
2098
2099         default:
2100                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2101                 return tevent_req_post(req, ev);
2102         }
2103
2104         /*
2105          * From here on we assume a copy-chunk fsctl
2106          */
2107
2108         if (to_copy == 0) {
2109                 tevent_req_done(req);
2110                 return tevent_req_post(req, ev);
2111         }
2112
2113         if (state->src_off > max_offset) {
2114                 /*
2115                  * Protect integer checks below.
2116                  */
2117                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2118                 return tevent_req_post(req, ev);
2119         }
2120         if (state->src_off < 0) {
2121                 /*
2122                  * Protect integer checks below.
2123                  */
2124                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2125                 return tevent_req_post(req, ev);
2126         }
2127         if (state->dst_off > max_offset) {
2128                 /*
2129                  * Protect integer checks below.
2130                  */
2131                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2132                 return tevent_req_post(req, ev);
2133         }
2134         if (state->dst_off < 0) {
2135                 /*
2136                  * Protect integer checks below.
2137                  */
2138                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2139                 return tevent_req_post(req, ev);
2140         }
2141
2142         status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2143                                                 token, &src_fsp);
2144         if (tevent_req_nterror(req, status)) {
2145                 return tevent_req_post(req, ev);
2146         }
2147
2148         DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2149
2150         status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2151         if (!NT_STATUS_IS_OK(status)) {
2152                 tevent_req_nterror(req, status);
2153                 return tevent_req_post(req, ev);
2154         }
2155
2156         ok = change_to_user_and_service_by_fsp(src_fsp);
2157         if (!ok) {
2158                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2159                 return tevent_req_post(req, ev);
2160         }
2161
2162         state->src_ev = src_fsp->conn->sconn->ev_ctx;
2163         state->src_fsp = src_fsp;
2164
2165         status = vfs_stat_fsp(src_fsp);
2166         if (tevent_req_nterror(req, status)) {
2167                 return tevent_req_post(req, ev);
2168         }
2169
2170         if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2171                 /*
2172                  * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2173                  *   If the SourceOffset or SourceOffset + Length extends beyond
2174                  *   the end of file, the server SHOULD<240> treat this as a
2175                  *   STATUS_END_OF_FILE error.
2176                  * ...
2177                  *   <240> Section 3.3.5.15.6: Windows servers will return
2178                  *   STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2179                  */
2180                 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2181                 return tevent_req_post(req, ev);
2182         }
2183
2184         status = vfswrap_offload_copy_file_range(req);
2185         if (NT_STATUS_IS_OK(status)) {
2186                 tevent_req_done(req);
2187                 return tevent_req_post(req, ev);
2188         }
2189         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2190                 tevent_req_nterror(req, status);
2191                 return tevent_req_post(req, ev);
2192         }
2193
2194         state->buf = talloc_array(state, uint8_t, num);
2195         if (tevent_req_nomem(state->buf, req)) {
2196                 return tevent_req_post(req, ev);
2197         }
2198
2199         status = vfswrap_offload_write_loop(req);
2200         if (!NT_STATUS_IS_OK(status)) {
2201                 tevent_req_nterror(req, status);
2202                 return tevent_req_post(req, ev);
2203         }
2204
2205         return req;
2206 }
2207
2208 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2209 {
2210         struct vfswrap_offload_write_state *state = tevent_req_data(
2211                 req, struct vfswrap_offload_write_state);
2212         struct lock_struct lck;
2213         ssize_t nwritten;
2214         NTSTATUS status;
2215         bool same_file;
2216         bool ok;
2217
2218 #ifndef USE_COPY_FILE_RANGE
2219         return NT_STATUS_MORE_PROCESSING_REQUIRED;
2220 #endif
2221
2222         same_file = file_id_equal(&state->src_fsp->file_id,
2223                                   &state->dst_fsp->file_id);
2224         if (same_file &&
2225             sys_io_ranges_overlap(state->remaining,
2226                                   state->src_off,
2227                                   state->remaining,
2228                                   state->dst_off))
2229         {
2230                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2231         }
2232
2233         if (is_named_stream(state->src_fsp->fsp_name) ||
2234             is_named_stream(state->dst_fsp->fsp_name))
2235         {
2236                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2237         }
2238
2239         init_strict_lock_struct(state->src_fsp,
2240                                 state->src_fsp->op->global->open_persistent_id,
2241                                 state->src_off,
2242                                 state->remaining,
2243                                 READ_LOCK,
2244                                 &lck);
2245
2246         ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2247                                  state->src_fsp,
2248                                  &lck);
2249         if (!ok) {
2250                 return NT_STATUS_FILE_LOCK_CONFLICT;
2251         }
2252
2253         ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2254         if (!ok) {
2255                 return NT_STATUS_INTERNAL_ERROR;
2256         }
2257
2258         init_strict_lock_struct(state->dst_fsp,
2259                                 state->dst_fsp->op->global->open_persistent_id,
2260                                 state->dst_off,
2261                                 state->remaining,
2262                                 WRITE_LOCK,
2263                                 &lck);
2264
2265         ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2266                                        state->dst_fsp,
2267                                        &lck);
2268         if (!ok) {
2269                 return NT_STATUS_FILE_LOCK_CONFLICT;
2270         }
2271
2272         while (state->remaining > 0) {
2273                 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2274                                            &state->src_off,
2275                                            fsp_get_io_fd(state->dst_fsp),
2276                                            &state->dst_off,
2277                                            state->remaining,
2278                                            0);
2279                 if (nwritten == -1) {
2280                         DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2281                                   "n [%jd] failed: %s\n",
2282                                   fsp_str_dbg(state->src_fsp),
2283                                   (intmax_t)state->src_off,
2284                                   fsp_str_dbg(state->dst_fsp),
2285                                   (intmax_t)state->dst_off,
2286                                   (intmax_t)state->remaining,
2287                                   strerror(errno));
2288                         switch (errno) {
2289                         case EXDEV:
2290                                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2291                                 break;
2292                         default:
2293                                 status = map_nt_error_from_unix(errno);
2294                                 if (NT_STATUS_EQUAL(
2295                                             status,
2296                                             NT_STATUS_MORE_PROCESSING_REQUIRED))
2297                                 {
2298                                         /* Avoid triggering the fallback */
2299                                         status = NT_STATUS_INTERNAL_ERROR;
2300                                 }
2301                                 break;
2302                         }
2303                         return status;
2304                 }
2305
2306                 if (state->remaining < nwritten) {
2307                         DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2308                                   "n [%jd] remaining [%jd]\n",
2309                                   fsp_str_dbg(state->src_fsp),
2310                                   fsp_str_dbg(state->dst_fsp),
2311                                   (intmax_t)nwritten,
2312                                   (intmax_t)state->remaining);
2313                         return NT_STATUS_INTERNAL_ERROR;
2314                 }
2315
2316                 if (nwritten == 0) {
2317                         break;
2318                 }
2319                 state->copied += nwritten;
2320                 state->remaining -= nwritten;
2321         }
2322
2323         /*
2324          * Tell the req cleanup function there's no need to call
2325          * change_to_user_and_service_by_fsp() on the dst handle.
2326          */
2327         state->dst_fsp = NULL;
2328         return NT_STATUS_OK;
2329 }
2330
2331 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2332
2333 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2334 {
2335         struct vfswrap_offload_write_state *state = tevent_req_data(
2336                 req, struct vfswrap_offload_write_state);
2337         struct tevent_req *subreq = NULL;
2338         struct lock_struct read_lck;
2339         bool ok;
2340
2341         /*
2342          * This is called under the context of state->src_fsp.
2343          */
2344
2345         state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2346
2347         init_strict_lock_struct(state->src_fsp,
2348                                 state->src_fsp->op->global->open_persistent_id,
2349                                 state->src_off,
2350                                 state->next_io_size,
2351                                 READ_LOCK,
2352                                 &read_lck);
2353
2354         ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2355                                  state->src_fsp,
2356                                  &read_lck);
2357         if (!ok) {
2358                 return NT_STATUS_FILE_LOCK_CONFLICT;
2359         }
2360
2361         subreq = SMB_VFS_PREAD_SEND(state,
2362                                     state->src_ev,
2363                                     state->src_fsp,
2364                                     state->buf,
2365                                     state->next_io_size,
2366                                     state->src_off);
2367         if (subreq == NULL) {
2368                 return NT_STATUS_NO_MEMORY;
2369         }
2370         tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2371
2372         return NT_STATUS_OK;
2373 }
2374
2375 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2376
2377 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2378 {
2379         struct tevent_req *req = tevent_req_callback_data(
2380                 subreq, struct tevent_req);
2381         struct vfswrap_offload_write_state *state = tevent_req_data(
2382                 req, struct vfswrap_offload_write_state);
2383         struct vfs_aio_state aio_state;
2384         struct lock_struct write_lck;
2385         ssize_t nread;
2386         bool ok;
2387
2388         nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2389         TALLOC_FREE(subreq);
2390         if (nread == -1) {
2391                 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2392                 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2393                 return;
2394         }
2395         if (nread != state->next_io_size) {
2396                 DBG_ERR("Short read, only %zd of %zu\n",
2397                         nread, state->next_io_size);
2398                 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2399                 return;
2400         }
2401
2402         state->src_off += nread;
2403
2404         ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2405         if (!ok) {
2406                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2407                 return;
2408         }
2409
2410         init_strict_lock_struct(state->dst_fsp,
2411                                 state->dst_fsp->op->global->open_persistent_id,
2412                                 state->dst_off,
2413                                 state->next_io_size,
2414                                 WRITE_LOCK,
2415                                 &write_lck);
2416
2417         ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2418                                  state->dst_fsp,
2419                                  &write_lck);
2420         if (!ok) {
2421                 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2422                 return;
2423         }
2424
2425         subreq = SMB_VFS_PWRITE_SEND(state,
2426                                      state->dst_ev,
2427                                      state->dst_fsp,
2428                                      state->buf,
2429                                      state->next_io_size,
2430                                      state->dst_off);
2431         if (subreq == NULL) {
2432                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2433                 return;
2434         }
2435         tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2436 }
2437
2438 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2439 {
2440         struct tevent_req *req = tevent_req_callback_data(
2441                 subreq, struct tevent_req);
2442         struct vfswrap_offload_write_state *state = tevent_req_data(
2443                 req, struct vfswrap_offload_write_state);
2444         struct vfs_aio_state aio_state;
2445         ssize_t nwritten;
2446         NTSTATUS status;
2447         bool ok;
2448
2449         nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2450         TALLOC_FREE(subreq);
2451         if (nwritten == -1) {
2452                 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2453                 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2454                 return;
2455         }
2456         if (nwritten != state->next_io_size) {
2457                 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2458                 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2459                 return;
2460         }
2461
2462         state->dst_off += nwritten;
2463
2464         if (state->remaining < nwritten) {
2465                 /* Paranoia check */
2466                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2467                 return;
2468         }
2469         state->copied += nwritten;
2470         state->remaining -= nwritten;
2471         if (state->remaining == 0) {
2472                 tevent_req_done(req);
2473                 return;
2474         }
2475
2476         ok = change_to_user_and_service_by_fsp(state->src_fsp);
2477         if (!ok) {
2478                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2479                 return;
2480         }
2481
2482         status = vfswrap_offload_write_loop(req);
2483         if (!NT_STATUS_IS_OK(status)) {
2484                 tevent_req_nterror(req, status);
2485                 return;
2486         }
2487
2488         return;
2489 }
2490
2491 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2492                                         struct tevent_req *req,
2493                                         off_t *copied)
2494 {
2495         struct vfswrap_offload_write_state *state = tevent_req_data(
2496                 req, struct vfswrap_offload_write_state);
2497         NTSTATUS status;
2498
2499         if (tevent_req_is_nterror(req, &status)) {
2500                 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2501                 *copied = 0;
2502                 tevent_req_received(req);
2503                 return status;
2504         }
2505
2506         *copied = state->copied;
2507         DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2508         tevent_req_received(req);
2509
2510         return NT_STATUS_OK;
2511 }
2512
2513 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2514                                         TALLOC_CTX *mem_ctx,
2515                                         struct files_struct *fsp,
2516                                         uint16_t *_compression_fmt)
2517 {
2518         return NT_STATUS_INVALID_DEVICE_REQUEST;
2519 }
2520
2521 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2522                                         TALLOC_CTX *mem_ctx,
2523                                         struct files_struct *fsp,
2524                                         uint16_t compression_fmt)
2525 {
2526         return NT_STATUS_INVALID_DEVICE_REQUEST;
2527 }
2528
2529 /********************************************************************
2530  Given a stat buffer return the allocated size on disk, taking into
2531  account sparse files.
2532 ********************************************************************/
2533 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2534                                        struct files_struct *fsp,
2535                                        const SMB_STRUCT_STAT *sbuf)
2536 {
2537         uint64_t result;
2538
2539         START_PROFILE(syscall_get_alloc_size);
2540
2541         if(S_ISDIR(sbuf->st_ex_mode)) {
2542                 result = 0;
2543                 goto out;
2544         }
2545
2546 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2547         /* The type of st_blocksize is blkcnt_t which *MUST* be
2548            signed (according to POSIX) and can be less than 64-bits.
2549            Ensure when we're converting to 64 bits wide we don't
2550            sign extend. */
2551 #if defined(SIZEOF_BLKCNT_T_8)
2552         result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2553 #elif defined(SIZEOF_BLKCNT_T_4)
2554         {
2555                 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2556                 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2557         }
2558 #else
2559 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2560 #endif
2561         if (result == 0) {
2562                 /*
2563                  * Some file systems do not allocate a block for very
2564                  * small files. But for non-empty file should report a
2565                  * positive size.
2566                  */
2567
2568                 uint64_t filesize = get_file_size_stat(sbuf);
2569                 if (filesize > 0) {
2570                         result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2571                 }
2572         }
2573 #else
2574         result = get_file_size_stat(sbuf);
2575 #endif
2576
2577         if (fsp && fsp->initial_allocation_size)
2578                 result = MAX(result,fsp->initial_allocation_size);
2579
2580         result = smb_roundup(handle->conn, result);
2581
2582  out:
2583         END_PROFILE(syscall_get_alloc_size);
2584         return result;
2585 }
2586
2587 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2588                         struct files_struct *dirfsp,
2589                         const struct smb_filename *smb_fname,
2590                         int flags)
2591 {
2592         int result = -1;
2593
2594         START_PROFILE(syscall_unlinkat);
2595
2596         if (is_named_stream(smb_fname)) {
2597                 errno = ENOENT;
2598                 goto out;
2599         }
2600         result = unlinkat(fsp_get_pathref_fd(dirfsp),
2601                         smb_fname->base_name,
2602                         flags);
2603
2604  out:
2605         END_PROFILE(syscall_unlinkat);
2606         return result;
2607 }
2608
2609 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2610 {
2611         int result;
2612
2613         START_PROFILE(syscall_fchmod);
2614
2615         if (!fsp->fsp_flags.is_pathref) {
2616                 result = fchmod(fsp_get_io_fd(fsp), mode);
2617                 END_PROFILE(syscall_fchmod);
2618                 return result;
2619         }
2620
2621         if (fsp->fsp_flags.have_proc_fds) {
2622                 int fd = fsp_get_pathref_fd(fsp);
2623                 const char *p = NULL;
2624                 char buf[PATH_MAX];
2625
2626                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2627                 if (p != NULL) {
2628                         result = chmod(p, mode);
2629                 } else {
2630                         result = -1;
2631                 }
2632                 END_PROFILE(syscall_fchmod);
2633                 return result;
2634         }
2635
2636         /*
2637          * This is no longer a handle based call.
2638          */
2639         result = chmod(fsp->fsp_name->base_name, mode);
2640
2641         END_PROFILE(syscall_fchmod);
2642         return result;
2643 }
2644
2645 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2646 {
2647 #ifdef HAVE_FCHOWN
2648         int result;
2649
2650         START_PROFILE(syscall_fchown);
2651         if (!fsp->fsp_flags.is_pathref) {
2652                 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2653                 END_PROFILE(syscall_fchown);
2654                 return result;
2655         }
2656
2657         if (fsp->fsp_flags.have_proc_fds) {
2658                 int fd = fsp_get_pathref_fd(fsp);
2659                 const char *p = NULL;
2660                 char buf[PATH_MAX];
2661
2662                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2663                 if (p != NULL) {
2664                         result = chown(p, uid, gid);
2665                 } else {
2666                         result = -1;
2667                 }
2668                 END_PROFILE(syscall_fchown);
2669                 return result;
2670         }
2671
2672         /*
2673          * This is no longer a handle based call.
2674          */
2675         result = chown(fsp->fsp_name->base_name, uid, gid);
2676         END_PROFILE(syscall_fchown);
2677         return result;
2678 #else
2679         errno = ENOSYS;
2680         return -1;
2681 #endif
2682 }
2683
2684 static int vfswrap_lchown(vfs_handle_struct *handle,
2685                         const struct smb_filename *smb_fname,
2686                         uid_t uid,
2687                         gid_t gid)
2688 {
2689         int result;
2690
2691         START_PROFILE(syscall_lchown);
2692         result = lchown(smb_fname->base_name, uid, gid);
2693         END_PROFILE(syscall_lchown);
2694         return result;
2695 }
2696
2697 static int vfswrap_chdir(vfs_handle_struct *handle,
2698                         const struct smb_filename *smb_fname)
2699 {
2700         int result;
2701
2702         START_PROFILE(syscall_chdir);
2703         result = chdir(smb_fname->base_name);
2704         END_PROFILE(syscall_chdir);
2705         return result;
2706 }
2707
2708 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2709                                 TALLOC_CTX *ctx)
2710 {
2711         char *result;
2712         struct smb_filename *smb_fname = NULL;
2713
2714         START_PROFILE(syscall_getwd);
2715         result = sys_getwd();
2716         END_PROFILE(syscall_getwd);
2717
2718         if (result == NULL) {
2719                 return NULL;
2720         }
2721         smb_fname = synthetic_smb_fname(ctx,
2722                                 result,
2723                                 NULL,
2724                                 NULL,
2725                                 0,
2726                                 0);
2727         /*
2728          * sys_getwd() *always* returns malloced memory.
2729          * We must free here to avoid leaks:
2730          * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2731          */
2732         SAFE_FREE(result);
2733         return smb_fname;
2734 }
2735
2736 /*********************************************************************
2737  nsec timestamp resolution call. Convert down to whatever the underlying
2738  system will support.
2739 **********************************************************************/
2740
2741 static int vfswrap_fntimes(vfs_handle_struct *handle,
2742                            files_struct *fsp,
2743                            struct smb_file_time *ft)
2744 {
2745         int result = -1;
2746         struct timespec ts[2];
2747         struct timespec *times = NULL;
2748
2749         START_PROFILE(syscall_fntimes);
2750
2751         if (is_named_stream(fsp->fsp_name)) {
2752                 errno = ENOENT;
2753                 goto out;
2754         }
2755
2756         if (ft != NULL) {
2757                 if (is_omit_timespec(&ft->atime)) {
2758                         ft->atime = fsp->fsp_name->st.st_ex_atime;
2759                 }
2760
2761                 if (is_omit_timespec(&ft->mtime)) {
2762                         ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2763                 }
2764
2765                 if (!is_omit_timespec(&ft->create_time)) {
2766                         set_create_timespec_ea(fsp,
2767                                                ft->create_time);
2768                 }
2769
2770                 if ((timespec_compare(&ft->atime,
2771                                       &fsp->fsp_name->st.st_ex_atime) == 0) &&
2772                     (timespec_compare(&ft->mtime,
2773                                       &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2774                         result = 0;
2775                         goto out;
2776                 }
2777
2778                 ts[0] = ft->atime;
2779                 ts[1] = ft->mtime;
2780                 times = ts;
2781         } else {
2782                 times = NULL;
2783         }
2784
2785         if (!fsp->fsp_flags.is_pathref) {
2786                 result = futimens(fsp_get_io_fd(fsp), times);
2787                 goto out;
2788         }
2789
2790         if (fsp->fsp_flags.have_proc_fds) {
2791                 int fd = fsp_get_pathref_fd(fsp);
2792                 const char *p = NULL;
2793                 char buf[PATH_MAX];
2794
2795                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2796                 if (p != NULL) {
2797                         /*
2798                          * The dirfd argument of utimensat is ignored when
2799                          * pathname is an absolute path
2800                          */
2801                         result = utimensat(AT_FDCWD, p, times, 0);
2802                 } else {
2803                         result = -1;
2804                 }
2805
2806                 goto out;
2807         }
2808
2809         /*
2810          * The fd is a pathref (opened with O_PATH) and there isn't fd to
2811          * path translation mechanism. Fallback to path based call.
2812          */
2813         result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2814
2815 out:
2816         END_PROFILE(syscall_fntimes);
2817
2818         return result;
2819 }
2820
2821
2822 /*********************************************************************
2823  A version of ftruncate that will write the space on disk if strict
2824  allocate is set.
2825 **********************************************************************/
2826
2827 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2828 {
2829         off_t space_to_write;
2830         uint64_t space_avail;
2831         uint64_t bsize,dfree,dsize;
2832         int ret;
2833         NTSTATUS status;
2834         SMB_STRUCT_STAT *pst;
2835         bool ok;
2836
2837         ok = vfs_valid_pwrite_range(len, 0);
2838         if (!ok) {
2839                 errno = EINVAL;
2840                 return -1;
2841         }
2842
2843         status = vfs_stat_fsp(fsp);
2844         if (!NT_STATUS_IS_OK(status)) {
2845                 return -1;
2846         }
2847         pst = &fsp->fsp_name->st;
2848
2849 #ifdef S_ISFIFO
2850         if (S_ISFIFO(pst->st_ex_mode))
2851                 return 0;
2852 #endif
2853
2854         if (pst->st_ex_size == len)
2855                 return 0;
2856
2857         /* Shrink - just ftruncate. */
2858         if (pst->st_ex_size > len)
2859                 return ftruncate(fsp_get_io_fd(fsp), len);
2860
2861         space_to_write = len - pst->st_ex_size;
2862
2863         /* for allocation try fallocate first. This can fail on some
2864            platforms e.g. when the filesystem doesn't support it and no
2865            emulation is being done by the libc (like on AIX with JFS1). In that
2866            case we do our own emulation. fallocate implementations can
2867            return ENOTSUP or EINVAL in cases like that. */
2868         ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2869         if (ret == -1 && errno == ENOSPC) {
2870                 return -1;
2871         }
2872         if (ret == 0) {
2873                 return 0;
2874         }
2875         DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2876                 "error %d. Falling back to slow manual allocation\n", errno));
2877
2878         /* available disk space is enough or not? */
2879         space_avail =
2880             get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2881         /* space_avail is 1k blocks */
2882         if (space_avail == (uint64_t)-1 ||
2883                         ((uint64_t)space_to_write/1024 > space_avail) ) {
2884                 errno = ENOSPC;
2885                 return -1;
2886         }
2887
2888         /* Write out the real space on disk. */
2889         ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2890         if (ret != 0) {
2891                 return -1;
2892         }
2893
2894         return 0;
2895 }
2896
2897 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2898 {
2899         int result = -1;
2900         SMB_STRUCT_STAT *pst;
2901         NTSTATUS status;
2902         char c = 0;
2903
2904         START_PROFILE(syscall_ftruncate);
2905
2906         if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2907                 result = strict_allocate_ftruncate(handle, fsp, len);
2908                 END_PROFILE(syscall_ftruncate);
2909                 return result;
2910         }
2911
2912         /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2913            ftruncate if the system supports it. Then I discovered that
2914            you can have some filesystems that support ftruncate
2915            expansion and some that don't! On Linux fat can't do
2916            ftruncate extend but ext2 can. */
2917
2918         result = ftruncate(fsp_get_io_fd(fsp), len);
2919
2920         /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2921            extend a file with ftruncate. Provide alternate implementation
2922            for this */
2923
2924         /* Do an fstat to see if the file is longer than the requested
2925            size in which case the ftruncate above should have
2926            succeeded or shorter, in which case seek to len - 1 and
2927            write 1 byte of zero */
2928         status = vfs_stat_fsp(fsp);
2929         if (!NT_STATUS_IS_OK(status)) {
2930                 goto done;
2931         }
2932
2933         /* We need to update the files_struct after successful ftruncate */
2934         if (result == 0) {
2935                 goto done;
2936         }
2937
2938         pst = &fsp->fsp_name->st;
2939
2940 #ifdef S_ISFIFO
2941         if (S_ISFIFO(pst->st_ex_mode)) {
2942                 result = 0;
2943                 goto done;
2944         }
2945 #endif
2946
2947         if (pst->st_ex_size == len) {
2948                 result = 0;
2949                 goto done;
2950         }
2951
2952         if (pst->st_ex_size > len) {
2953                 /* the ftruncate should have worked */
2954                 goto done;
2955         }
2956
2957         if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
2958                 goto done;
2959         }
2960
2961         result = 0;
2962
2963   done:
2964
2965         END_PROFILE(syscall_ftruncate);
2966         return result;
2967 }
2968
2969 static int vfswrap_fallocate(vfs_handle_struct *handle,
2970                         files_struct *fsp,
2971                         uint32_t mode,
2972                         off_t offset,
2973                         off_t len)
2974 {
2975         int result;
2976
2977         START_PROFILE(syscall_fallocate);
2978         if (mode == 0) {
2979                 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
2980                 /*
2981                  * posix_fallocate returns 0 on success, errno on error
2982                  * and doesn't set errno. Make it behave like fallocate()
2983                  * which returns -1, and sets errno on failure.
2984                  */
2985                 if (result != 0) {
2986                         errno = result;
2987                         result = -1;
2988                 }
2989         } else {
2990                 /* sys_fallocate handles filtering of unsupported mode flags */
2991                 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
2992         }
2993         END_PROFILE(syscall_fallocate);
2994         return result;
2995 }
2996
2997 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
2998 {
2999         bool result;
3000
3001         START_PROFILE(syscall_fcntl_lock);
3002
3003         if (fsp->fsp_flags.use_ofd_locks) {
3004                 op = map_process_lock_to_ofd_lock(op);
3005         }
3006
3007         result =  fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3008         END_PROFILE(syscall_fcntl_lock);
3009         return result;
3010 }
3011
3012 static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
3013                                 uint32_t share_access, uint32_t access_mask)
3014 {
3015         START_PROFILE(syscall_kernel_flock);
3016         kernel_flock(fsp_get_io_fd(fsp), share_access, access_mask);
3017         END_PROFILE(syscall_kernel_flock);
3018         return 0;
3019 }
3020
3021 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3022                          va_list cmd_arg)
3023 {
3024         void *argp;
3025         va_list dup_cmd_arg;
3026         int result;
3027         int val;
3028
3029         START_PROFILE(syscall_fcntl);
3030
3031         va_copy(dup_cmd_arg, cmd_arg);
3032
3033         switch(cmd) {
3034         case F_SETLK:
3035         case F_SETLKW:
3036         case F_GETLK:
3037 #if defined(HAVE_OFD_LOCKS)
3038         case F_OFD_SETLK:
3039         case F_OFD_SETLKW:
3040         case F_OFD_GETLK:
3041 #endif
3042 #if defined(HAVE_F_OWNER_EX)
3043         case F_GETOWN_EX:
3044         case F_SETOWN_EX:
3045 #endif
3046 #if defined(HAVE_RW_HINTS)
3047         case F_GET_RW_HINT:
3048         case F_SET_RW_HINT:
3049         case F_GET_FILE_RW_HINT:
3050         case F_SET_FILE_RW_HINT:
3051 #endif
3052                 argp = va_arg(dup_cmd_arg, void *);
3053                 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3054                 break;
3055         default:
3056                 val = va_arg(dup_cmd_arg, int);
3057                 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3058         }
3059
3060         va_end(dup_cmd_arg);
3061
3062         END_PROFILE(syscall_fcntl);
3063         return result;
3064 }
3065
3066 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3067 {
3068         bool result;
3069         int op = F_GETLK;
3070
3071         START_PROFILE(syscall_fcntl_getlock);
3072
3073         if (fsp->fsp_flags.use_ofd_locks) {
3074                 op = map_process_lock_to_ofd_lock(op);
3075         }
3076
3077         result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3078         END_PROFILE(syscall_fcntl_getlock);
3079         return result;
3080 }
3081
3082 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3083                                 int leasetype)
3084 {
3085         int result = -1;
3086
3087         START_PROFILE(syscall_linux_setlease);
3088
3089 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3090         result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3091 #else
3092         errno = ENOSYS;
3093 #endif
3094         END_PROFILE(syscall_linux_setlease);
3095         return result;
3096 }
3097
3098 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3099                         const struct smb_filename *link_target,
3100                         struct files_struct *dirfsp,
3101                         const struct smb_filename *new_smb_fname)
3102 {
3103         int result;
3104
3105         START_PROFILE(syscall_symlinkat);
3106
3107         result = symlinkat(link_target->base_name,
3108                         fsp_get_pathref_fd(dirfsp),
3109                         new_smb_fname->base_name);
3110         END_PROFILE(syscall_symlinkat);
3111         return result;
3112 }
3113
3114 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3115                         const struct files_struct *dirfsp,
3116                         const struct smb_filename *smb_fname,
3117                         char *buf,
3118                         size_t bufsiz)
3119 {
3120         int result;
3121
3122         START_PROFILE(syscall_readlinkat);
3123
3124         result = readlinkat(fsp_get_pathref_fd(dirfsp),
3125                         smb_fname->base_name,
3126                         buf,
3127                         bufsiz);
3128
3129         END_PROFILE(syscall_readlinkat);
3130         return result;
3131 }
3132
3133 static int vfswrap_linkat(vfs_handle_struct *handle,
3134                         files_struct *srcfsp,
3135                         const struct smb_filename *old_smb_fname,
3136                         files_struct *dstfsp,
3137                         const struct smb_filename *new_smb_fname,
3138                         int flags)
3139 {
3140         int result;
3141
3142         START_PROFILE(syscall_linkat);
3143
3144         result = linkat(fsp_get_pathref_fd(srcfsp),
3145                         old_smb_fname->base_name,
3146                         fsp_get_pathref_fd(dstfsp),
3147                         new_smb_fname->base_name,
3148                         flags);
3149
3150         END_PROFILE(syscall_linkat);
3151         return result;
3152 }
3153
3154 static int vfswrap_mknodat(vfs_handle_struct *handle,
3155                         files_struct *dirfsp,
3156                         const struct smb_filename *smb_fname,
3157                         mode_t mode,
3158                         SMB_DEV_T dev)
3159 {
3160         int result;
3161
3162         START_PROFILE(syscall_mknodat);
3163
3164         result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3165                         smb_fname->base_name,
3166                         mode,
3167                         dev);
3168
3169         END_PROFILE(syscall_mknodat);
3170         return result;
3171 }
3172
3173 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3174                         TALLOC_CTX *ctx,
3175                         const struct smb_filename *smb_fname)
3176 {
3177         char *result;
3178         struct smb_filename *result_fname = NULL;
3179
3180         START_PROFILE(syscall_realpath);
3181         result = sys_realpath(smb_fname->base_name);
3182         END_PROFILE(syscall_realpath);
3183         if (result) {
3184                 result_fname = synthetic_smb_fname(ctx,
3185                                                    result,
3186                                                    NULL,
3187                                                    NULL,
3188                                                    0,
3189                                                    0);
3190                 SAFE_FREE(result);
3191         }
3192         return result_fname;
3193 }
3194
3195 static int vfswrap_fchflags(vfs_handle_struct *handle,
3196                         struct files_struct *fsp,
3197                         unsigned int flags)
3198 {
3199 #ifdef HAVE_FCHFLAGS
3200         int fd = fsp_get_pathref_fd(fsp);
3201
3202         if (!fsp->fsp_flags.is_pathref) {
3203                 return fchflags(fd, flags);
3204         }
3205
3206         if (fsp->fsp_flags.have_proc_fds) {
3207                 const char *p = NULL;
3208                 char buf[PATH_MAX];
3209
3210                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3211                 if (p == NULL) {
3212                         return -1;
3213                 }
3214
3215                 return chflags(p, flags);
3216         }
3217
3218         /*
3219          * This is no longer a handle based call.
3220          */
3221         return chflags(fsp->fsp_name->base_name, flags);
3222 #else
3223         errno = ENOSYS;
3224         return -1;
3225 #endif
3226 }
3227
3228 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3229                                              const SMB_STRUCT_STAT *sbuf)
3230 {
3231         struct file_id key;
3232
3233         /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3234          * blob */
3235         ZERO_STRUCT(key);
3236
3237         key.devid = sbuf->st_ex_dev;
3238         key.inode = sbuf->st_ex_ino;
3239         /* key.extid is unused by default. */
3240
3241         return key;
3242 }
3243
3244 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3245                                    const SMB_STRUCT_STAT *psbuf)
3246 {
3247         uint64_t file_id;
3248
3249         if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
3250                 return psbuf->st_ex_file_id;
3251         }
3252
3253         if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3254                 return (uint64_t)psbuf->st_ex_ino;
3255         }
3256
3257         /* FileIDLow */
3258         file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3259
3260         /* FileIDHigh */
3261         file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3262
3263         return file_id;
3264 }
3265
3266 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3267                                    struct files_struct *fsp,
3268                                    TALLOC_CTX *mem_ctx,
3269                                    unsigned int *pnum_streams,
3270                                    struct stream_struct **pstreams)
3271 {
3272         struct stream_struct *tmp_streams = NULL;
3273         unsigned int num_streams = *pnum_streams;
3274         struct stream_struct *streams = *pstreams;
3275         NTSTATUS status;
3276
3277         if (fsp->fsp_flags.is_directory) {
3278                 /*
3279                  * No default streams on directories
3280                  */
3281                 goto done;
3282         }
3283         status = vfs_stat_fsp(fsp);
3284         if (!NT_STATUS_IS_OK(status)) {
3285                 return status;
3286         }
3287
3288         if (num_streams + 1 < 1) {
3289                 /* Integer wrap. */
3290                 return NT_STATUS_INVALID_PARAMETER;
3291         }
3292
3293         tmp_streams = talloc_realloc(mem_ctx,
3294                                         streams,
3295                                         struct stream_struct,
3296                                         num_streams + 1);
3297         if (tmp_streams == NULL) {
3298                 return NT_STATUS_NO_MEMORY;
3299         }
3300         tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3301         if (tmp_streams[num_streams].name == NULL) {
3302                 return NT_STATUS_NO_MEMORY;
3303         }
3304         tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3305         tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3306                                                 handle->conn,
3307                                                 fsp,
3308                                                 &fsp->fsp_name->st);
3309         num_streams += 1;
3310
3311         *pnum_streams = num_streams;
3312         *pstreams = tmp_streams;
3313  done:
3314         return NT_STATUS_OK;
3315 }
3316
3317 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
3318                                      const struct smb_filename *path,
3319                                      const char *name,
3320                                      TALLOC_CTX *mem_ctx,
3321                                      char **found_name)
3322 {
3323         /*
3324          * Don't fall back to get_real_filename so callers can differentiate
3325          * between a full directory scan and an actual case-insensitive stat.
3326          */
3327         errno = EOPNOTSUPP;
3328         return -1;
3329 }
3330
3331 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3332                                    const struct smb_filename *smb_fname)
3333 {
3334         return handle->conn->connectpath;
3335 }
3336
3337 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3338                                          struct byte_range_lock *br_lck,
3339                                          struct lock_struct *plock)
3340 {
3341         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3342
3343         /* Note: blr is not used in the default implementation. */
3344         return brl_lock_windows_default(br_lck, plock);
3345 }
3346
3347 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3348                                        struct byte_range_lock *br_lck,
3349                                        const struct lock_struct *plock)
3350 {
3351         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3352
3353         return brl_unlock_windows_default(br_lck, plock);
3354 }
3355
3356 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3357                                       files_struct *fsp,
3358                                       struct lock_struct *plock)
3359 {
3360         SMB_ASSERT(plock->lock_type == READ_LOCK ||
3361             plock->lock_type == WRITE_LOCK);
3362
3363         return strict_lock_check_default(fsp, plock);
3364 }
3365
3366 /* NT ACL operations. */
3367
3368 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3369                                     files_struct *fsp,
3370                                     uint32_t security_info,
3371                                     TALLOC_CTX *mem_ctx,
3372                                     struct security_descriptor **ppdesc)
3373 {
3374         NTSTATUS result;
3375
3376         START_PROFILE(fget_nt_acl);
3377         result = posix_fget_nt_acl(fsp, security_info,
3378                                    mem_ctx, ppdesc);
3379         END_PROFILE(fget_nt_acl);
3380         return result;
3381 }
3382
3383 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3384 {
3385         NTSTATUS result;
3386
3387         START_PROFILE(fset_nt_acl);
3388         result = set_nt_acl(fsp, security_info_sent, psd);
3389         END_PROFILE(fset_nt_acl);
3390         return result;
3391 }
3392
3393 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3394                                    struct smb_filename *file,
3395                                    struct security_acl *sacl,
3396                                    uint32_t access_requested,
3397                                    uint32_t access_denied)
3398 {
3399         return NT_STATUS_OK; /* Nothing to do here ... */
3400 }
3401
3402 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3403                                         files_struct *fsp,
3404                                         SMB_ACL_TYPE_T type,
3405                                         TALLOC_CTX *mem_ctx)
3406 {
3407         return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3408 }
3409
3410 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3411                                   files_struct *fsp,
3412                                   SMB_ACL_TYPE_T type,
3413                                   SMB_ACL_T theacl)
3414 {
3415         return sys_acl_set_fd(handle, fsp, type, theacl);
3416 }
3417
3418 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3419                                          files_struct *fsp)
3420 {
3421         return sys_acl_delete_def_fd(handle, fsp);
3422 }
3423
3424 /****************************************************************
3425  Extended attribute operations.
3426 *****************************************************************/
3427
3428 struct vfswrap_getxattrat_state {
3429         struct tevent_context *ev;
3430         files_struct *dir_fsp;
3431         const struct smb_filename *smb_fname;
3432
3433         /*
3434          * The following variables are talloced off "state" which is protected
3435          * by a destructor and thus are guaranteed to be safe to be used in the
3436          * job function in the worker thread.
3437          */
3438         char *name;
3439         const char *xattr_name;
3440         uint8_t *xattr_value;
3441         struct security_unix_token *token;
3442
3443         ssize_t xattr_size;
3444         struct vfs_aio_state vfs_aio_state;
3445         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3446 };
3447
3448 static int vfswrap_getxattrat_state_destructor(
3449                 struct vfswrap_getxattrat_state *state)
3450 {
3451         return -1;
3452 }
3453
3454 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3455 static void vfswrap_getxattrat_do_async(void *private_data);
3456 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3457
3458 static struct tevent_req *vfswrap_getxattrat_send(
3459                         TALLOC_CTX *mem_ctx,
3460                         struct tevent_context *ev,
3461                         struct vfs_handle_struct *handle,
3462                         files_struct *dir_fsp,
3463                         const struct smb_filename *smb_fname,
3464                         const char *xattr_name,
3465                         size_t alloc_hint)
3466 {
3467         struct tevent_req *req = NULL;
3468         struct tevent_req *subreq = NULL;
3469         struct vfswrap_getxattrat_state *state = NULL;
3470         size_t max_threads = 0;
3471         bool have_per_thread_cwd = false;
3472         bool have_per_thread_creds = false;
3473         bool do_async = false;
3474
3475         req = tevent_req_create(mem_ctx, &state,
3476                                 struct vfswrap_getxattrat_state);
3477         if (req == NULL) {
3478                 return NULL;
3479         }
3480         *state = (struct vfswrap_getxattrat_state) {
3481                 .ev = ev,
3482                 .dir_fsp = dir_fsp,
3483                 .smb_fname = smb_fname,
3484         };
3485
3486         max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3487         if (max_threads >= 1) {
3488                 /*
3489                  * We need a non sync threadpool!
3490                  */
3491                 have_per_thread_cwd = per_thread_cwd_supported();
3492         }
3493 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3494         have_per_thread_creds = true;
3495 #endif
3496         if (have_per_thread_cwd && have_per_thread_creds) {
3497                 do_async = true;
3498         }
3499
3500         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3501                                      state->profile_bytes, 0);
3502
3503         if (fsp_get_pathref_fd(dir_fsp) == -1) {
3504                 DBG_ERR("Need a valid directory fd\n");
3505                 tevent_req_error(req, EINVAL);
3506                 return tevent_req_post(req, ev);
3507         }
3508
3509         if (alloc_hint > 0) {
3510                 state->xattr_value = talloc_zero_array(state,
3511                                                        uint8_t,
3512                                                        alloc_hint);
3513                 if (tevent_req_nomem(state->xattr_value, req)) {
3514                         return tevent_req_post(req, ev);
3515                 }
3516         }
3517
3518         if (!do_async) {
3519                 vfswrap_getxattrat_do_sync(req);
3520                 return tevent_req_post(req, ev);
3521         }
3522
3523         /*
3524          * Now allocate all parameters from a memory context that won't go away
3525          * no matter what. These paremeters will get used in threads and we
3526          * can't reliably cancel threads, so all buffers passed to the threads
3527          * must not be freed before all referencing threads terminate.
3528          */
3529
3530         state->name = talloc_strdup(state, smb_fname->base_name);
3531         if (tevent_req_nomem(state->name, req)) {
3532                 return tevent_req_post(req, ev);
3533         }
3534
3535         state->xattr_name = talloc_strdup(state, xattr_name);
3536         if (tevent_req_nomem(state->xattr_name, req)) {
3537                 return tevent_req_post(req, ev);
3538         }
3539
3540         /*
3541          * This is a hot codepath so at first glance one might think we should
3542          * somehow optimize away the token allocation and do a
3543          * talloc_reference() or similar black magic instead. But due to the
3544          * talloc_stackframe pool per SMB2 request this should be a simple copy
3545          * without a malloc in most cases.
3546          */
3547         if (geteuid() == sec_initial_uid()) {
3548                 state->token = root_unix_token(state);
3549         } else {
3550                 state->token = copy_unix_token(
3551                                         state,
3552                                         dir_fsp->conn->session_info->unix_token);
3553         }
3554         if (tevent_req_nomem(state->token, req)) {
3555                 return tevent_req_post(req, ev);
3556         }
3557
3558         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3559
3560         subreq = pthreadpool_tevent_job_send(
3561                         state,
3562                         ev,
3563                         dir_fsp->conn->sconn->pool,
3564                         vfswrap_getxattrat_do_async,
3565                         state);
3566         if (tevent_req_nomem(subreq, req)) {
3567                 return tevent_req_post(req, ev);
3568         }
3569         tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3570
3571         talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3572
3573         return req;
3574 }
3575
3576 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3577 {
3578         struct vfswrap_getxattrat_state *state = tevent_req_data(
3579                 req, struct vfswrap_getxattrat_state);
3580         char *path = NULL;
3581         char *tofree = NULL;
3582         char pathbuf[PATH_MAX+1];
3583         ssize_t pathlen;
3584         int err;
3585
3586         pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
3587                                 state->smb_fname->base_name,
3588                                 pathbuf,
3589                                 sizeof(pathbuf),
3590                                 &path,
3591                                 &tofree);
3592         if (pathlen == -1) {
3593                 tevent_req_error(req, ENOMEM);
3594                 return;
3595         }
3596
3597         state->xattr_size = getxattr(path,
3598                                      state->xattr_name,
3599                                      state->xattr_value,
3600                                      talloc_array_length(state->xattr_value));
3601         err = errno;
3602         TALLOC_FREE(tofree);
3603         if (state->xattr_size == -1) {
3604                 tevent_req_error(req, err);
3605                 return;
3606         }
3607
3608         tevent_req_done(req);
3609         return;
3610 }
3611
3612 static void vfswrap_getxattrat_do_async(void *private_data)
3613 {
3614         struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3615                 private_data, struct vfswrap_getxattrat_state);
3616         struct timespec start_time;
3617         struct timespec end_time;
3618         int ret;
3619
3620         PROFILE_TIMESTAMP(&start_time);
3621         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3622
3623         /*
3624          * Here we simulate a getxattrat()
3625          * call using fchdir();getxattr()
3626          */
3627
3628         per_thread_cwd_activate();
3629
3630         /* Become the correct credential on this thread. */
3631         ret = set_thread_credentials(state->token->uid,
3632                                      state->token->gid,
3633                                      (size_t)state->token->ngroups,
3634                                      state->token->groups);
3635         if (ret != 0) {
3636                 state->xattr_size = -1;
3637                 state->vfs_aio_state.error = errno;
3638                 goto end_profile;
3639         }
3640
3641         ret = fchdir(fsp_get_pathref_fd(state->dir_fsp));
3642         if (ret == -1) {
3643                 state->xattr_size = -1;
3644                 state->vfs_aio_state.error = errno;
3645                 goto end_profile;
3646         }
3647
3648         state->xattr_size = getxattr(state->name,
3649                                      state->xattr_name,
3650                                      state->xattr_value,
3651                                      talloc_array_length(state->xattr_value));
3652         if (state->xattr_size == -1) {
3653                 state->vfs_aio_state.error = errno;
3654         }
3655
3656 end_profile:
3657         PROFILE_TIMESTAMP(&end_time);
3658         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3659         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3660 }
3661
3662 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3663 {
3664         struct tevent_req *req = tevent_req_callback_data(
3665                 subreq, struct tevent_req);
3666         struct vfswrap_getxattrat_state *state = tevent_req_data(
3667                 req, struct vfswrap_getxattrat_state);
3668         int ret;
3669         bool ok;
3670
3671         /*
3672          * Make sure we run as the user again
3673          */
3674         ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3675         SMB_ASSERT(ok);
3676
3677         ret = pthreadpool_tevent_job_recv(subreq);
3678         TALLOC_FREE(subreq);
3679         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3680         talloc_set_destructor(state, NULL);
3681         if (ret != 0) {
3682                 if (ret != EAGAIN) {
3683                         tevent_req_error(req, ret);
3684                         return;
3685                 }
3686                 /*
3687                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3688                  * means the lower level pthreadpool failed to create a new
3689                  * thread. Fallback to sync processing in that case to allow
3690                  * some progress for the client.
3691                  */
3692                 vfswrap_getxattrat_do_sync(req);
3693                 return;
3694         }
3695
3696         if (state->xattr_size == -1) {
3697                 tevent_req_error(req, state->vfs_aio_state.error);
3698                 return;
3699         }
3700
3701         if (state->xattr_value == NULL) {
3702                 /*
3703                  * The caller only wanted the size.
3704                  */
3705                 tevent_req_done(req);
3706                 return;
3707         }
3708
3709         /*
3710          * shrink the buffer to the returned size.
3711          * (can't fail). It means NULL if size is 0.
3712          */
3713         state->xattr_value = talloc_realloc(state,
3714                                             state->xattr_value,
3715                                             uint8_t,
3716                                             state->xattr_size);
3717
3718         tevent_req_done(req);
3719 }
3720
3721 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3722                                        struct vfs_aio_state *aio_state,
3723                                        TALLOC_CTX *mem_ctx,
3724                                        uint8_t **xattr_value)
3725 {
3726         struct vfswrap_getxattrat_state *state = tevent_req_data(
3727                 req, struct vfswrap_getxattrat_state);
3728         ssize_t xattr_size;
3729
3730         if (tevent_req_is_unix_error(req, &aio_state->error)) {
3731                 tevent_req_received(req);
3732                 return -1;
3733         }
3734
3735         *aio_state = state->vfs_aio_state;
3736         xattr_size = state->xattr_size;
3737         if (xattr_value != NULL) {
3738                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3739         }
3740
3741         tevent_req_received(req);
3742         return xattr_size;
3743 }
3744
3745 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3746                                  struct files_struct *fsp,
3747                                  const char *name,
3748                                  void *value,
3749                                  size_t size)
3750 {
3751         int fd = fsp_get_pathref_fd(fsp);
3752
3753         if (!fsp->fsp_flags.is_pathref) {
3754                 return fgetxattr(fd, name, value, size);
3755         }
3756
3757         if (fsp->fsp_flags.have_proc_fds) {
3758                 const char *p = NULL;
3759                 char buf[PATH_MAX];
3760
3761                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3762                 if (p == NULL) {
3763                         return -1;
3764                 }
3765
3766                 return getxattr(p, name, value, size);
3767         }
3768
3769         /*
3770          * This is no longer a handle based call.
3771          */
3772         return getxattr(fsp->fsp_name->base_name, name, value, size);
3773 }
3774
3775 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3776 {
3777         int fd = fsp_get_pathref_fd(fsp);
3778
3779         if (!fsp->fsp_flags.is_pathref) {
3780                 return flistxattr(fd, list, size);
3781         }
3782
3783         if (fsp->fsp_flags.have_proc_fds) {
3784                 const char *p = NULL;
3785                 char buf[PATH_MAX];
3786
3787                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3788                 if (p == NULL) {
3789                         return -1;
3790                 }
3791
3792                 return listxattr(p, list, size);
3793         }
3794
3795         /*
3796          * This is no longer a handle based call.
3797          */
3798         return listxattr(fsp->fsp_name->base_name, list, size);
3799 }
3800
3801 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3802 {
3803         int fd = fsp_get_pathref_fd(fsp);
3804
3805         if (!fsp->fsp_flags.is_pathref) {
3806                 return fremovexattr(fd, name);
3807         }
3808
3809         if (fsp->fsp_flags.have_proc_fds) {
3810                 const char *p = NULL;
3811                 char buf[PATH_MAX];
3812
3813                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3814                 if (p == NULL) {
3815                         return -1;
3816                 }
3817
3818                 return removexattr(p, name);
3819         }
3820
3821         /*
3822          * This is no longer a handle based call.
3823          */
3824         return removexattr(fsp->fsp_name->base_name, name);
3825 }
3826
3827 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3828 {
3829         int fd = fsp_get_pathref_fd(fsp);
3830
3831         if (!fsp->fsp_flags.is_pathref) {
3832                 return fsetxattr(fd, name, value, size, flags);
3833         }
3834
3835         if (fsp->fsp_flags.have_proc_fds) {
3836                 const char *p = NULL;
3837                 char buf[PATH_MAX];
3838
3839                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3840                 if (p == NULL) {
3841                         return -1;
3842                 }
3843
3844                 return setxattr(p, name, value, size, flags);
3845         }
3846
3847         /*
3848          * This is no longer a handle based call.
3849          */
3850         return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3851 }
3852
3853 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3854 {
3855         return false;
3856 }
3857
3858 static bool vfswrap_is_offline(struct connection_struct *conn,
3859                                const struct smb_filename *fname)
3860 {
3861         NTSTATUS status;
3862         char *path;
3863         bool offline = false;
3864
3865         if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3866                 return false;
3867         }
3868
3869         if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3870 #if defined(ENOTSUP)
3871                 errno = ENOTSUP;
3872 #endif
3873                 return false;
3874         }
3875
3876         status = get_full_smb_filename(talloc_tos(), fname, &path);
3877         if (!NT_STATUS_IS_OK(status)) {
3878                 errno = map_errno_from_nt_status(status);
3879                 return false;
3880         }
3881
3882         offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3883
3884         TALLOC_FREE(path);
3885
3886         return offline;
3887 }
3888
3889 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3890                                        struct files_struct *fsp,
3891                                        TALLOC_CTX *mem_ctx,
3892                                        DATA_BLOB *cookie)
3893 {
3894         return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3895 }
3896
3897 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3898                                            struct files_struct *fsp,
3899                                            const DATA_BLOB old_cookie,
3900                                            TALLOC_CTX *mem_ctx,
3901                                            DATA_BLOB *new_cookie)
3902 {
3903         return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3904                                               new_cookie);
3905 }
3906
3907 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3908                                           struct smb_request *smb1req,
3909                                           struct smbXsrv_open *op,
3910                                           const DATA_BLOB old_cookie,
3911                                           TALLOC_CTX *mem_ctx,
3912                                           struct files_struct **fsp,
3913                                           DATA_BLOB *new_cookie)
3914 {
3915         return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3916                                              old_cookie, mem_ctx,
3917                                              fsp, new_cookie);
3918 }
3919
3920 static struct vfs_fn_pointers vfs_default_fns = {
3921         /* Disk operations */
3922
3923         .connect_fn = vfswrap_connect,
3924         .disconnect_fn = vfswrap_disconnect,
3925         .disk_free_fn = vfswrap_disk_free,
3926         .get_quota_fn = vfswrap_get_quota,
3927         .set_quota_fn = vfswrap_set_quota,
3928         .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3929         .statvfs_fn = vfswrap_statvfs,
3930         .fs_capabilities_fn = vfswrap_fs_capabilities,
3931         .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3932         .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3933         .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3934         .snap_check_path_fn = vfswrap_snap_check_path,
3935         .snap_create_fn = vfswrap_snap_create,
3936         .snap_delete_fn = vfswrap_snap_delete,
3937
3938         /* Directory operations */
3939
3940         .fdopendir_fn = vfswrap_fdopendir,
3941         .readdir_fn = vfswrap_readdir,
3942         .freaddir_attr_fn = vfswrap_freaddir_attr,
3943         .seekdir_fn = vfswrap_seekdir,
3944         .telldir_fn = vfswrap_telldir,
3945         .rewind_dir_fn = vfswrap_rewinddir,
3946         .mkdirat_fn = vfswrap_mkdirat,
3947         .closedir_fn = vfswrap_closedir,
3948
3949         /* File operations */
3950
3951         .openat_fn = vfswrap_openat,
3952         .create_file_fn = vfswrap_create_file,
3953         .close_fn = vfswrap_close,
3954         .pread_fn = vfswrap_pread,
3955         .pread_send_fn = vfswrap_pread_send,
3956         .pread_recv_fn = vfswrap_pread_recv,
3957         .pwrite_fn = vfswrap_pwrite,
3958         .pwrite_send_fn = vfswrap_pwrite_send,
3959         .pwrite_recv_fn = vfswrap_pwrite_recv,
3960         .lseek_fn = vfswrap_lseek,
3961         .sendfile_fn = vfswrap_sendfile,
3962         .recvfile_fn = vfswrap_recvfile,
3963         .renameat_fn = vfswrap_renameat,
3964         .fsync_send_fn = vfswrap_fsync_send,
3965         .fsync_recv_fn = vfswrap_fsync_recv,
3966         .stat_fn = vfswrap_stat,
3967         .fstat_fn = vfswrap_fstat,
3968         .lstat_fn = vfswrap_lstat,
3969         .get_alloc_size_fn = vfswrap_get_alloc_size,
3970         .unlinkat_fn = vfswrap_unlinkat,
3971         .fchmod_fn = vfswrap_fchmod,
3972         .fchown_fn = vfswrap_fchown,
3973         .lchown_fn = vfswrap_lchown,
3974         .chdir_fn = vfswrap_chdir,
3975         .getwd_fn = vfswrap_getwd,
3976         .fntimes_fn = vfswrap_fntimes,
3977         .ftruncate_fn = vfswrap_ftruncate,
3978         .fallocate_fn = vfswrap_fallocate,
3979         .lock_fn = vfswrap_lock,
3980         .kernel_flock_fn = vfswrap_kernel_flock,
3981         .fcntl_fn = vfswrap_fcntl,
3982         .linux_setlease_fn = vfswrap_linux_setlease,
3983         .getlock_fn = vfswrap_getlock,
3984         .symlinkat_fn = vfswrap_symlinkat,
3985         .readlinkat_fn = vfswrap_readlinkat,
3986         .linkat_fn = vfswrap_linkat,
3987         .mknodat_fn = vfswrap_mknodat,
3988         .realpath_fn = vfswrap_realpath,
3989         .fchflags_fn = vfswrap_fchflags,
3990         .file_id_create_fn = vfswrap_file_id_create,
3991         .fs_file_id_fn = vfswrap_fs_file_id,
3992         .fstreaminfo_fn = vfswrap_fstreaminfo,
3993         .get_real_filename_fn = vfswrap_get_real_filename,
3994         .connectpath_fn = vfswrap_connectpath,
3995         .brl_lock_windows_fn = vfswrap_brl_lock_windows,
3996         .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
3997         .strict_lock_check_fn = vfswrap_strict_lock_check,
3998         .translate_name_fn = vfswrap_translate_name,
3999         .parent_pathname_fn = vfswrap_parent_pathname,
4000         .fsctl_fn = vfswrap_fsctl,
4001         .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4002         .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4003         .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4004         .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4005         .offload_read_send_fn = vfswrap_offload_read_send,
4006         .offload_read_recv_fn = vfswrap_offload_read_recv,
4007         .offload_write_send_fn = vfswrap_offload_write_send,
4008         .offload_write_recv_fn = vfswrap_offload_write_recv,
4009         .fget_compression_fn = vfswrap_fget_compression,
4010         .set_compression_fn = vfswrap_set_compression,
4011
4012         /* NT ACL operations. */
4013
4014         .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4015         .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4016         .audit_file_fn = vfswrap_audit_file,
4017
4018         /* POSIX ACL operations. */
4019
4020         .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4021         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4022         .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4023         .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4024
4025         /* EA operations. */
4026         .getxattrat_send_fn = vfswrap_getxattrat_send,
4027         .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4028         .fgetxattr_fn = vfswrap_fgetxattr,
4029         .flistxattr_fn = vfswrap_flistxattr,
4030         .fremovexattr_fn = vfswrap_fremovexattr,
4031         .fsetxattr_fn = vfswrap_fsetxattr,
4032
4033         /* aio operations */
4034         .aio_force_fn = vfswrap_aio_force,
4035
4036         /* durable handle operations */
4037         .durable_cookie_fn = vfswrap_durable_cookie,
4038         .durable_disconnect_fn = vfswrap_durable_disconnect,
4039         .durable_reconnect_fn = vfswrap_durable_reconnect,
4040 };
4041
4042 static_decl_vfs;
4043 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4044 {
4045         /*
4046          * Here we need to implement every call!
4047          *
4048          * As this is the end of the vfs module chain.
4049          */
4050         smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4051         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4052                                 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);
4053 }
4054
4055