LCOV - code coverage report
Current view: top level - source3/modules - vfs_default.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 1206 1696 71.1 %
Date: 2024-01-11 09:59:51 Functions: 100 119 84.0 %

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

Generated by: LCOV version 1.14