LCOV - code coverage report
Current view: top level - source3/modules - vfs_default.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 605 1626 37.2 %
Date: 2024-06-13 04:01:37 Functions: 61 121 50.4 %

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

Generated by: LCOV version 1.13