vfs: Add SMB_VFS_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         if (is_named_stream(smb_fname)) {
441                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
442                 goto err;
443         }
444
445         if (ppreflist == NULL && preferral_count == NULL) {
446                 /*
447                  * We're only checking if this is a DFS
448                  * redirect. We don't need to return data.
449                  */
450                 bufsize = sizeof(link_target_buf);
451                 link_target = link_target_buf;
452         } else {
453                 bufsize = PATH_MAX;
454                 link_target = talloc_array(mem_ctx, char, bufsize);
455                 if (!link_target) {
456                         goto err;
457                 }
458         }
459
460         referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
461                                 smb_fname->base_name,
462                                 link_target,
463                                 bufsize - 1);
464         if (referral_len == -1) {
465                 if (errno == EINVAL) {
466                         /*
467                          * If the path isn't a link, readlinkat
468                          * returns EINVAL. Allow the caller to
469                          * detect this.
470                          */
471                         DBG_INFO("%s is not a link.\n", smb_fname->base_name);
472                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
473                 } else {
474                         status = map_nt_error_from_unix(errno);
475                         if (errno == ENOENT) {
476                                 DBG_NOTICE("Error reading "
477                                          "msdfs link %s: %s\n",
478                                          smb_fname->base_name,
479                                          strerror(errno));
480                         } else {
481                                 DBG_ERR("Error reading "
482                                         "msdfs link %s: %s\n",
483                                         smb_fname->base_name,
484                                         strerror(errno));
485                         }
486                 }
487                 goto err;
488         }
489         link_target[referral_len] = '\0';
490
491         DBG_INFO("%s -> %s\n",
492                         smb_fname->base_name,
493                         link_target);
494
495         if (!strnequal(link_target, "msdfs:", 6)) {
496                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
497                 goto err;
498         }
499
500        ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
501                          smb_fname->base_name,
502                          &smb_fname->st,
503                          AT_SYMLINK_NOFOLLOW,
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 int vfswrap_fstatat(
1318         struct vfs_handle_struct *handle,
1319         const struct files_struct *dirfsp,
1320         const struct smb_filename *smb_fname,
1321         SMB_STRUCT_STAT *sbuf,
1322         int flags)
1323 {
1324         int result = -1;
1325
1326         START_PROFILE(syscall_fstatat);
1327
1328         if (is_named_stream(smb_fname)) {
1329                 errno = ENOENT;
1330                 goto out;
1331         }
1332
1333         result = sys_fstatat(
1334                 fsp_get_pathref_fd(dirfsp),
1335                 smb_fname->base_name,
1336                 sbuf,
1337                 flags,
1338                 lp_fake_directory_create_times(SNUM(handle->conn)));
1339  out:
1340         END_PROFILE(syscall_fstatat);
1341         return result;
1342 }
1343
1344 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1345                                        const char *name,
1346                                        enum vfs_translate_direction direction,
1347                                        TALLOC_CTX *mem_ctx,
1348                                        char **mapped_name)
1349 {
1350         return NT_STATUS_NONE_MAPPED;
1351 }
1352
1353 /**
1354  * Return allocated parent directory and basename of path
1355  *
1356  * Note: if requesting atname, it is returned as talloc child of the
1357  * parent. Freeing the parent is thus sufficient to free both.
1358  */
1359 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1360                                         TALLOC_CTX *mem_ctx,
1361                                         const struct smb_filename *smb_fname_in,
1362                                         struct smb_filename **parent_dir_out,
1363                                         struct smb_filename **atname_out)
1364 {
1365         TALLOC_CTX *frame = talloc_stackframe();
1366         struct smb_filename *parent = NULL;
1367         struct smb_filename *name = NULL;
1368         char *p = NULL;
1369
1370         parent = cp_smb_filename_nostream(frame, smb_fname_in);
1371         if (parent == NULL) {
1372                 TALLOC_FREE(frame);
1373                 return NT_STATUS_NO_MEMORY;
1374         }
1375         SET_STAT_INVALID(parent->st);
1376
1377         p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1378         if (p == NULL) {
1379                 TALLOC_FREE(parent->base_name);
1380                 parent->base_name = talloc_strdup(parent, ".");
1381                 if (parent->base_name == NULL) {
1382                         TALLOC_FREE(frame);
1383                         return NT_STATUS_NO_MEMORY;
1384                 }
1385                 p = smb_fname_in->base_name;
1386         } else {
1387                 *p = '\0';
1388                 p++;
1389         }
1390
1391         if (atname_out == NULL) {
1392                 *parent_dir_out = talloc_move(mem_ctx, &parent);
1393                 TALLOC_FREE(frame);
1394                 return NT_STATUS_OK;
1395         }
1396
1397         name = cp_smb_filename(frame, smb_fname_in);
1398         if (name == NULL) {
1399                 TALLOC_FREE(frame);
1400                 return NT_STATUS_NO_MEMORY;
1401         }
1402         TALLOC_FREE(name->base_name);
1403
1404         name->base_name = talloc_strdup(name, p);
1405         if (name->base_name == NULL) {
1406                 TALLOC_FREE(frame);
1407                 return NT_STATUS_NO_MEMORY;
1408         }
1409
1410         *parent_dir_out = talloc_move(mem_ctx, &parent);
1411         *atname_out = talloc_move(*parent_dir_out, &name);
1412         TALLOC_FREE(frame);
1413         return NT_STATUS_OK;
1414 }
1415
1416 /*
1417  * Implement the default fsctl operation.
1418  */
1419 static bool vfswrap_logged_ioctl_message = false;
1420
1421 static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1422                               struct files_struct *fsp,
1423                               TALLOC_CTX *ctx,
1424                               uint32_t function,
1425                               uint16_t req_flags, /* Needed for UNICODE ... */
1426                               const uint8_t *_in_data,
1427                               uint32_t in_len,
1428                               uint8_t **_out_data,
1429                               uint32_t max_out_len,
1430                               uint32_t *out_len)
1431 {
1432         const char *in_data = (const char *)_in_data;
1433         char **out_data = (char **)_out_data;
1434         NTSTATUS status;
1435
1436         switch (function) {
1437         case FSCTL_SET_SPARSE:
1438         {
1439                 bool set_sparse = true;
1440
1441                 if (in_len >= 1 && in_data[0] == 0) {
1442                         set_sparse = false;
1443                 }
1444
1445                 status = file_set_sparse(handle->conn, fsp, set_sparse);
1446
1447                 DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1448                       ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1449                        smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1450                        nt_errstr(status)));
1451
1452                 return status;
1453         }
1454
1455         case FSCTL_CREATE_OR_GET_OBJECT_ID:
1456         {
1457                 unsigned char objid[16];
1458                 char *return_data = NULL;
1459
1460                 /* This should return the object-id on this file.
1461                  * I think I'll make this be the inode+dev. JRA.
1462                  */
1463
1464                 DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1465                           fsp_fnum_dbg(fsp)));
1466
1467                 *out_len = MIN(max_out_len, 64);
1468
1469                 /* Hmmm, will this cause problems if less data asked for? */
1470                 return_data = talloc_array(ctx, char, 64);
1471                 if (return_data == NULL) {
1472                         return NT_STATUS_NO_MEMORY;
1473                 }
1474
1475                 /* For backwards compatibility only store the dev/inode. */
1476                 push_file_id_16(return_data, &fsp->file_id);
1477                 memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1478                 push_file_id_16(return_data+32, &fsp->file_id);
1479                 memset(return_data+48, 0, 16);
1480                 *out_data = return_data;
1481                 return NT_STATUS_OK;
1482         }
1483
1484         case FSCTL_GET_REPARSE_POINT:
1485         {
1486                 status = fsctl_get_reparse_point(
1487                         fsp, ctx, out_data, max_out_len, out_len);
1488                 return status;
1489         }
1490
1491         case FSCTL_SET_REPARSE_POINT:
1492         {
1493                 status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1494                 return status;
1495         }
1496
1497         case FSCTL_DELETE_REPARSE_POINT:
1498         {
1499                 status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1500                 return status;
1501         }
1502
1503         case FSCTL_GET_SHADOW_COPY_DATA:
1504         {
1505                 /*
1506                  * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1507                  * and return their volume names.  If max_data_count is 16, then it is just
1508                  * asking for the number of volumes and length of the combined names.
1509                  *
1510                  * pdata is the data allocated by our caller, but that uses
1511                  * total_data_count (which is 0 in our case) rather than max_data_count.
1512                  * Allocate the correct amount and return the pointer to let
1513                  * it be deallocated when we return.
1514                  */
1515                 struct shadow_copy_data *shadow_data = NULL;
1516                 bool labels = False;
1517                 uint32_t labels_data_count = 0;
1518                 uint32_t i;
1519                 char *cur_pdata = NULL;
1520
1521                 if (max_out_len < 16) {
1522                         DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1523                                 max_out_len));
1524                         return NT_STATUS_INVALID_PARAMETER;
1525                 }
1526
1527                 if (max_out_len > 16) {
1528                         labels = True;
1529                 }
1530
1531                 shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1532                 if (shadow_data == NULL) {
1533                         DEBUG(0,("TALLOC_ZERO() failed!\n"));
1534                         return NT_STATUS_NO_MEMORY;
1535                 }
1536
1537                 /*
1538                  * Call the VFS routine to actually do the work.
1539                  */
1540                 if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1541                         int log_lev = 0;
1542                         if (errno == 0) {
1543                                 /* broken module didn't set errno on error */
1544                                 status = NT_STATUS_UNSUCCESSFUL;
1545                         } else {
1546                                 status = map_nt_error_from_unix(errno);
1547                                 if (NT_STATUS_EQUAL(status,
1548                                                     NT_STATUS_NOT_SUPPORTED)) {
1549                                         log_lev = 5;
1550                                 }
1551                         }
1552                         DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1553                                         "connectpath %s, failed - %s.\n",
1554                                         fsp->conn->connectpath,
1555                                         nt_errstr(status)));
1556                         TALLOC_FREE(shadow_data);
1557                         return status;
1558                 }
1559
1560                 labels_data_count = (shadow_data->num_volumes * 2 *
1561                                         sizeof(SHADOW_COPY_LABEL)) + 2;
1562
1563                 if (!labels) {
1564                         *out_len = 16;
1565                 } else {
1566                         *out_len = 12 + labels_data_count;
1567                 }
1568
1569                 if (max_out_len < *out_len) {
1570                         DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1571                                 max_out_len, *out_len));
1572                         TALLOC_FREE(shadow_data);
1573                         return NT_STATUS_BUFFER_TOO_SMALL;
1574                 }
1575
1576                 cur_pdata = talloc_zero_array(ctx, char, *out_len);
1577                 if (cur_pdata == NULL) {
1578                         TALLOC_FREE(shadow_data);
1579                         return NT_STATUS_NO_MEMORY;
1580                 }
1581
1582                 *out_data = cur_pdata;
1583
1584                 /* num_volumes 4 bytes */
1585                 SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1586
1587                 if (labels) {
1588                         /* num_labels 4 bytes */
1589                         SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1590                 }
1591
1592                 /* needed_data_count 4 bytes */
1593                 SIVAL(cur_pdata, 8, labels_data_count);
1594
1595                 cur_pdata += 12;
1596
1597                 DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1598                           shadow_data->num_volumes, fsp_str_dbg(fsp)));
1599                 if (labels && shadow_data->labels) {
1600                         for (i=0; i<shadow_data->num_volumes; i++) {
1601                                 size_t len = 0;
1602                                 status = srvstr_push(cur_pdata, req_flags,
1603                                             cur_pdata, shadow_data->labels[i],
1604                                             2 * sizeof(SHADOW_COPY_LABEL),
1605                                             STR_UNICODE|STR_TERMINATE, &len);
1606                                 if (!NT_STATUS_IS_OK(status)) {
1607                                         TALLOC_FREE(*out_data);
1608                                         TALLOC_FREE(shadow_data);
1609                                         return status;
1610                                 }
1611                                 cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1612                                 DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1613                         }
1614                 }
1615
1616                 TALLOC_FREE(shadow_data);
1617
1618                 return NT_STATUS_OK;
1619         }
1620
1621         case FSCTL_FIND_FILES_BY_SID:
1622         {
1623                 /* pretend this succeeded -
1624                  *
1625                  * we have to send back a list with all files owned by this SID
1626                  *
1627                  * but I have to check that --metze
1628                  */
1629                 ssize_t ret;
1630                 struct dom_sid sid;
1631                 struct dom_sid_buf buf;
1632                 uid_t uid;
1633                 size_t sid_len;
1634
1635                 DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1636                            fsp_fnum_dbg(fsp)));
1637
1638                 if (in_len < 8) {
1639                         /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1640                         return NT_STATUS_INVALID_PARAMETER;
1641                 }
1642
1643                 sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1644
1645                 /* unknown 4 bytes: this is not the length of the sid :-(  */
1646                 /*unknown = IVAL(pdata,0);*/
1647
1648                 ret = sid_parse(_in_data + 4, sid_len, &sid);
1649                 if (ret == -1) {
1650                         return NT_STATUS_INVALID_PARAMETER;
1651                 }
1652                 DEBUGADD(10, ("for SID: %s\n",
1653                               dom_sid_str_buf(&sid, &buf)));
1654
1655                 if (!sid_to_uid(&sid, &uid)) {
1656                         DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1657                                  dom_sid_str_buf(&sid, &buf),
1658                                  (unsigned long)sid_len));
1659                         uid = (-1);
1660                 }
1661
1662                 /* we can take a look at the find source :-)
1663                  *
1664                  * find ./ -uid $uid  -name '*'   is what we need here
1665                  *
1666                  *
1667                  * and send 4bytes len and then NULL terminated unicode strings
1668                  * for each file
1669                  *
1670                  * but I don't know how to deal with the paged results
1671                  * (maybe we can hang the result anywhere in the fsp struct)
1672                  *
1673                  * but I don't know how to deal with the paged results
1674                  * (maybe we can hang the result anywhere in the fsp struct)
1675                  *
1676                  * we don't send all files at once
1677                  * and at the next we should *not* start from the beginning,
1678                  * so we have to cache the result
1679                  *
1680                  * --metze
1681                  */
1682
1683                 /* this works for now... */
1684                 return NT_STATUS_OK;
1685         }
1686
1687         case FSCTL_QUERY_ALLOCATED_RANGES:
1688         {
1689                 /* FIXME: This is just a dummy reply, telling that all of the
1690                  * file is allocated. MKS cp needs that.
1691                  * Adding the real allocated ranges via FIEMAP on Linux
1692                  * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1693                  * this FSCTL correct for sparse files.
1694                  */
1695                 uint64_t offset, length;
1696                 char *out_data_tmp = NULL;
1697
1698                 if (in_len != 16) {
1699                         DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1700                                 in_len));
1701                         return NT_STATUS_INVALID_PARAMETER;
1702                 }
1703
1704                 if (max_out_len < 16) {
1705                         DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1706                                 max_out_len));
1707                         return NT_STATUS_INVALID_PARAMETER;
1708                 }
1709
1710                 offset = BVAL(in_data,0);
1711                 length = BVAL(in_data,8);
1712
1713                 if (offset + length < offset) {
1714                         /* No 64-bit integer wrap. */
1715                         return NT_STATUS_INVALID_PARAMETER;
1716                 }
1717
1718                 /* Shouldn't this be SMB_VFS_STAT ... ? */
1719                 status = vfs_stat_fsp(fsp);
1720                 if (!NT_STATUS_IS_OK(status)) {
1721                         return status;
1722                 }
1723
1724                 *out_len = 16;
1725                 out_data_tmp = talloc_array(ctx, char, *out_len);
1726                 if (out_data_tmp == NULL) {
1727                         DEBUG(10, ("unable to allocate memory for response\n"));
1728                         return NT_STATUS_NO_MEMORY;
1729                 }
1730
1731                 if (offset > fsp->fsp_name->st.st_ex_size ||
1732                                 fsp->fsp_name->st.st_ex_size == 0 ||
1733                                 length == 0) {
1734                         memset(out_data_tmp, 0, *out_len);
1735                 } else {
1736                         uint64_t end = offset + length;
1737                         end = MIN(end, fsp->fsp_name->st.st_ex_size);
1738                         SBVAL(out_data_tmp, 0, 0);
1739                         SBVAL(out_data_tmp, 8, end);
1740                 }
1741
1742                 *out_data = out_data_tmp;
1743
1744                 return NT_STATUS_OK;
1745         }
1746
1747         case FSCTL_IS_VOLUME_DIRTY:
1748         {
1749                 DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
1750                           "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
1751                 /*
1752                  * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1753                  * says we have to respond with NT_STATUS_INVALID_PARAMETER
1754                  */
1755                 return NT_STATUS_INVALID_PARAMETER;
1756         }
1757
1758         default:
1759                 /*
1760                  * Only print once ... unfortunately there could be lots of
1761                  * different FSCTLs that are called.
1762                  */
1763                 if (!vfswrap_logged_ioctl_message) {
1764                         vfswrap_logged_ioctl_message = true;
1765                         DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
1766                         __func__, function));
1767                 }
1768         }
1769
1770         return NT_STATUS_NOT_SUPPORTED;
1771 }
1772
1773 static bool vfswrap_is_offline(struct connection_struct *conn,
1774                                const struct smb_filename *fname);
1775
1776 struct vfswrap_get_dos_attributes_state {
1777         struct vfs_aio_state aio_state;
1778         connection_struct *conn;
1779         TALLOC_CTX *mem_ctx;
1780         struct tevent_context *ev;
1781         files_struct *dir_fsp;
1782         struct smb_filename *smb_fname;
1783         uint32_t dosmode;
1784         bool as_root;
1785 };
1786
1787 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1788
1789 static struct tevent_req *vfswrap_get_dos_attributes_send(
1790                         TALLOC_CTX *mem_ctx,
1791                         struct tevent_context *ev,
1792                         struct vfs_handle_struct *handle,
1793                         files_struct *dir_fsp,
1794                         struct smb_filename *smb_fname)
1795 {
1796         struct tevent_req *req = NULL;
1797         struct tevent_req *subreq = NULL;
1798         struct vfswrap_get_dos_attributes_state *state = NULL;
1799
1800         req = tevent_req_create(mem_ctx, &state,
1801                                 struct vfswrap_get_dos_attributes_state);
1802         if (req == NULL) {
1803                 return NULL;
1804         }
1805
1806         *state = (struct vfswrap_get_dos_attributes_state) {
1807                 .conn = dir_fsp->conn,
1808                 .mem_ctx = mem_ctx,
1809                 .ev = ev,
1810                 .dir_fsp = dir_fsp,
1811                 .smb_fname = smb_fname,
1812         };
1813
1814         if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1815                 DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1816                         "\"store dos attributes\" is disabled\n",
1817                         dir_fsp->conn->connectpath);
1818                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1819                 return tevent_req_post(req, ev);
1820         }
1821
1822         subreq = SMB_VFS_GETXATTRAT_SEND(state,
1823                                          ev,
1824                                          dir_fsp,
1825                                          smb_fname,
1826                                          SAMBA_XATTR_DOS_ATTRIB,
1827                                          sizeof(fstring));
1828         if (tevent_req_nomem(subreq, req)) {
1829                 return tevent_req_post(req, ev);
1830         }
1831         tevent_req_set_callback(subreq,
1832                                 vfswrap_get_dos_attributes_getxattr_done,
1833                                 req);
1834
1835         return req;
1836 }
1837
1838 static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1839 {
1840         struct tevent_req *req =
1841                 tevent_req_callback_data(subreq,
1842                 struct tevent_req);
1843         struct vfswrap_get_dos_attributes_state *state =
1844                 tevent_req_data(req,
1845                 struct vfswrap_get_dos_attributes_state);
1846         ssize_t xattr_size;
1847         DATA_BLOB blob = {0};
1848         char *path = NULL;
1849         char *tofree = NULL;
1850         char pathbuf[PATH_MAX+1];
1851         ssize_t pathlen;
1852         struct smb_filename smb_fname;
1853         bool offline;
1854         NTSTATUS status;
1855
1856         xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1857                                              &state->aio_state,
1858                                              state,
1859                                              &blob.data);
1860         TALLOC_FREE(subreq);
1861         if (xattr_size == -1) {
1862                 status = map_nt_error_from_unix(state->aio_state.error);
1863
1864                 if (state->as_root) {
1865                         tevent_req_nterror(req, status);
1866                         return;
1867                 }
1868                 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1869                         tevent_req_nterror(req, status);
1870                         return;
1871                 }
1872
1873                 state->as_root = true;
1874
1875                 become_root();
1876                 subreq = SMB_VFS_GETXATTRAT_SEND(state,
1877                                                  state->ev,
1878                                                  state->dir_fsp,
1879                                                  state->smb_fname,
1880                                                  SAMBA_XATTR_DOS_ATTRIB,
1881                                                  sizeof(fstring));
1882                 unbecome_root();
1883                 if (tevent_req_nomem(subreq, req)) {
1884                         return;
1885                 }
1886                 tevent_req_set_callback(subreq,
1887                                         vfswrap_get_dos_attributes_getxattr_done,
1888                                         req);
1889                 return;
1890         }
1891
1892         blob.length = xattr_size;
1893
1894         status = parse_dos_attribute_blob(state->smb_fname,
1895                                           blob,
1896                                           &state->dosmode);
1897         if (!NT_STATUS_IS_OK(status)) {
1898                 tevent_req_nterror(req, status);
1899                 return;
1900         }
1901
1902         pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1903                                 state->smb_fname->base_name,
1904                                 pathbuf,
1905                                 sizeof(pathbuf),
1906                                 &path,
1907                                 &tofree);
1908         if (pathlen == -1) {
1909                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1910                 return;
1911         }
1912
1913         smb_fname = (struct smb_filename) {
1914                 .base_name = path,
1915                 .st = state->smb_fname->st,
1916                 .flags = state->smb_fname->flags,
1917                 .twrp = state->smb_fname->twrp,
1918         };
1919
1920         offline = vfswrap_is_offline(state->conn, &smb_fname);
1921         if (offline) {
1922                 state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1923         }
1924         TALLOC_FREE(tofree);
1925
1926         tevent_req_done(req);
1927         return;
1928 }
1929
1930 static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1931                                                 struct vfs_aio_state *aio_state,
1932                                                 uint32_t *dosmode)
1933 {
1934         struct vfswrap_get_dos_attributes_state *state =
1935                 tevent_req_data(req,
1936                 struct vfswrap_get_dos_attributes_state);
1937         NTSTATUS status;
1938
1939         if (tevent_req_is_nterror(req, &status)) {
1940                 tevent_req_received(req);
1941                 return status;
1942         }
1943
1944         *aio_state = state->aio_state;
1945         *dosmode = state->dosmode;
1946         tevent_req_received(req);
1947         return NT_STATUS_OK;
1948 }
1949
1950 static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1951                                             struct files_struct *fsp,
1952                                             uint32_t *dosmode)
1953 {
1954         bool offline;
1955
1956         offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1957         if (offline) {
1958                 *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1959         }
1960
1961         return fget_ea_dos_attribute(fsp, dosmode);
1962 }
1963
1964 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1965                                             struct files_struct *fsp,
1966                                             uint32_t dosmode)
1967 {
1968         return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1969 }
1970
1971 static struct vfs_offload_ctx *vfswrap_offload_ctx;
1972
1973 struct vfswrap_offload_read_state {
1974         DATA_BLOB token;
1975 };
1976
1977 static struct tevent_req *vfswrap_offload_read_send(
1978         TALLOC_CTX *mem_ctx,
1979         struct tevent_context *ev,
1980         struct vfs_handle_struct *handle,
1981         struct files_struct *fsp,
1982         uint32_t fsctl,
1983         uint32_t ttl,
1984         off_t offset,
1985         size_t to_copy)
1986 {
1987         struct tevent_req *req = NULL;
1988         struct vfswrap_offload_read_state *state = NULL;
1989         NTSTATUS status;
1990
1991         req = tevent_req_create(mem_ctx, &state,
1992                                 struct vfswrap_offload_read_state);
1993         if (req == NULL) {
1994                 return NULL;
1995         }
1996
1997         status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
1998                                             &vfswrap_offload_ctx);
1999         if (tevent_req_nterror(req, status)) {
2000                 return tevent_req_post(req, ev);
2001         }
2002
2003         if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2004                 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2005                 return tevent_req_post(req, ev);
2006         }
2007
2008         status = vfs_offload_token_create_blob(state, fsp, fsctl,
2009                                                &state->token);
2010         if (tevent_req_nterror(req, status)) {
2011                 return tevent_req_post(req, ev);
2012         }
2013
2014         status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2015                                                 &state->token);
2016         if (tevent_req_nterror(req, status)) {
2017                 return tevent_req_post(req, ev);
2018         }
2019
2020         tevent_req_done(req);
2021         return tevent_req_post(req, ev);
2022 }
2023
2024 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2025                                           struct vfs_handle_struct *handle,
2026                                           TALLOC_CTX *mem_ctx,
2027                                           uint32_t *flags,
2028                                           uint64_t *xferlen,
2029                                           DATA_BLOB *token)
2030 {
2031         struct vfswrap_offload_read_state *state = tevent_req_data(
2032                 req, struct vfswrap_offload_read_state);
2033         NTSTATUS status;
2034
2035         if (tevent_req_is_nterror(req, &status)) {
2036                 tevent_req_received(req);
2037                 return status;
2038         }
2039
2040         *flags = 0;
2041         *xferlen = 0;
2042         token->length = state->token.length;
2043         token->data = talloc_move(mem_ctx, &state->token.data);
2044
2045         tevent_req_received(req);
2046         return NT_STATUS_OK;
2047 }
2048
2049 struct vfswrap_offload_write_state {
2050         uint8_t *buf;
2051         bool read_lck_locked;
2052         bool write_lck_locked;
2053         DATA_BLOB *token;
2054         struct tevent_context *src_ev;
2055         struct files_struct *src_fsp;
2056         off_t src_off;
2057         struct tevent_context *dst_ev;
2058         struct files_struct *dst_fsp;
2059         off_t dst_off;
2060         off_t to_copy;
2061         off_t remaining;
2062         off_t copied;
2063         size_t next_io_size;
2064 };
2065
2066 static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2067                                           enum tevent_req_state req_state)
2068 {
2069         struct vfswrap_offload_write_state *state = tevent_req_data(
2070                 req, struct vfswrap_offload_write_state);
2071         bool ok;
2072
2073         if (state->dst_fsp == NULL) {
2074                 return;
2075         }
2076
2077         ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2078         SMB_ASSERT(ok);
2079         state->dst_fsp = NULL;
2080 }
2081
2082 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2083 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2084
2085 static struct tevent_req *vfswrap_offload_write_send(
2086         struct vfs_handle_struct *handle,
2087         TALLOC_CTX *mem_ctx,
2088         struct tevent_context *ev,
2089         uint32_t fsctl,
2090         DATA_BLOB *token,
2091         off_t transfer_offset,
2092         struct files_struct *dest_fsp,
2093         off_t dest_off,
2094         off_t to_copy)
2095 {
2096         struct tevent_req *req;
2097         struct vfswrap_offload_write_state *state = NULL;
2098         /* off_t is signed! */
2099         off_t max_offset = INT64_MAX - to_copy;
2100         size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2101         files_struct *src_fsp = NULL;
2102         NTSTATUS status;
2103         bool ok;
2104
2105         req = tevent_req_create(mem_ctx, &state,
2106                                 struct vfswrap_offload_write_state);
2107         if (req == NULL) {
2108                 return NULL;
2109         }
2110
2111         *state = (struct vfswrap_offload_write_state) {
2112                 .token = token,
2113                 .src_off = transfer_offset,
2114                 .dst_ev = ev,
2115                 .dst_fsp = dest_fsp,
2116                 .dst_off = dest_off,
2117                 .to_copy = to_copy,
2118                 .remaining = to_copy,
2119         };
2120
2121         tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2122
2123         switch (fsctl) {
2124         case FSCTL_SRV_COPYCHUNK:
2125         case FSCTL_SRV_COPYCHUNK_WRITE:
2126                 break;
2127
2128         case FSCTL_OFFLOAD_WRITE:
2129                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2130                 return tevent_req_post(req, ev);
2131
2132         case FSCTL_DUP_EXTENTS_TO_FILE:
2133                 DBG_DEBUG("COW clones not supported by vfs_default\n");
2134                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2135                 return tevent_req_post(req, ev);
2136
2137         default:
2138                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2139                 return tevent_req_post(req, ev);
2140         }
2141
2142         /*
2143          * From here on we assume a copy-chunk fsctl
2144          */
2145
2146         if (to_copy == 0) {
2147                 tevent_req_done(req);
2148                 return tevent_req_post(req, ev);
2149         }
2150
2151         if (state->src_off > max_offset) {
2152                 /*
2153                  * Protect integer checks below.
2154                  */
2155                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2156                 return tevent_req_post(req, ev);
2157         }
2158         if (state->src_off < 0) {
2159                 /*
2160                  * Protect integer checks below.
2161                  */
2162                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2163                 return tevent_req_post(req, ev);
2164         }
2165         if (state->dst_off > max_offset) {
2166                 /*
2167                  * Protect integer checks below.
2168                  */
2169                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2170                 return tevent_req_post(req, ev);
2171         }
2172         if (state->dst_off < 0) {
2173                 /*
2174                  * Protect integer checks below.
2175                  */
2176                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2177                 return tevent_req_post(req, ev);
2178         }
2179
2180         status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2181                                                 token, &src_fsp);
2182         if (tevent_req_nterror(req, status)) {
2183                 return tevent_req_post(req, ev);
2184         }
2185
2186         DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2187
2188         status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2189         if (!NT_STATUS_IS_OK(status)) {
2190                 tevent_req_nterror(req, status);
2191                 return tevent_req_post(req, ev);
2192         }
2193
2194         ok = change_to_user_and_service_by_fsp(src_fsp);
2195         if (!ok) {
2196                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2197                 return tevent_req_post(req, ev);
2198         }
2199
2200         state->src_ev = src_fsp->conn->sconn->ev_ctx;
2201         state->src_fsp = src_fsp;
2202
2203         status = vfs_stat_fsp(src_fsp);
2204         if (tevent_req_nterror(req, status)) {
2205                 return tevent_req_post(req, ev);
2206         }
2207
2208         if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2209                 /*
2210                  * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2211                  *   If the SourceOffset or SourceOffset + Length extends beyond
2212                  *   the end of file, the server SHOULD<240> treat this as a
2213                  *   STATUS_END_OF_FILE error.
2214                  * ...
2215                  *   <240> Section 3.3.5.15.6: Windows servers will return
2216                  *   STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2217                  */
2218                 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2219                 return tevent_req_post(req, ev);
2220         }
2221
2222         status = vfswrap_offload_copy_file_range(req);
2223         if (NT_STATUS_IS_OK(status)) {
2224                 tevent_req_done(req);
2225                 return tevent_req_post(req, ev);
2226         }
2227         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2228                 tevent_req_nterror(req, status);
2229                 return tevent_req_post(req, ev);
2230         }
2231
2232         state->buf = talloc_array(state, uint8_t, num);
2233         if (tevent_req_nomem(state->buf, req)) {
2234                 return tevent_req_post(req, ev);
2235         }
2236
2237         status = vfswrap_offload_write_loop(req);
2238         if (!NT_STATUS_IS_OK(status)) {
2239                 tevent_req_nterror(req, status);
2240                 return tevent_req_post(req, ev);
2241         }
2242
2243         return req;
2244 }
2245
2246 static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2247 {
2248         struct vfswrap_offload_write_state *state = tevent_req_data(
2249                 req, struct vfswrap_offload_write_state);
2250         struct lock_struct lck;
2251         ssize_t nwritten;
2252         NTSTATUS status;
2253         bool same_file;
2254         bool ok;
2255         static bool try_copy_file_range = true;
2256
2257         if (!try_copy_file_range) {
2258                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2259         }
2260
2261         same_file = file_id_equal(&state->src_fsp->file_id,
2262                                   &state->dst_fsp->file_id);
2263         if (same_file &&
2264             sys_io_ranges_overlap(state->remaining,
2265                                   state->src_off,
2266                                   state->remaining,
2267                                   state->dst_off))
2268         {
2269                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2270         }
2271
2272         if (fsp_is_alternate_stream(state->src_fsp) ||
2273             fsp_is_alternate_stream(state->dst_fsp))
2274         {
2275                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2276         }
2277
2278         init_strict_lock_struct(state->src_fsp,
2279                                 state->src_fsp->op->global->open_persistent_id,
2280                                 state->src_off,
2281                                 state->remaining,
2282                                 READ_LOCK,
2283                                 lp_posix_cifsu_locktype(state->src_fsp),
2284                                 &lck);
2285
2286         ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2287                                  state->src_fsp,
2288                                  &lck);
2289         if (!ok) {
2290                 return NT_STATUS_FILE_LOCK_CONFLICT;
2291         }
2292
2293         ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2294         if (!ok) {
2295                 return NT_STATUS_INTERNAL_ERROR;
2296         }
2297
2298         init_strict_lock_struct(state->dst_fsp,
2299                                 state->dst_fsp->op->global->open_persistent_id,
2300                                 state->dst_off,
2301                                 state->remaining,
2302                                 WRITE_LOCK,
2303                                 lp_posix_cifsu_locktype(state->dst_fsp),
2304                                 &lck);
2305
2306         ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2307                                        state->dst_fsp,
2308                                        &lck);
2309         if (!ok) {
2310                 return NT_STATUS_FILE_LOCK_CONFLICT;
2311         }
2312
2313         while (state->remaining > 0) {
2314                 nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2315                                            &state->src_off,
2316                                            fsp_get_io_fd(state->dst_fsp),
2317                                            &state->dst_off,
2318                                            state->remaining,
2319                                            0);
2320                 if (nwritten == -1) {
2321                         DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2322                                   "n [%jd] failed: %s\n",
2323                                   fsp_str_dbg(state->src_fsp),
2324                                   (intmax_t)state->src_off,
2325                                   fsp_str_dbg(state->dst_fsp),
2326                                   (intmax_t)state->dst_off,
2327                                   (intmax_t)state->remaining,
2328                                   strerror(errno));
2329                         switch (errno) {
2330                         case EOPNOTSUPP:
2331                         case ENOSYS:
2332                                 try_copy_file_range = false;
2333                                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2334                                 break;
2335                         case EXDEV:
2336                                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2337                                 break;
2338                         default:
2339                                 status = map_nt_error_from_unix(errno);
2340                                 if (NT_STATUS_EQUAL(
2341                                             status,
2342                                             NT_STATUS_MORE_PROCESSING_REQUIRED))
2343                                 {
2344                                         /* Avoid triggering the fallback */
2345                                         status = NT_STATUS_INTERNAL_ERROR;
2346                                 }
2347                                 break;
2348                         }
2349                         return status;
2350                 }
2351
2352                 if (state->remaining < nwritten) {
2353                         DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2354                                   "n [%jd] remaining [%jd]\n",
2355                                   fsp_str_dbg(state->src_fsp),
2356                                   fsp_str_dbg(state->dst_fsp),
2357                                   (intmax_t)nwritten,
2358                                   (intmax_t)state->remaining);
2359                         return NT_STATUS_INTERNAL_ERROR;
2360                 }
2361
2362                 if (nwritten == 0) {
2363                         break;
2364                 }
2365                 state->copied += nwritten;
2366                 state->remaining -= nwritten;
2367         }
2368
2369         /*
2370          * Tell the req cleanup function there's no need to call
2371          * change_to_user_and_service_by_fsp() on the dst handle.
2372          */
2373         state->dst_fsp = NULL;
2374         return NT_STATUS_OK;
2375 }
2376
2377 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2378
2379 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2380 {
2381         struct vfswrap_offload_write_state *state = tevent_req_data(
2382                 req, struct vfswrap_offload_write_state);
2383         struct tevent_req *subreq = NULL;
2384         struct lock_struct read_lck;
2385         bool ok;
2386
2387         /*
2388          * This is called under the context of state->src_fsp.
2389          */
2390
2391         state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2392
2393         init_strict_lock_struct(state->src_fsp,
2394                                 state->src_fsp->op->global->open_persistent_id,
2395                                 state->src_off,
2396                                 state->next_io_size,
2397                                 READ_LOCK,
2398                                 lp_posix_cifsu_locktype(state->src_fsp),
2399                                 &read_lck);
2400
2401         ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2402                                  state->src_fsp,
2403                                  &read_lck);
2404         if (!ok) {
2405                 return NT_STATUS_FILE_LOCK_CONFLICT;
2406         }
2407
2408         subreq = SMB_VFS_PREAD_SEND(state,
2409                                     state->src_ev,
2410                                     state->src_fsp,
2411                                     state->buf,
2412                                     state->next_io_size,
2413                                     state->src_off);
2414         if (subreq == NULL) {
2415                 return NT_STATUS_NO_MEMORY;
2416         }
2417         tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2418
2419         return NT_STATUS_OK;
2420 }
2421
2422 static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2423
2424 static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2425 {
2426         struct tevent_req *req = tevent_req_callback_data(
2427                 subreq, struct tevent_req);
2428         struct vfswrap_offload_write_state *state = tevent_req_data(
2429                 req, struct vfswrap_offload_write_state);
2430         struct vfs_aio_state aio_state;
2431         struct lock_struct write_lck;
2432         ssize_t nread;
2433         bool ok;
2434
2435         nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2436         TALLOC_FREE(subreq);
2437         if (nread == -1) {
2438                 DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2439                 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2440                 return;
2441         }
2442         if (nread != state->next_io_size) {
2443                 DBG_ERR("Short read, only %zd of %zu\n",
2444                         nread, state->next_io_size);
2445                 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2446                 return;
2447         }
2448
2449         state->src_off += nread;
2450
2451         ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2452         if (!ok) {
2453                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2454                 return;
2455         }
2456
2457         init_strict_lock_struct(state->dst_fsp,
2458                                 state->dst_fsp->op->global->open_persistent_id,
2459                                 state->dst_off,
2460                                 state->next_io_size,
2461                                 WRITE_LOCK,
2462                                 lp_posix_cifsu_locktype(state->dst_fsp),
2463                                 &write_lck);
2464
2465         ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2466                                  state->dst_fsp,
2467                                  &write_lck);
2468         if (!ok) {
2469                 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2470                 return;
2471         }
2472
2473         subreq = SMB_VFS_PWRITE_SEND(state,
2474                                      state->dst_ev,
2475                                      state->dst_fsp,
2476                                      state->buf,
2477                                      state->next_io_size,
2478                                      state->dst_off);
2479         if (subreq == NULL) {
2480                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2481                 return;
2482         }
2483         tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2484 }
2485
2486 static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2487 {
2488         struct tevent_req *req = tevent_req_callback_data(
2489                 subreq, struct tevent_req);
2490         struct vfswrap_offload_write_state *state = tevent_req_data(
2491                 req, struct vfswrap_offload_write_state);
2492         struct vfs_aio_state aio_state;
2493         ssize_t nwritten;
2494         NTSTATUS status;
2495         bool ok;
2496
2497         nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2498         TALLOC_FREE(subreq);
2499         if (nwritten == -1) {
2500                 DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2501                 tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2502                 return;
2503         }
2504         if (nwritten != state->next_io_size) {
2505                 DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2506                 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2507                 return;
2508         }
2509
2510         state->dst_off += nwritten;
2511
2512         if (state->remaining < nwritten) {
2513                 /* Paranoia check */
2514                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2515                 return;
2516         }
2517         state->copied += nwritten;
2518         state->remaining -= nwritten;
2519         if (state->remaining == 0) {
2520                 tevent_req_done(req);
2521                 return;
2522         }
2523
2524         ok = change_to_user_and_service_by_fsp(state->src_fsp);
2525         if (!ok) {
2526                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2527                 return;
2528         }
2529
2530         status = vfswrap_offload_write_loop(req);
2531         if (!NT_STATUS_IS_OK(status)) {
2532                 tevent_req_nterror(req, status);
2533                 return;
2534         }
2535
2536         return;
2537 }
2538
2539 static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2540                                         struct tevent_req *req,
2541                                         off_t *copied)
2542 {
2543         struct vfswrap_offload_write_state *state = tevent_req_data(
2544                 req, struct vfswrap_offload_write_state);
2545         NTSTATUS status;
2546
2547         if (tevent_req_is_nterror(req, &status)) {
2548                 DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2549                 *copied = 0;
2550                 tevent_req_received(req);
2551                 return status;
2552         }
2553
2554         *copied = state->copied;
2555         DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2556         tevent_req_received(req);
2557
2558         return NT_STATUS_OK;
2559 }
2560
2561 static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2562                                         TALLOC_CTX *mem_ctx,
2563                                         struct files_struct *fsp,
2564                                         uint16_t *_compression_fmt)
2565 {
2566         return NT_STATUS_INVALID_DEVICE_REQUEST;
2567 }
2568
2569 static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2570                                         TALLOC_CTX *mem_ctx,
2571                                         struct files_struct *fsp,
2572                                         uint16_t compression_fmt)
2573 {
2574         return NT_STATUS_INVALID_DEVICE_REQUEST;
2575 }
2576
2577 /********************************************************************
2578  Given a stat buffer return the allocated size on disk, taking into
2579  account sparse files.
2580 ********************************************************************/
2581 static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2582                                        struct files_struct *fsp,
2583                                        const SMB_STRUCT_STAT *sbuf)
2584 {
2585         uint64_t result;
2586
2587         START_PROFILE(syscall_get_alloc_size);
2588
2589         if(S_ISDIR(sbuf->st_ex_mode)) {
2590                 result = 0;
2591                 goto out;
2592         }
2593
2594 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2595         /* The type of st_blocksize is blkcnt_t which *MUST* be
2596            signed (according to POSIX) and can be less than 64-bits.
2597            Ensure when we're converting to 64 bits wide we don't
2598            sign extend. */
2599 #if defined(SIZEOF_BLKCNT_T_8)
2600         result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2601 #elif defined(SIZEOF_BLKCNT_T_4)
2602         {
2603                 uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2604                 result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2605         }
2606 #else
2607 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2608 #endif
2609         if (result == 0) {
2610                 /*
2611                  * Some file systems do not allocate a block for very
2612                  * small files. But for non-empty file should report a
2613                  * positive size.
2614                  */
2615
2616                 uint64_t filesize = get_file_size_stat(sbuf);
2617                 if (filesize > 0) {
2618                         result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2619                 }
2620         }
2621 #else
2622         result = get_file_size_stat(sbuf);
2623 #endif
2624
2625         if (fsp && fsp->initial_allocation_size)
2626                 result = MAX(result,fsp->initial_allocation_size);
2627
2628         result = smb_roundup(handle->conn, result);
2629
2630  out:
2631         END_PROFILE(syscall_get_alloc_size);
2632         return result;
2633 }
2634
2635 static int vfswrap_unlinkat(vfs_handle_struct *handle,
2636                         struct files_struct *dirfsp,
2637                         const struct smb_filename *smb_fname,
2638                         int flags)
2639 {
2640         int result = -1;
2641
2642         START_PROFILE(syscall_unlinkat);
2643
2644         if (is_named_stream(smb_fname)) {
2645                 errno = ENOENT;
2646                 goto out;
2647         }
2648         result = unlinkat(fsp_get_pathref_fd(dirfsp),
2649                         smb_fname->base_name,
2650                         flags);
2651
2652  out:
2653         END_PROFILE(syscall_unlinkat);
2654         return result;
2655 }
2656
2657 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2658 {
2659         int result;
2660
2661         START_PROFILE(syscall_fchmod);
2662
2663         if (!fsp->fsp_flags.is_pathref) {
2664                 result = fchmod(fsp_get_io_fd(fsp), mode);
2665                 END_PROFILE(syscall_fchmod);
2666                 return result;
2667         }
2668
2669         if (fsp->fsp_flags.have_proc_fds) {
2670                 int fd = fsp_get_pathref_fd(fsp);
2671                 const char *p = NULL;
2672                 char buf[PATH_MAX];
2673
2674                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2675                 if (p != NULL) {
2676                         result = chmod(p, mode);
2677                 } else {
2678                         result = -1;
2679                 }
2680                 END_PROFILE(syscall_fchmod);
2681                 return result;
2682         }
2683
2684         /*
2685          * This is no longer a handle based call.
2686          */
2687         result = chmod(fsp->fsp_name->base_name, mode);
2688
2689         END_PROFILE(syscall_fchmod);
2690         return result;
2691 }
2692
2693 static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2694 {
2695 #ifdef HAVE_FCHOWN
2696         int result;
2697
2698         START_PROFILE(syscall_fchown);
2699         if (!fsp->fsp_flags.is_pathref) {
2700                 result = fchown(fsp_get_io_fd(fsp), uid, gid);
2701                 END_PROFILE(syscall_fchown);
2702                 return result;
2703         }
2704
2705         if (fsp->fsp_flags.have_proc_fds) {
2706                 int fd = fsp_get_pathref_fd(fsp);
2707                 const char *p = NULL;
2708                 char buf[PATH_MAX];
2709
2710                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2711                 if (p != NULL) {
2712                         result = chown(p, uid, gid);
2713                 } else {
2714                         result = -1;
2715                 }
2716                 END_PROFILE(syscall_fchown);
2717                 return result;
2718         }
2719
2720         /*
2721          * This is no longer a handle based call.
2722          */
2723         result = chown(fsp->fsp_name->base_name, uid, gid);
2724         END_PROFILE(syscall_fchown);
2725         return result;
2726 #else
2727         errno = ENOSYS;
2728         return -1;
2729 #endif
2730 }
2731
2732 static int vfswrap_lchown(vfs_handle_struct *handle,
2733                         const struct smb_filename *smb_fname,
2734                         uid_t uid,
2735                         gid_t gid)
2736 {
2737         int result;
2738
2739         START_PROFILE(syscall_lchown);
2740         result = lchown(smb_fname->base_name, uid, gid);
2741         END_PROFILE(syscall_lchown);
2742         return result;
2743 }
2744
2745 static int vfswrap_chdir(vfs_handle_struct *handle,
2746                         const struct smb_filename *smb_fname)
2747 {
2748         int result;
2749
2750         START_PROFILE(syscall_chdir);
2751         result = chdir(smb_fname->base_name);
2752         END_PROFILE(syscall_chdir);
2753         return result;
2754 }
2755
2756 static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2757                                 TALLOC_CTX *ctx)
2758 {
2759         char *result;
2760         struct smb_filename *smb_fname = NULL;
2761
2762         START_PROFILE(syscall_getwd);
2763         result = sys_getwd();
2764         END_PROFILE(syscall_getwd);
2765
2766         if (result == NULL) {
2767                 return NULL;
2768         }
2769         smb_fname = synthetic_smb_fname(ctx,
2770                                 result,
2771                                 NULL,
2772                                 NULL,
2773                                 0,
2774                                 0);
2775         /*
2776          * sys_getwd() *always* returns malloced memory.
2777          * We must free here to avoid leaks:
2778          * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2779          */
2780         SAFE_FREE(result);
2781         return smb_fname;
2782 }
2783
2784 /*********************************************************************
2785  nsec timestamp resolution call. Convert down to whatever the underlying
2786  system will support.
2787 **********************************************************************/
2788
2789 static int vfswrap_fntimes(vfs_handle_struct *handle,
2790                            files_struct *fsp,
2791                            struct smb_file_time *ft)
2792 {
2793         int result = -1;
2794         struct timespec ts[2];
2795         struct timespec *times = NULL;
2796
2797         START_PROFILE(syscall_fntimes);
2798
2799         if (fsp_is_alternate_stream(fsp)) {
2800                 errno = ENOENT;
2801                 goto out;
2802         }
2803
2804         if (ft != NULL) {
2805                 if (is_omit_timespec(&ft->atime)) {
2806                         ft->atime = fsp->fsp_name->st.st_ex_atime;
2807                 }
2808
2809                 if (is_omit_timespec(&ft->mtime)) {
2810                         ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2811                 }
2812
2813                 if (!is_omit_timespec(&ft->create_time)) {
2814                         set_create_timespec_ea(fsp,
2815                                                ft->create_time);
2816                 }
2817
2818                 if ((timespec_compare(&ft->atime,
2819                                       &fsp->fsp_name->st.st_ex_atime) == 0) &&
2820                     (timespec_compare(&ft->mtime,
2821                                       &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2822                         result = 0;
2823                         goto out;
2824                 }
2825
2826                 ts[0] = ft->atime;
2827                 ts[1] = ft->mtime;
2828                 times = ts;
2829         } else {
2830                 times = NULL;
2831         }
2832
2833         if (!fsp->fsp_flags.is_pathref) {
2834                 result = futimens(fsp_get_io_fd(fsp), times);
2835                 goto out;
2836         }
2837
2838         if (fsp->fsp_flags.have_proc_fds) {
2839                 int fd = fsp_get_pathref_fd(fsp);
2840                 const char *p = NULL;
2841                 char buf[PATH_MAX];
2842
2843                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
2844                 if (p != NULL) {
2845                         /*
2846                          * The dirfd argument of utimensat is ignored when
2847                          * pathname is an absolute path
2848                          */
2849                         result = utimensat(AT_FDCWD, p, times, 0);
2850                 } else {
2851                         result = -1;
2852                 }
2853
2854                 goto out;
2855         }
2856
2857         /*
2858          * The fd is a pathref (opened with O_PATH) and there isn't fd to
2859          * path translation mechanism. Fallback to path based call.
2860          */
2861         result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2862
2863 out:
2864         END_PROFILE(syscall_fntimes);
2865
2866         return result;
2867 }
2868
2869
2870 /*********************************************************************
2871  A version of ftruncate that will write the space on disk if strict
2872  allocate is set.
2873 **********************************************************************/
2874
2875 static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2876 {
2877         off_t space_to_write;
2878         uint64_t space_avail;
2879         uint64_t bsize,dfree,dsize;
2880         int ret;
2881         NTSTATUS status;
2882         SMB_STRUCT_STAT *pst;
2883         bool ok;
2884
2885         ok = vfs_valid_pwrite_range(len, 0);
2886         if (!ok) {
2887                 errno = EINVAL;
2888                 return -1;
2889         }
2890
2891         status = vfs_stat_fsp(fsp);
2892         if (!NT_STATUS_IS_OK(status)) {
2893                 return -1;
2894         }
2895         pst = &fsp->fsp_name->st;
2896
2897 #ifdef S_ISFIFO
2898         if (S_ISFIFO(pst->st_ex_mode))
2899                 return 0;
2900 #endif
2901
2902         if (pst->st_ex_size == len)
2903                 return 0;
2904
2905         /* Shrink - just ftruncate. */
2906         if (pst->st_ex_size > len)
2907                 return ftruncate(fsp_get_io_fd(fsp), len);
2908
2909         space_to_write = len - pst->st_ex_size;
2910
2911         /* for allocation try fallocate first. This can fail on some
2912            platforms e.g. when the filesystem doesn't support it and no
2913            emulation is being done by the libc (like on AIX with JFS1). In that
2914            case we do our own emulation. fallocate implementations can
2915            return ENOTSUP or EINVAL in cases like that. */
2916         ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2917         if (ret == -1 && errno == ENOSPC) {
2918                 return -1;
2919         }
2920         if (ret == 0) {
2921                 return 0;
2922         }
2923         DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2924                 "error %d. Falling back to slow manual allocation\n", errno));
2925
2926         /* available disk space is enough or not? */
2927         space_avail =
2928             get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2929         /* space_avail is 1k blocks */
2930         if (space_avail == (uint64_t)-1 ||
2931                         ((uint64_t)space_to_write/1024 > space_avail) ) {
2932                 errno = ENOSPC;
2933                 return -1;
2934         }
2935
2936         /* Write out the real space on disk. */
2937         ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2938         if (ret != 0) {
2939                 return -1;
2940         }
2941
2942         return 0;
2943 }
2944
2945 static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2946 {
2947         int result = -1;
2948         SMB_STRUCT_STAT *pst;
2949         NTSTATUS status;
2950         char c = 0;
2951
2952         START_PROFILE(syscall_ftruncate);
2953
2954         if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2955                 result = strict_allocate_ftruncate(handle, fsp, len);
2956                 END_PROFILE(syscall_ftruncate);
2957                 return result;
2958         }
2959
2960         /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2961            ftruncate if the system supports it. Then I discovered that
2962            you can have some filesystems that support ftruncate
2963            expansion and some that don't! On Linux fat can't do
2964            ftruncate extend but ext2 can. */
2965
2966         result = ftruncate(fsp_get_io_fd(fsp), len);
2967
2968         /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2969            extend a file with ftruncate. Provide alternate implementation
2970            for this */
2971
2972         /* Do an fstat to see if the file is longer than the requested
2973            size in which case the ftruncate above should have
2974            succeeded or shorter, in which case seek to len - 1 and
2975            write 1 byte of zero */
2976         status = vfs_stat_fsp(fsp);
2977         if (!NT_STATUS_IS_OK(status)) {
2978                 goto done;
2979         }
2980
2981         /* We need to update the files_struct after successful ftruncate */
2982         if (result == 0) {
2983                 goto done;
2984         }
2985
2986         pst = &fsp->fsp_name->st;
2987
2988 #ifdef S_ISFIFO
2989         if (S_ISFIFO(pst->st_ex_mode)) {
2990                 result = 0;
2991                 goto done;
2992         }
2993 #endif
2994
2995         if (pst->st_ex_size == len) {
2996                 result = 0;
2997                 goto done;
2998         }
2999
3000         if (pst->st_ex_size > len) {
3001                 /* the ftruncate should have worked */
3002                 goto done;
3003         }
3004
3005         if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3006                 goto done;
3007         }
3008
3009         result = 0;
3010
3011   done:
3012
3013         END_PROFILE(syscall_ftruncate);
3014         return result;
3015 }
3016
3017 static int vfswrap_fallocate(vfs_handle_struct *handle,
3018                         files_struct *fsp,
3019                         uint32_t mode,
3020                         off_t offset,
3021                         off_t len)
3022 {
3023         int result;
3024
3025         START_PROFILE(syscall_fallocate);
3026         if (mode == 0) {
3027                 result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3028                 /*
3029                  * posix_fallocate returns 0 on success, errno on error
3030                  * and doesn't set errno. Make it behave like fallocate()
3031                  * which returns -1, and sets errno on failure.
3032                  */
3033                 if (result != 0) {
3034                         errno = result;
3035                         result = -1;
3036                 }
3037         } else {
3038                 /* sys_fallocate handles filtering of unsupported mode flags */
3039                 result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3040         }
3041         END_PROFILE(syscall_fallocate);
3042         return result;
3043 }
3044
3045 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3046 {
3047         bool result;
3048
3049         START_PROFILE(syscall_fcntl_lock);
3050
3051         if (fsp->fsp_flags.use_ofd_locks) {
3052                 op = map_process_lock_to_ofd_lock(op);
3053         }
3054
3055         result =  fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3056         END_PROFILE(syscall_fcntl_lock);
3057         return result;
3058 }
3059
3060 static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3061                                         files_struct *fsp,
3062                                         uint32_t share_access,
3063                                         uint32_t access_mask)
3064 {
3065         errno = ENOTSUP;
3066         return -1;
3067 }
3068
3069 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3070                          va_list cmd_arg)
3071 {
3072         void *argp;
3073         va_list dup_cmd_arg;
3074         int result;
3075         int val;
3076
3077         START_PROFILE(syscall_fcntl);
3078
3079         va_copy(dup_cmd_arg, cmd_arg);
3080
3081         switch(cmd) {
3082         case F_SETLK:
3083         case F_SETLKW:
3084         case F_GETLK:
3085 #if defined(HAVE_OFD_LOCKS)
3086         case F_OFD_SETLK:
3087         case F_OFD_SETLKW:
3088         case F_OFD_GETLK:
3089 #endif
3090 #if defined(HAVE_F_OWNER_EX)
3091         case F_GETOWN_EX:
3092         case F_SETOWN_EX:
3093 #endif
3094 #if defined(HAVE_RW_HINTS)
3095         case F_GET_RW_HINT:
3096         case F_SET_RW_HINT:
3097         case F_GET_FILE_RW_HINT:
3098         case F_SET_FILE_RW_HINT:
3099 #endif
3100                 argp = va_arg(dup_cmd_arg, void *);
3101                 result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3102                 break;
3103         default:
3104                 val = va_arg(dup_cmd_arg, int);
3105                 result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3106         }
3107
3108         va_end(dup_cmd_arg);
3109
3110         END_PROFILE(syscall_fcntl);
3111         return result;
3112 }
3113
3114 static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3115 {
3116         bool result;
3117         int op = F_GETLK;
3118
3119         START_PROFILE(syscall_fcntl_getlock);
3120
3121         if (fsp->fsp_flags.use_ofd_locks) {
3122                 op = map_process_lock_to_ofd_lock(op);
3123         }
3124
3125         result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3126         END_PROFILE(syscall_fcntl_getlock);
3127         return result;
3128 }
3129
3130 static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3131                                 int leasetype)
3132 {
3133         int result = -1;
3134
3135         START_PROFILE(syscall_linux_setlease);
3136
3137 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3138         result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3139 #else
3140         errno = ENOSYS;
3141 #endif
3142         END_PROFILE(syscall_linux_setlease);
3143         return result;
3144 }
3145
3146 static int vfswrap_symlinkat(vfs_handle_struct *handle,
3147                         const struct smb_filename *link_target,
3148                         struct files_struct *dirfsp,
3149                         const struct smb_filename *new_smb_fname)
3150 {
3151         int result;
3152
3153         START_PROFILE(syscall_symlinkat);
3154
3155         result = symlinkat(link_target->base_name,
3156                         fsp_get_pathref_fd(dirfsp),
3157                         new_smb_fname->base_name);
3158         END_PROFILE(syscall_symlinkat);
3159         return result;
3160 }
3161
3162 static int vfswrap_readlinkat(vfs_handle_struct *handle,
3163                         const struct files_struct *dirfsp,
3164                         const struct smb_filename *smb_fname,
3165                         char *buf,
3166                         size_t bufsiz)
3167 {
3168         int result;
3169
3170         START_PROFILE(syscall_readlinkat);
3171
3172         result = readlinkat(fsp_get_pathref_fd(dirfsp),
3173                         smb_fname->base_name,
3174                         buf,
3175                         bufsiz);
3176
3177         END_PROFILE(syscall_readlinkat);
3178         return result;
3179 }
3180
3181 static int vfswrap_linkat(vfs_handle_struct *handle,
3182                         files_struct *srcfsp,
3183                         const struct smb_filename *old_smb_fname,
3184                         files_struct *dstfsp,
3185                         const struct smb_filename *new_smb_fname,
3186                         int flags)
3187 {
3188         int result;
3189
3190         START_PROFILE(syscall_linkat);
3191
3192         result = linkat(fsp_get_pathref_fd(srcfsp),
3193                         old_smb_fname->base_name,
3194                         fsp_get_pathref_fd(dstfsp),
3195                         new_smb_fname->base_name,
3196                         flags);
3197
3198         END_PROFILE(syscall_linkat);
3199         return result;
3200 }
3201
3202 static int vfswrap_mknodat(vfs_handle_struct *handle,
3203                         files_struct *dirfsp,
3204                         const struct smb_filename *smb_fname,
3205                         mode_t mode,
3206                         SMB_DEV_T dev)
3207 {
3208         int result;
3209
3210         START_PROFILE(syscall_mknodat);
3211
3212         result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3213                         smb_fname->base_name,
3214                         mode,
3215                         dev);
3216
3217         END_PROFILE(syscall_mknodat);
3218         return result;
3219 }
3220
3221 static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3222                         TALLOC_CTX *ctx,
3223                         const struct smb_filename *smb_fname)
3224 {
3225         char *result;
3226         struct smb_filename *result_fname = NULL;
3227
3228         START_PROFILE(syscall_realpath);
3229         result = sys_realpath(smb_fname->base_name);
3230         END_PROFILE(syscall_realpath);
3231         if (result) {
3232                 result_fname = synthetic_smb_fname(ctx,
3233                                                    result,
3234                                                    NULL,
3235                                                    NULL,
3236                                                    0,
3237                                                    0);
3238                 SAFE_FREE(result);
3239         }
3240         return result_fname;
3241 }
3242
3243 static int vfswrap_fchflags(vfs_handle_struct *handle,
3244                         struct files_struct *fsp,
3245                         unsigned int flags)
3246 {
3247 #ifdef HAVE_FCHFLAGS
3248         int fd = fsp_get_pathref_fd(fsp);
3249
3250         if (!fsp->fsp_flags.is_pathref) {
3251                 return fchflags(fd, flags);
3252         }
3253
3254         if (fsp->fsp_flags.have_proc_fds) {
3255                 const char *p = NULL;
3256                 char buf[PATH_MAX];
3257
3258                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3259                 if (p == NULL) {
3260                         return -1;
3261                 }
3262
3263                 return chflags(p, flags);
3264         }
3265
3266         /*
3267          * This is no longer a handle based call.
3268          */
3269         return chflags(fsp->fsp_name->base_name, flags);
3270 #else
3271         errno = ENOSYS;
3272         return -1;
3273 #endif
3274 }
3275
3276 static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3277                                              const SMB_STRUCT_STAT *sbuf)
3278 {
3279         struct file_id key;
3280
3281         /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3282          * blob */
3283         ZERO_STRUCT(key);
3284
3285         key.devid = sbuf->st_ex_dev;
3286         key.inode = sbuf->st_ex_ino;
3287         /* key.extid is unused by default. */
3288
3289         return key;
3290 }
3291
3292 static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3293                                    const SMB_STRUCT_STAT *psbuf)
3294 {
3295         uint64_t file_id;
3296
3297         if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
3298                 return psbuf->st_ex_file_id;
3299         }
3300
3301         if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3302                 return (uint64_t)psbuf->st_ex_ino;
3303         }
3304
3305         /* FileIDLow */
3306         file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3307
3308         /* FileIDHigh */
3309         file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3310
3311         return file_id;
3312 }
3313
3314 static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3315                                    struct files_struct *fsp,
3316                                    TALLOC_CTX *mem_ctx,
3317                                    unsigned int *pnum_streams,
3318                                    struct stream_struct **pstreams)
3319 {
3320         struct stream_struct *tmp_streams = NULL;
3321         unsigned int num_streams = *pnum_streams;
3322         struct stream_struct *streams = *pstreams;
3323         NTSTATUS status;
3324
3325         if (fsp->fsp_flags.is_directory) {
3326                 /*
3327                  * No default streams on directories
3328                  */
3329                 goto done;
3330         }
3331         status = vfs_stat_fsp(fsp);
3332         if (!NT_STATUS_IS_OK(status)) {
3333                 return status;
3334         }
3335
3336         if (num_streams + 1 < 1) {
3337                 /* Integer wrap. */
3338                 return NT_STATUS_INVALID_PARAMETER;
3339         }
3340
3341         tmp_streams = talloc_realloc(mem_ctx,
3342                                         streams,
3343                                         struct stream_struct,
3344                                         num_streams + 1);
3345         if (tmp_streams == NULL) {
3346                 return NT_STATUS_NO_MEMORY;
3347         }
3348         tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3349         if (tmp_streams[num_streams].name == NULL) {
3350                 return NT_STATUS_NO_MEMORY;
3351         }
3352         tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3353         tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3354                                                 handle->conn,
3355                                                 fsp,
3356                                                 &fsp->fsp_name->st);
3357         num_streams += 1;
3358
3359         *pnum_streams = num_streams;
3360         *pstreams = tmp_streams;
3361  done:
3362         return NT_STATUS_OK;
3363 }
3364
3365 static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
3366                                      const struct smb_filename *path,
3367                                      const char *name,
3368                                      TALLOC_CTX *mem_ctx,
3369                                      char **found_name)
3370 {
3371         /*
3372          * Don't fall back to get_real_filename so callers can differentiate
3373          * between a full directory scan and an actual case-insensitive stat.
3374          */
3375         errno = EOPNOTSUPP;
3376         return -1;
3377 }
3378
3379 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3380                                    const struct smb_filename *smb_fname)
3381 {
3382         return handle->conn->connectpath;
3383 }
3384
3385 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3386                                          struct byte_range_lock *br_lck,
3387                                          struct lock_struct *plock)
3388 {
3389         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3390
3391         /* Note: blr is not used in the default implementation. */
3392         return brl_lock_windows_default(br_lck, plock);
3393 }
3394
3395 static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3396                                        struct byte_range_lock *br_lck,
3397                                        const struct lock_struct *plock)
3398 {
3399         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3400
3401         return brl_unlock_windows_default(br_lck, plock);
3402 }
3403
3404 static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3405                                       files_struct *fsp,
3406                                       struct lock_struct *plock)
3407 {
3408         SMB_ASSERT(plock->lock_type == READ_LOCK ||
3409             plock->lock_type == WRITE_LOCK);
3410
3411         return strict_lock_check_default(fsp, plock);
3412 }
3413
3414 /* NT ACL operations. */
3415
3416 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3417                                     files_struct *fsp,
3418                                     uint32_t security_info,
3419                                     TALLOC_CTX *mem_ctx,
3420                                     struct security_descriptor **ppdesc)
3421 {
3422         NTSTATUS result;
3423
3424         START_PROFILE(fget_nt_acl);
3425         result = posix_fget_nt_acl(fsp, security_info,
3426                                    mem_ctx, ppdesc);
3427         END_PROFILE(fget_nt_acl);
3428         return result;
3429 }
3430
3431 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3432 {
3433         NTSTATUS result;
3434
3435         START_PROFILE(fset_nt_acl);
3436         result = set_nt_acl(fsp, security_info_sent, psd);
3437         END_PROFILE(fset_nt_acl);
3438         return result;
3439 }
3440
3441 static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3442                                    struct smb_filename *file,
3443                                    struct security_acl *sacl,
3444                                    uint32_t access_requested,
3445                                    uint32_t access_denied)
3446 {
3447         return NT_STATUS_OK; /* Nothing to do here ... */
3448 }
3449
3450 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3451                                         files_struct *fsp,
3452                                         SMB_ACL_TYPE_T type,
3453                                         TALLOC_CTX *mem_ctx)
3454 {
3455         return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3456 }
3457
3458 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3459                                   files_struct *fsp,
3460                                   SMB_ACL_TYPE_T type,
3461                                   SMB_ACL_T theacl)
3462 {
3463         return sys_acl_set_fd(handle, fsp, type, theacl);
3464 }
3465
3466 static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3467                                          files_struct *fsp)
3468 {
3469         return sys_acl_delete_def_fd(handle, fsp);
3470 }
3471
3472 /****************************************************************
3473  Extended attribute operations.
3474 *****************************************************************/
3475
3476 static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3477                                  struct files_struct *fsp,
3478                                  const char *name,
3479                                  void *value,
3480                                  size_t size)
3481 {
3482         int fd = fsp_get_pathref_fd(fsp);
3483
3484         if (!fsp->fsp_flags.is_pathref) {
3485                 return fgetxattr(fd, name, value, size);
3486         }
3487
3488         if (fsp->fsp_flags.have_proc_fds) {
3489                 const char *p = NULL;
3490                 char buf[PATH_MAX];
3491
3492                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3493                 if (p == NULL) {
3494                         return -1;
3495                 }
3496
3497                 return getxattr(p, name, value, size);
3498         }
3499
3500         /*
3501          * This is no longer a handle based call.
3502          */
3503         return getxattr(fsp->fsp_name->base_name, name, value, size);
3504 }
3505
3506 struct vfswrap_getxattrat_state {
3507         struct tevent_context *ev;
3508         struct vfs_handle_struct *handle;
3509         files_struct *dir_fsp;
3510         const struct smb_filename *smb_fname;
3511
3512         /*
3513          * The following variables are talloced off "state" which is protected
3514          * by a destructor and thus are guaranteed to be safe to be used in the
3515          * job function in the worker thread.
3516          */
3517         char *name;
3518         const char *xattr_name;
3519         uint8_t *xattr_value;
3520         struct security_unix_token *token;
3521
3522         ssize_t xattr_size;
3523         struct vfs_aio_state vfs_aio_state;
3524         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3525 };
3526
3527 static int vfswrap_getxattrat_state_destructor(
3528                 struct vfswrap_getxattrat_state *state)
3529 {
3530         return -1;
3531 }
3532
3533 static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3534 static void vfswrap_getxattrat_do_async(void *private_data);
3535 static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3536
3537 static struct tevent_req *vfswrap_getxattrat_send(
3538                         TALLOC_CTX *mem_ctx,
3539                         struct tevent_context *ev,
3540                         struct vfs_handle_struct *handle,
3541                         files_struct *dir_fsp,
3542                         const struct smb_filename *smb_fname,
3543                         const char *xattr_name,
3544                         size_t alloc_hint)
3545 {
3546         struct tevent_req *req = NULL;
3547         struct tevent_req *subreq = NULL;
3548         struct vfswrap_getxattrat_state *state = NULL;
3549         size_t max_threads = 0;
3550         bool have_per_thread_cwd = false;
3551         bool have_per_thread_creds = false;
3552         bool do_async = false;
3553
3554         req = tevent_req_create(mem_ctx, &state,
3555                                 struct vfswrap_getxattrat_state);
3556         if (req == NULL) {
3557                 return NULL;
3558         }
3559         *state = (struct vfswrap_getxattrat_state) {
3560                 .ev = ev,
3561                 .handle = handle,
3562                 .dir_fsp = dir_fsp,
3563                 .smb_fname = smb_fname,
3564         };
3565
3566         max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3567         if (max_threads >= 1) {
3568                 /*
3569                  * We need a non sync threadpool!
3570                  */
3571                 have_per_thread_cwd = per_thread_cwd_supported();
3572         }
3573 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3574         have_per_thread_creds = true;
3575 #endif
3576         if (have_per_thread_cwd && have_per_thread_creds) {
3577                 do_async = true;
3578         }
3579
3580         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3581                                      state->profile_bytes, 0);
3582
3583         if (fsp_get_pathref_fd(dir_fsp) == -1) {
3584                 DBG_ERR("Need a valid directory fd\n");
3585                 tevent_req_error(req, EINVAL);
3586                 return tevent_req_post(req, ev);
3587         }
3588
3589         if (alloc_hint > 0) {
3590                 state->xattr_value = talloc_zero_array(state,
3591                                                        uint8_t,
3592                                                        alloc_hint);
3593                 if (tevent_req_nomem(state->xattr_value, req)) {
3594                         return tevent_req_post(req, ev);
3595                 }
3596         }
3597
3598         if (!do_async) {
3599                 vfswrap_getxattrat_do_sync(req);
3600                 return tevent_req_post(req, ev);
3601         }
3602
3603         /*
3604          * Now allocate all parameters from a memory context that won't go away
3605          * no matter what. These paremeters will get used in threads and we
3606          * can't reliably cancel threads, so all buffers passed to the threads
3607          * must not be freed before all referencing threads terminate.
3608          */
3609
3610         state->name = talloc_strdup(state, smb_fname->base_name);
3611         if (tevent_req_nomem(state->name, req)) {
3612                 return tevent_req_post(req, ev);
3613         }
3614
3615         state->xattr_name = talloc_strdup(state, xattr_name);
3616         if (tevent_req_nomem(state->xattr_name, req)) {
3617                 return tevent_req_post(req, ev);
3618         }
3619
3620         /*
3621          * This is a hot codepath so at first glance one might think we should
3622          * somehow optimize away the token allocation and do a
3623          * talloc_reference() or similar black magic instead. But due to the
3624          * talloc_stackframe pool per SMB2 request this should be a simple copy
3625          * without a malloc in most cases.
3626          */
3627         if (geteuid() == sec_initial_uid()) {
3628                 state->token = root_unix_token(state);
3629         } else {
3630                 state->token = copy_unix_token(
3631                                         state,
3632                                         dir_fsp->conn->session_info->unix_token);
3633         }
3634         if (tevent_req_nomem(state->token, req)) {
3635                 return tevent_req_post(req, ev);
3636         }
3637
3638         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3639
3640         subreq = pthreadpool_tevent_job_send(
3641                         state,
3642                         ev,
3643                         dir_fsp->conn->sconn->pool,
3644                         vfswrap_getxattrat_do_async,
3645                         state);
3646         if (tevent_req_nomem(subreq, req)) {
3647                 return tevent_req_post(req, ev);
3648         }
3649         tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3650
3651         talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3652
3653         return req;
3654 }
3655
3656 static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3657 {
3658         struct vfswrap_getxattrat_state *state = tevent_req_data(
3659                 req, struct vfswrap_getxattrat_state);
3660         struct files_struct *fsp = metadata_fsp(state->smb_fname->fsp);
3661
3662         state->xattr_size = vfswrap_fgetxattr(state->handle,
3663                                               fsp,
3664                                               state->xattr_name,
3665                                               state->xattr_value,
3666                                               talloc_array_length(state->xattr_value));
3667         if (state->xattr_size == -1) {
3668                 tevent_req_error(req, errno);
3669                 return;
3670         }
3671
3672         tevent_req_done(req);
3673         return;
3674 }
3675
3676 static void vfswrap_getxattrat_do_async(void *private_data)
3677 {
3678         struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3679                 private_data, struct vfswrap_getxattrat_state);
3680         struct timespec start_time;
3681         struct timespec end_time;
3682         int ret;
3683         struct files_struct *fsp = metadata_fsp(state->smb_fname->fsp);
3684
3685         PROFILE_TIMESTAMP(&start_time);
3686         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3687
3688         /*
3689          * Here we simulate a getxattrat()
3690          * call using fchdir();getxattr()
3691          */
3692
3693         per_thread_cwd_activate();
3694
3695         /* Become the correct credential on this thread. */
3696         ret = set_thread_credentials(state->token->uid,
3697                                      state->token->gid,
3698                                      (size_t)state->token->ngroups,
3699                                      state->token->groups);
3700         if (ret != 0) {
3701                 state->xattr_size = -1;
3702                 state->vfs_aio_state.error = errno;
3703                 goto end_profile;
3704         }
3705
3706         state->xattr_size = vfswrap_fgetxattr(state->handle,
3707                                               fsp,
3708                                               state->xattr_name,
3709                                               state->xattr_value,
3710                                               talloc_array_length(state->xattr_value));
3711         if (state->xattr_size == -1) {
3712                 state->vfs_aio_state.error = errno;
3713         }
3714
3715 end_profile:
3716         PROFILE_TIMESTAMP(&end_time);
3717         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3718         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3719 }
3720
3721 static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3722 {
3723         struct tevent_req *req = tevent_req_callback_data(
3724                 subreq, struct tevent_req);
3725         struct vfswrap_getxattrat_state *state = tevent_req_data(
3726                 req, struct vfswrap_getxattrat_state);
3727         int ret;
3728         bool ok;
3729
3730         /*
3731          * Make sure we run as the user again
3732          */
3733         ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3734         SMB_ASSERT(ok);
3735
3736         ret = pthreadpool_tevent_job_recv(subreq);
3737         TALLOC_FREE(subreq);
3738         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3739         talloc_set_destructor(state, NULL);
3740         if (ret != 0) {
3741                 if (ret != EAGAIN) {
3742                         tevent_req_error(req, ret);
3743                         return;
3744                 }
3745                 /*
3746                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3747                  * means the lower level pthreadpool failed to create a new
3748                  * thread. Fallback to sync processing in that case to allow
3749                  * some progress for the client.
3750                  */
3751                 vfswrap_getxattrat_do_sync(req);
3752                 return;
3753         }
3754
3755         if (state->xattr_size == -1) {
3756                 tevent_req_error(req, state->vfs_aio_state.error);
3757                 return;
3758         }
3759
3760         if (state->xattr_value == NULL) {
3761                 /*
3762                  * The caller only wanted the size.
3763                  */
3764                 tevent_req_done(req);
3765                 return;
3766         }
3767
3768         /*
3769          * shrink the buffer to the returned size.
3770          * (can't fail). It means NULL if size is 0.
3771          */
3772         state->xattr_value = talloc_realloc(state,
3773                                             state->xattr_value,
3774                                             uint8_t,
3775                                             state->xattr_size);
3776
3777         tevent_req_done(req);
3778 }
3779
3780 static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3781                                        struct vfs_aio_state *aio_state,
3782                                        TALLOC_CTX *mem_ctx,
3783                                        uint8_t **xattr_value)
3784 {
3785         struct vfswrap_getxattrat_state *state = tevent_req_data(
3786                 req, struct vfswrap_getxattrat_state);
3787         ssize_t xattr_size;
3788
3789         if (tevent_req_is_unix_error(req, &aio_state->error)) {
3790                 tevent_req_received(req);
3791                 return -1;
3792         }
3793
3794         *aio_state = state->vfs_aio_state;
3795         xattr_size = state->xattr_size;
3796         if (xattr_value != NULL) {
3797                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3798         }
3799
3800         tevent_req_received(req);
3801         return xattr_size;
3802 }
3803
3804 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3805 {
3806         int fd = fsp_get_pathref_fd(fsp);
3807
3808         if (!fsp->fsp_flags.is_pathref) {
3809                 return flistxattr(fd, list, size);
3810         }
3811
3812         if (fsp->fsp_flags.have_proc_fds) {
3813                 const char *p = NULL;
3814                 char buf[PATH_MAX];
3815
3816                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3817                 if (p == NULL) {
3818                         return -1;
3819                 }
3820
3821                 return listxattr(p, list, size);
3822         }
3823
3824         /*
3825          * This is no longer a handle based call.
3826          */
3827         return listxattr(fsp->fsp_name->base_name, list, size);
3828 }
3829
3830 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3831 {
3832         int fd = fsp_get_pathref_fd(fsp);
3833
3834         if (!fsp->fsp_flags.is_pathref) {
3835                 return fremovexattr(fd, name);
3836         }
3837
3838         if (fsp->fsp_flags.have_proc_fds) {
3839                 const char *p = NULL;
3840                 char buf[PATH_MAX];
3841
3842                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3843                 if (p == NULL) {
3844                         return -1;
3845                 }
3846
3847                 return removexattr(p, name);
3848         }
3849
3850         /*
3851          * This is no longer a handle based call.
3852          */
3853         return removexattr(fsp->fsp_name->base_name, name);
3854 }
3855
3856 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3857 {
3858         int fd = fsp_get_pathref_fd(fsp);
3859
3860         if (!fsp->fsp_flags.is_pathref) {
3861                 return fsetxattr(fd, name, value, size, flags);
3862         }
3863
3864         if (fsp->fsp_flags.have_proc_fds) {
3865                 const char *p = NULL;
3866                 char buf[PATH_MAX];
3867
3868                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
3869                 if (p == NULL) {
3870                         return -1;
3871                 }
3872
3873                 return setxattr(p, name, value, size, flags);
3874         }
3875
3876         /*
3877          * This is no longer a handle based call.
3878          */
3879         return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3880 }
3881
3882 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3883 {
3884         return false;
3885 }
3886
3887 static bool vfswrap_is_offline(struct connection_struct *conn,
3888                                const struct smb_filename *fname)
3889 {
3890         NTSTATUS status;
3891         char *path;
3892         bool offline = false;
3893
3894         if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3895                 return false;
3896         }
3897
3898         if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3899 #if defined(ENOTSUP)
3900                 errno = ENOTSUP;
3901 #endif
3902                 return false;
3903         }
3904
3905         status = get_full_smb_filename(talloc_tos(), fname, &path);
3906         if (!NT_STATUS_IS_OK(status)) {
3907                 errno = map_errno_from_nt_status(status);
3908                 return false;
3909         }
3910
3911         offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3912
3913         TALLOC_FREE(path);
3914
3915         return offline;
3916 }
3917
3918 static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3919                                        struct files_struct *fsp,
3920                                        TALLOC_CTX *mem_ctx,
3921                                        DATA_BLOB *cookie)
3922 {
3923         return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3924 }
3925
3926 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3927                                            struct files_struct *fsp,
3928                                            const DATA_BLOB old_cookie,
3929                                            TALLOC_CTX *mem_ctx,
3930                                            DATA_BLOB *new_cookie)
3931 {
3932         return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3933                                               new_cookie);
3934 }
3935
3936 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3937                                           struct smb_request *smb1req,
3938                                           struct smbXsrv_open *op,
3939                                           const DATA_BLOB old_cookie,
3940                                           TALLOC_CTX *mem_ctx,
3941                                           struct files_struct **fsp,
3942                                           DATA_BLOB *new_cookie)
3943 {
3944         return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3945                                              old_cookie, mem_ctx,
3946                                              fsp, new_cookie);
3947 }
3948
3949 static struct vfs_fn_pointers vfs_default_fns = {
3950         /* Disk operations */
3951
3952         .connect_fn = vfswrap_connect,
3953         .disconnect_fn = vfswrap_disconnect,
3954         .disk_free_fn = vfswrap_disk_free,
3955         .get_quota_fn = vfswrap_get_quota,
3956         .set_quota_fn = vfswrap_set_quota,
3957         .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3958         .statvfs_fn = vfswrap_statvfs,
3959         .fs_capabilities_fn = vfswrap_fs_capabilities,
3960         .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3961         .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3962         .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3963         .snap_check_path_fn = vfswrap_snap_check_path,
3964         .snap_create_fn = vfswrap_snap_create,
3965         .snap_delete_fn = vfswrap_snap_delete,
3966
3967         /* Directory operations */
3968
3969         .fdopendir_fn = vfswrap_fdopendir,
3970         .readdir_fn = vfswrap_readdir,
3971         .freaddir_attr_fn = vfswrap_freaddir_attr,
3972         .seekdir_fn = vfswrap_seekdir,
3973         .telldir_fn = vfswrap_telldir,
3974         .rewind_dir_fn = vfswrap_rewinddir,
3975         .mkdirat_fn = vfswrap_mkdirat,
3976         .closedir_fn = vfswrap_closedir,
3977
3978         /* File operations */
3979
3980         .openat_fn = vfswrap_openat,
3981         .create_file_fn = vfswrap_create_file,
3982         .close_fn = vfswrap_close,
3983         .pread_fn = vfswrap_pread,
3984         .pread_send_fn = vfswrap_pread_send,
3985         .pread_recv_fn = vfswrap_pread_recv,
3986         .pwrite_fn = vfswrap_pwrite,
3987         .pwrite_send_fn = vfswrap_pwrite_send,
3988         .pwrite_recv_fn = vfswrap_pwrite_recv,
3989         .lseek_fn = vfswrap_lseek,
3990         .sendfile_fn = vfswrap_sendfile,
3991         .recvfile_fn = vfswrap_recvfile,
3992         .renameat_fn = vfswrap_renameat,
3993         .fsync_send_fn = vfswrap_fsync_send,
3994         .fsync_recv_fn = vfswrap_fsync_recv,
3995         .stat_fn = vfswrap_stat,
3996         .fstat_fn = vfswrap_fstat,
3997         .lstat_fn = vfswrap_lstat,
3998         .fstatat_fn = vfswrap_fstatat,
3999         .get_alloc_size_fn = vfswrap_get_alloc_size,
4000         .unlinkat_fn = vfswrap_unlinkat,
4001         .fchmod_fn = vfswrap_fchmod,
4002         .fchown_fn = vfswrap_fchown,
4003         .lchown_fn = vfswrap_lchown,
4004         .chdir_fn = vfswrap_chdir,
4005         .getwd_fn = vfswrap_getwd,
4006         .fntimes_fn = vfswrap_fntimes,
4007         .ftruncate_fn = vfswrap_ftruncate,
4008         .fallocate_fn = vfswrap_fallocate,
4009         .lock_fn = vfswrap_lock,
4010         .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4011         .fcntl_fn = vfswrap_fcntl,
4012         .linux_setlease_fn = vfswrap_linux_setlease,
4013         .getlock_fn = vfswrap_getlock,
4014         .symlinkat_fn = vfswrap_symlinkat,
4015         .readlinkat_fn = vfswrap_readlinkat,
4016         .linkat_fn = vfswrap_linkat,
4017         .mknodat_fn = vfswrap_mknodat,
4018         .realpath_fn = vfswrap_realpath,
4019         .fchflags_fn = vfswrap_fchflags,
4020         .file_id_create_fn = vfswrap_file_id_create,
4021         .fs_file_id_fn = vfswrap_fs_file_id,
4022         .fstreaminfo_fn = vfswrap_fstreaminfo,
4023         .get_real_filename_fn = vfswrap_get_real_filename,
4024         .connectpath_fn = vfswrap_connectpath,
4025         .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4026         .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4027         .strict_lock_check_fn = vfswrap_strict_lock_check,
4028         .translate_name_fn = vfswrap_translate_name,
4029         .parent_pathname_fn = vfswrap_parent_pathname,
4030         .fsctl_fn = vfswrap_fsctl,
4031         .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4032         .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4033         .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4034         .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4035         .offload_read_send_fn = vfswrap_offload_read_send,
4036         .offload_read_recv_fn = vfswrap_offload_read_recv,
4037         .offload_write_send_fn = vfswrap_offload_write_send,
4038         .offload_write_recv_fn = vfswrap_offload_write_recv,
4039         .fget_compression_fn = vfswrap_fget_compression,
4040         .set_compression_fn = vfswrap_set_compression,
4041
4042         /* NT ACL operations. */
4043
4044         .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4045         .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4046         .audit_file_fn = vfswrap_audit_file,
4047
4048         /* POSIX ACL operations. */
4049
4050         .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4051         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4052         .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4053         .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4054
4055         /* EA operations. */
4056         .getxattrat_send_fn = vfswrap_getxattrat_send,
4057         .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4058         .fgetxattr_fn = vfswrap_fgetxattr,
4059         .flistxattr_fn = vfswrap_flistxattr,
4060         .fremovexattr_fn = vfswrap_fremovexattr,
4061         .fsetxattr_fn = vfswrap_fsetxattr,
4062
4063         /* aio operations */
4064         .aio_force_fn = vfswrap_aio_force,
4065
4066         /* durable handle operations */
4067         .durable_cookie_fn = vfswrap_durable_cookie,
4068         .durable_disconnect_fn = vfswrap_durable_disconnect,
4069         .durable_reconnect_fn = vfswrap_durable_reconnect,
4070 };
4071
4072 static_decl_vfs;
4073 NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4074 {
4075         /*
4076          * Here we need to implement every call!
4077          *
4078          * As this is the end of the vfs module chain.
4079          */
4080         smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4081         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4082                                 DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);
4083 }
4084
4085