LCOV - code coverage report
Current view: top level - source3/modules - vfs_default.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1218 1698 71.7 %
Date: 2024-04-21 15:09:00 Functions: 100 119 84.0 %

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

Generated by: LCOV version 1.14