LCOV - code coverage report
Current view: top level - source3/modules - vfs_streams_xattr.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 433 656 66.0 %
Date: 2021-09-23 10:06:22 Functions: 38 43 88.4 %

          Line data    Source code
       1             : /*
       2             :  * Store streams in xattrs
       3             :  *
       4             :  * Copyright (C) Volker Lendecke, 2008
       5             :  *
       6             :  * Partly based on James Peach's Darwin module, which is
       7             :  *
       8             :  * Copyright (C) James Peach 2006-2007
       9             :  *
      10             :  * This program is free software; you can redistribute it and/or modify
      11             :  * it under the terms of the GNU General Public License as published by
      12             :  * the Free Software Foundation; either version 3 of the License, or
      13             :  * (at your option) any later version.
      14             :  *
      15             :  * This program is distributed in the hope that it will be useful,
      16             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  * GNU General Public License for more details.
      19             :  *
      20             :  * You should have received a copy of the GNU General Public License
      21             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      22             :  */
      23             : 
      24             : #include "includes.h"
      25             : #include "smbd/smbd.h"
      26             : #include "system/filesys.h"
      27             : #include "lib/util/tevent_unix.h"
      28             : #include "librpc/gen_ndr/ioctl.h"
      29             : #include "hash_inode.h"
      30             : 
      31             : #undef DBGC_CLASS
      32             : #define DBGC_CLASS DBGC_VFS
      33             : 
      34             : struct streams_xattr_config {
      35             :         const char *prefix;
      36             :         size_t prefix_len;
      37             :         bool store_stream_type;
      38             : };
      39             : 
      40             : struct stream_io {
      41             :         char *base;
      42             :         char *xattr_name;
      43             :         void *fsp_name_ptr;
      44             :         files_struct *fsp;
      45             :         vfs_handle_struct *handle;
      46             : };
      47             : 
      48        6036 : static ssize_t get_xattr_size_fsp(struct files_struct *fsp,
      49             :                                   const char *xattr_name)
      50             : {
      51             :         NTSTATUS status;
      52             :         struct ea_struct ea;
      53             :         ssize_t result;
      54             : 
      55        6036 :         status = get_ea_value_fsp(talloc_tos(),
      56             :                                   fsp,
      57             :                                   xattr_name,
      58             :                                   &ea);
      59        6036 :         if (!NT_STATUS_IS_OK(status)) {
      60        1400 :                 return -1;
      61             :         }
      62             : 
      63        4636 :         result = ea.value.length-1;
      64        4636 :         TALLOC_FREE(ea.value.data);
      65        4636 :         return result;
      66             : }
      67             : 
      68             : /**
      69             :  * Given a stream name, populate xattr_name with the xattr name to use for
      70             :  * accessing the stream.
      71             :  */
      72        7082 : static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
      73             :                                        TALLOC_CTX *ctx,
      74             :                                        const char *stream_name,
      75             :                                        char **xattr_name)
      76             : {
      77             :         char *sname;
      78             :         char *stype;
      79             :         struct streams_xattr_config *config;
      80             : 
      81        7082 :         SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
      82             :                                 return NT_STATUS_UNSUCCESSFUL);
      83             : 
      84        7082 :         sname = talloc_strdup(ctx, stream_name + 1);
      85        7082 :         if (sname == NULL) {
      86           0 :                 return NT_STATUS_NO_MEMORY;
      87             :         }
      88             : 
      89             :         /*
      90             :          * With vfs_fruit option "fruit:encoding = native" we're
      91             :          * already converting stream names that contain illegal NTFS
      92             :          * characters from their on-the-wire Unicode Private Range
      93             :          * encoding to their native ASCII representation.
      94             :          *
      95             :          * As as result the name of xattrs storing the streams (via
      96             :          * vfs_streams_xattr) may contain a colon, so we have to use
      97             :          * strrchr_m() instead of strchr_m() for matching the stream
      98             :          * type suffix.
      99             :          *
     100             :          * In check_path_syntax() we've already ensured the streamname
     101             :          * we got from the client is valid.
     102             :          */
     103        7082 :         stype = strrchr_m(sname, ':');
     104             : 
     105        7082 :         if (stype) {
     106             :                 /*
     107             :                  * We only support one stream type: "$DATA"
     108             :                  */
     109        5162 :                 if (strcasecmp_m(stype, ":$DATA") != 0) {
     110           8 :                         talloc_free(sname);
     111           8 :                         return NT_STATUS_INVALID_PARAMETER;
     112             :                 }
     113             : 
     114             :                 /* Split name and type */
     115        5154 :                 stype[0] = '\0';
     116             :         }
     117             : 
     118        7074 :         *xattr_name = talloc_asprintf(ctx, "%s%s%s",
     119             :                                       config->prefix,
     120             :                                       sname,
     121        7074 :                                       config->store_stream_type ? ":$DATA" : "");
     122        7074 :         if (*xattr_name == NULL) {
     123           0 :                 talloc_free(sname);
     124           0 :                 return NT_STATUS_NO_MEMORY;
     125             :         }
     126             : 
     127        7074 :         DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name,
     128             :                    stream_name));
     129             : 
     130        7074 :         talloc_free(sname);
     131        7074 :         return NT_STATUS_OK;
     132             : }
     133             : 
     134        4112 : static bool streams_xattr_recheck(struct stream_io *sio)
     135             : {
     136             :         NTSTATUS status;
     137        4112 :         char *xattr_name = NULL;
     138             : 
     139        4112 :         if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
     140        3028 :                 return true;
     141             :         }
     142             : 
     143        1084 :         if (sio->fsp->fsp_name->stream_name == NULL) {
     144             :                 /* how can this happen */
     145           0 :                 errno = EINVAL;
     146           0 :                 return false;
     147             :         }
     148             : 
     149        1084 :         status = streams_xattr_get_name(sio->handle, talloc_tos(),
     150        1084 :                                         sio->fsp->fsp_name->stream_name,
     151             :                                         &xattr_name);
     152        1084 :         if (!NT_STATUS_IS_OK(status)) {
     153           0 :                 return false;
     154             :         }
     155             : 
     156        1084 :         TALLOC_FREE(sio->xattr_name);
     157        1084 :         TALLOC_FREE(sio->base);
     158        1084 :         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
     159             :                                         xattr_name);
     160        1084 :         if (sio->xattr_name == NULL) {
     161           0 :                 DBG_DEBUG("sio->xattr_name==NULL\n");
     162           0 :                 return false;
     163             :         }
     164        1084 :         TALLOC_FREE(xattr_name);
     165             : 
     166        1084 :         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
     167        1084 :                                   sio->fsp->fsp_name->base_name);
     168        1084 :         if (sio->base == NULL) {
     169           0 :                 DBG_DEBUG("sio->base==NULL\n");
     170           0 :                 return false;
     171             :         }
     172             : 
     173        1084 :         sio->fsp_name_ptr = sio->fsp->fsp_name;
     174             : 
     175        1084 :         return true;
     176             : }
     177             : 
     178      102650 : static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
     179             :                                SMB_STRUCT_STAT *sbuf)
     180             : {
     181      102650 :         int ret = -1;
     182      102410 :         struct stream_io *io = (struct stream_io *)
     183         240 :                 VFS_FETCH_FSP_EXTENSION(handle, fsp);
     184             : 
     185      102650 :         if (io == NULL || fsp->base_fsp == NULL) {
     186       99294 :                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
     187             :         }
     188             : 
     189        3356 :         DBG_DEBUG("streams_xattr_fstat called for %s\n", fsp_str_dbg(io->fsp));
     190             : 
     191        3356 :         if (!streams_xattr_recheck(io)) {
     192           0 :                 return -1;
     193             :         }
     194             : 
     195        3356 :         ret = SMB_VFS_NEXT_FSTAT(handle, fsp->base_fsp, sbuf);
     196        3356 :         if (ret == -1) {
     197           0 :                 return -1;
     198             :         }
     199             : 
     200        3382 :         sbuf->st_ex_size = get_xattr_size_fsp(fsp->base_fsp,
     201        3356 :                                               io->xattr_name);
     202        3356 :         if (sbuf->st_ex_size == -1) {
     203           0 :                 SET_STAT_INVALID(*sbuf);
     204           0 :                 return -1;
     205             :         }
     206             : 
     207        3356 :         DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf->st_ex_size));
     208             : 
     209        3356 :         sbuf->st_ex_ino = hash_inode(sbuf, io->xattr_name);
     210        3356 :         sbuf->st_ex_mode &= ~S_IFMT;
     211        3356 :         sbuf->st_ex_mode &= ~S_IFDIR;
     212        3356 :         sbuf->st_ex_mode |= S_IFREG;
     213        3356 :         sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
     214             : 
     215        3356 :         return 0;
     216             : }
     217             : 
     218      237394 : static int streams_xattr_stat(vfs_handle_struct *handle,
     219             :                               struct smb_filename *smb_fname)
     220             : {
     221             :         NTSTATUS status;
     222      237394 :         int result = -1;
     223      237394 :         char *xattr_name = NULL;
     224      237394 :         char *tmp_stream_name = NULL;
     225      237394 :         struct smb_filename *pathref = NULL;
     226      237394 :         struct files_struct *fsp = smb_fname->fsp;
     227             : 
     228      237394 :         if (!is_named_stream(smb_fname)) {
     229      234678 :                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
     230             :         }
     231             : 
     232             :         /* Note if lp_posix_paths() is true, we can never
     233             :          * get here as is_named_stream() is
     234             :          * always false. So we never need worry about
     235             :          * not following links here. */
     236             : 
     237             :         /* Populate the stat struct with info from the base file. */
     238        2716 :         tmp_stream_name = smb_fname->stream_name;
     239        2716 :         smb_fname->stream_name = NULL;
     240        2716 :         result = SMB_VFS_NEXT_STAT(handle, smb_fname);
     241        2716 :         smb_fname->stream_name = tmp_stream_name;
     242             : 
     243        2716 :         if (result == -1) {
     244          28 :                 return -1;
     245             :         }
     246             : 
     247             :         /* Derive the xattr name to lookup. */
     248        2688 :         status = streams_xattr_get_name(handle, talloc_tos(),
     249        2688 :                                         smb_fname->stream_name, &xattr_name);
     250        2688 :         if (!NT_STATUS_IS_OK(status)) {
     251           8 :                 errno = map_errno_from_nt_status(status);
     252           8 :                 return -1;
     253             :         }
     254             : 
     255             :         /* Augment the base file's stat information before returning. */
     256        2680 :         if (fsp == NULL) {
     257        5300 :                 status = synthetic_pathref(talloc_tos(),
     258        2656 :                                            handle->conn->cwd_fsp,
     259        2656 :                                            smb_fname->base_name,
     260             :                                            NULL,
     261             :                                            NULL,
     262             :                                            smb_fname->twrp,
     263             :                                            smb_fname->flags,
     264             :                                            &pathref);
     265        2656 :                 if (!NT_STATUS_IS_OK(status)) {
     266           0 :                         TALLOC_FREE(xattr_name);
     267           0 :                         SET_STAT_INVALID(smb_fname->st);
     268           0 :                         errno = ENOENT;
     269           0 :                         return -1;
     270             :                 }
     271        2656 :                 fsp = pathref->fsp;
     272             :         } else {
     273          24 :                 fsp = fsp->base_fsp;
     274             :         }
     275             : 
     276        2680 :         smb_fname->st.st_ex_size = get_xattr_size_fsp(fsp,
     277             :                                                       xattr_name);
     278        2680 :         if (smb_fname->st.st_ex_size == -1) {
     279        1400 :                 TALLOC_FREE(xattr_name);
     280        1400 :                 TALLOC_FREE(pathref);
     281        1400 :                 SET_STAT_INVALID(smb_fname->st);
     282        1400 :                 errno = ENOENT;
     283        1400 :                 return -1;
     284             :         }
     285             : 
     286        1280 :         smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st, xattr_name);
     287        1280 :         smb_fname->st.st_ex_mode &= ~S_IFMT;
     288        1280 :         smb_fname->st.st_ex_mode |= S_IFREG;
     289        1280 :         smb_fname->st.st_ex_blocks =
     290        1280 :             smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
     291             : 
     292        1280 :         TALLOC_FREE(xattr_name);
     293        1280 :         TALLOC_FREE(pathref);
     294        1280 :         return 0;
     295             : }
     296             : 
     297        7196 : static int streams_xattr_lstat(vfs_handle_struct *handle,
     298             :                                struct smb_filename *smb_fname)
     299             : {
     300        7196 :         if (is_named_stream(smb_fname)) {
     301             :                 /*
     302             :                  * There can never be EA's on a symlink.
     303             :                  * Windows will never see a symlink, and
     304             :                  * in SMB_FILENAME_POSIX_PATH mode we don't
     305             :                  * allow EA's on a symlink.
     306             :                  */
     307           0 :                 SET_STAT_INVALID(smb_fname->st);
     308           0 :                 errno = ENOENT;
     309           0 :                 return -1;
     310             :         }
     311        7196 :         return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
     312             : }
     313             : 
     314       86005 : static int streams_xattr_openat(struct vfs_handle_struct *handle,
     315             :                                 const struct files_struct *dirfsp,
     316             :                                 const struct smb_filename *smb_fname,
     317             :                                 files_struct *fsp,
     318             :                                 int flags,
     319             :                                 mode_t mode)
     320             : {
     321             :         NTSTATUS status;
     322       86005 :         struct streams_xattr_config *config = NULL;
     323       86005 :         struct stream_io *sio = NULL;
     324             :         struct ea_struct ea;
     325       86005 :         char *xattr_name = NULL;
     326       86005 :         int fakefd = -1;
     327       86005 :         bool set_empty_xattr = false;
     328             :         int ret;
     329             : 
     330       86005 :         SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
     331             :                                 return -1);
     332             : 
     333       86005 :         DEBUG(10, ("streams_xattr_open called for %s with flags 0x%x\n",
     334             :                    smb_fname_str_dbg(smb_fname), flags));
     335             : 
     336       86005 :         if (!is_named_stream(smb_fname)) {
     337       83075 :                 return SMB_VFS_NEXT_OPENAT(handle,
     338             :                                            dirfsp,
     339             :                                            smb_fname,
     340             :                                            fsp,
     341             :                                            flags,
     342             :                                            mode);
     343             :         }
     344             : 
     345             :         /*
     346             :          * For now assert this, so the below SMB_VFS_SETXATTR() works.
     347             :          */
     348        2930 :         SMB_ASSERT(fsp_get_pathref_fd(dirfsp) == AT_FDCWD);
     349             : 
     350        2930 :         status = streams_xattr_get_name(handle, talloc_tos(),
     351        2930 :                                         smb_fname->stream_name, &xattr_name);
     352        2930 :         if (!NT_STATUS_IS_OK(status)) {
     353           0 :                 errno = map_errno_from_nt_status(status);
     354           0 :                 goto fail;
     355             :         }
     356             : 
     357        5848 :         status = get_ea_value_fsp(talloc_tos(),
     358        2930 :                                   fsp->base_fsp,
     359             :                                   xattr_name,
     360             :                                   &ea);
     361             : 
     362        2930 :         DBG_DEBUG("get_ea_value_fsp returned %s\n", nt_errstr(status));
     363             : 
     364        2930 :         if (!NT_STATUS_IS_OK(status)) {
     365        1148 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     366             :                         /*
     367             :                          * The base file is not there. This is an error even if
     368             :                          * we got O_CREAT, the higher levels should have created
     369             :                          * the base file for us.
     370             :                          */
     371           0 :                         DBG_DEBUG("streams_xattr_open: base file %s not around, "
     372             :                                   "returning ENOENT\n", smb_fname->base_name);
     373           0 :                         errno = ENOENT;
     374           0 :                         goto fail;
     375             :                 }
     376             : 
     377        1148 :                 if (!(flags & O_CREAT)) {
     378         732 :                         errno = ENOATTR;
     379         732 :                         goto fail;
     380             :                 }
     381             : 
     382         416 :                 set_empty_xattr = true;
     383             :         }
     384             : 
     385        2198 :         if (flags & O_TRUNC) {
     386           0 :                 set_empty_xattr = true;
     387             :         }
     388             : 
     389        2198 :         if (set_empty_xattr) {
     390             :                 /*
     391             :                  * The attribute does not exist or needs to be truncated
     392             :                  */
     393             : 
     394             :                 /*
     395             :                  * Darn, xattrs need at least 1 byte
     396             :                  */
     397         416 :                 char null = '\0';
     398             : 
     399         416 :                 DEBUG(10, ("creating or truncating attribute %s on file %s\n",
     400             :                            xattr_name, smb_fname->base_name));
     401             : 
     402         416 :                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
     403             :                                        xattr_name,
     404             :                                        &null, sizeof(null),
     405             :                                        flags & O_EXCL ? XATTR_CREATE : 0);
     406         416 :                 if (ret != 0) {
     407           0 :                         goto fail;
     408             :                 }
     409             :         }
     410             : 
     411        2198 :         fakefd = vfs_fake_fd();
     412             : 
     413        2198 :         sio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct stream_io, NULL);
     414        2198 :         if (sio == NULL) {
     415           0 :                 errno = ENOMEM;
     416           0 :                 goto fail;
     417             :         }
     418             : 
     419        2198 :         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
     420             :                                         xattr_name);
     421        2198 :         if (sio->xattr_name == NULL) {
     422           0 :                 errno = ENOMEM;
     423           0 :                 goto fail;
     424             :         }
     425             : 
     426             :         /*
     427             :          * so->base needs to be a copy of fsp->fsp_name->base_name,
     428             :          * making it identical to streams_xattr_recheck(). If the
     429             :          * open is changing directories, fsp->fsp_name->base_name
     430             :          * will be the full path from the share root, whilst
     431             :          * smb_fname will be relative to the $cwd.
     432             :          */
     433        2198 :         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
     434        2198 :                                   fsp->fsp_name->base_name);
     435        2198 :         if (sio->base == NULL) {
     436           0 :                 errno = ENOMEM;
     437           0 :                 goto fail;
     438             :         }
     439             : 
     440        2198 :         sio->fsp_name_ptr = fsp->fsp_name;
     441        2198 :         sio->handle = handle;
     442        2198 :         sio->fsp = fsp;
     443             : 
     444        2198 :         return fakefd;
     445             : 
     446         732 :  fail:
     447         732 :         if (fakefd >= 0) {
     448           0 :                 vfs_fake_fd_close(fakefd);
     449           0 :                 fakefd = -1;
     450             :         }
     451             : 
     452         732 :         return -1;
     453             : }
     454             : 
     455       77208 : static int streams_xattr_close(vfs_handle_struct *handle,
     456             :                                files_struct *fsp)
     457             : {
     458             :         int ret;
     459             :         int fd;
     460             : 
     461       77208 :         fd = fsp_get_pathref_fd(fsp);
     462             : 
     463       77208 :         DBG_DEBUG("streams_xattr_close called [%s] fd [%d]\n",
     464             :                         smb_fname_str_dbg(fsp->fsp_name), fd);
     465             : 
     466       77208 :         if (!is_named_stream(fsp->fsp_name)) {
     467       75010 :                 return SMB_VFS_NEXT_CLOSE(handle, fsp);
     468             :         }
     469             : 
     470        2198 :         ret = vfs_fake_fd_close(fd);
     471        2198 :         fsp_set_fd(fsp, -1);
     472             : 
     473        2198 :         return ret;
     474             : }
     475             : 
     476        1187 : static int streams_xattr_unlink_internal(vfs_handle_struct *handle,
     477             :                         struct files_struct *dirfsp,
     478             :                         const struct smb_filename *smb_fname,
     479             :                         int flags)
     480             : {
     481             :         NTSTATUS status;
     482        1187 :         int ret = -1;
     483        1187 :         char *xattr_name = NULL;
     484             : 
     485        1187 :         if (!is_named_stream(smb_fname)) {
     486         807 :                 return SMB_VFS_NEXT_UNLINKAT(handle,
     487             :                                         dirfsp,
     488             :                                         smb_fname,
     489             :                                         flags);
     490             :         }
     491             : 
     492         380 :         status = streams_xattr_get_name(handle, talloc_tos(),
     493         380 :                                         smb_fname->stream_name, &xattr_name);
     494         380 :         if (!NT_STATUS_IS_OK(status)) {
     495           0 :                 errno = map_errno_from_nt_status(status);
     496           0 :                 goto fail;
     497             :         }
     498             : 
     499         380 :         SMB_ASSERT(smb_fname->fsp != NULL);
     500         380 :         SMB_ASSERT(smb_fname->fsp->base_fsp != NULL);
     501             : 
     502         380 :         ret = SMB_VFS_FREMOVEXATTR(smb_fname->fsp->base_fsp, xattr_name);
     503             : 
     504         380 :         if ((ret == -1) && (errno == ENOATTR)) {
     505           0 :                 errno = ENOENT;
     506           0 :                 goto fail;
     507             :         }
     508             : 
     509         380 :         ret = 0;
     510             : 
     511         380 :  fail:
     512         380 :         TALLOC_FREE(xattr_name);
     513         380 :         return ret;
     514             : }
     515             : 
     516        1361 : static int streams_xattr_unlinkat(vfs_handle_struct *handle,
     517             :                         struct files_struct *dirfsp,
     518             :                         const struct smb_filename *smb_fname,
     519             :                         int flags)
     520             : {
     521             :         int ret;
     522        1361 :         if (flags & AT_REMOVEDIR) {
     523         174 :                 ret = SMB_VFS_NEXT_UNLINKAT(handle,
     524             :                                 dirfsp,
     525             :                                 smb_fname,
     526             :                                 flags);
     527             :         } else {
     528        1187 :                 ret = streams_xattr_unlink_internal(handle,
     529             :                                 dirfsp,
     530             :                                 smb_fname,
     531             :                                 flags);
     532             :         }
     533        1361 :         return ret;
     534             : }
     535             : 
     536           6 : static int streams_xattr_renameat(vfs_handle_struct *handle,
     537             :                                 files_struct *srcfsp,
     538             :                                 const struct smb_filename *smb_fname_src,
     539             :                                 files_struct *dstfsp,
     540             :                                 const struct smb_filename *smb_fname_dst)
     541             : {
     542             :         NTSTATUS status;
     543           6 :         int ret = -1;
     544           6 :         char *src_xattr_name = NULL;
     545           6 :         char *dst_xattr_name = NULL;
     546             :         bool src_is_stream, dst_is_stream;
     547             :         ssize_t oret;
     548             :         ssize_t nret;
     549             :         struct ea_struct ea;
     550           6 :         struct smb_filename *pathref_src = NULL;
     551           6 :         struct smb_filename *pathref_dst = NULL;
     552           6 :         struct smb_filename *full_src = NULL;
     553           6 :         struct smb_filename *full_dst = NULL;
     554             : 
     555           6 :         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
     556           6 :         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
     557             : 
     558           6 :         if (!src_is_stream && !dst_is_stream) {
     559           6 :                 return SMB_VFS_NEXT_RENAMEAT(handle,
     560             :                                         srcfsp,
     561             :                                         smb_fname_src,
     562             :                                         dstfsp,
     563             :                                         smb_fname_dst);
     564             :         }
     565             : 
     566             :         /* For now don't allow renames from or to the default stream. */
     567           0 :         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
     568           0 :             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
     569           0 :                 errno = ENOSYS;
     570           0 :                 goto done;
     571             :         }
     572             : 
     573             :         /* Don't rename if the streams are identical. */
     574           0 :         if (strcasecmp_m(smb_fname_src->stream_name,
     575           0 :                        smb_fname_dst->stream_name) == 0) {
     576           0 :                 goto done;
     577             :         }
     578             : 
     579             :         /* Get the xattr names. */
     580           0 :         status = streams_xattr_get_name(handle, talloc_tos(),
     581           0 :                                         smb_fname_src->stream_name,
     582             :                                         &src_xattr_name);
     583           0 :         if (!NT_STATUS_IS_OK(status)) {
     584           0 :                 errno = map_errno_from_nt_status(status);
     585           0 :                 goto fail;
     586             :         }
     587           0 :         status = streams_xattr_get_name(handle, talloc_tos(),
     588           0 :                                         smb_fname_dst->stream_name,
     589             :                                         &dst_xattr_name);
     590           0 :         if (!NT_STATUS_IS_OK(status)) {
     591           0 :                 errno = map_errno_from_nt_status(status);
     592           0 :                 goto fail;
     593             :         }
     594             : 
     595           0 :         full_src = full_path_from_dirfsp_atname(talloc_tos(),
     596             :                                                 srcfsp,
     597             :                                                 smb_fname_src);
     598           0 :         if (full_src == NULL) {
     599           0 :                 errno = ENOMEM;
     600           0 :                 goto fail;
     601             :         }
     602           0 :         full_dst = full_path_from_dirfsp_atname(talloc_tos(),
     603             :                                                 dstfsp,
     604             :                                                 smb_fname_dst);
     605           0 :         if (full_dst == NULL) {
     606           0 :                 errno = ENOMEM;
     607           0 :                 goto fail;
     608             :         }
     609             : 
     610             :         /* Get a pathref for full_src (base file, no stream name). */
     611           0 :         status = synthetic_pathref(talloc_tos(),
     612           0 :                                 handle->conn->cwd_fsp,
     613           0 :                                 full_src->base_name,
     614             :                                 NULL,
     615             :                                 NULL,
     616             :                                 full_src->twrp,
     617             :                                 full_src->flags,
     618             :                                 &pathref_src);
     619           0 :         if (!NT_STATUS_IS_OK(status)) {
     620           0 :                 errno = ENOENT;
     621           0 :                 goto fail;
     622             :         }
     623             : 
     624             :         /* Read the old stream from the base file fsp. */
     625           0 :         status = get_ea_value_fsp(talloc_tos(),
     626           0 :                                   pathref_src->fsp,
     627             :                                   src_xattr_name,
     628             :                                   &ea);
     629           0 :         if (!NT_STATUS_IS_OK(status)) {
     630           0 :                 errno = map_errno_from_nt_status(status);
     631           0 :                 goto fail;
     632             :         }
     633             : 
     634             :         /* Get a pathref for full_dst (base file, no stream name). */
     635           0 :         status = synthetic_pathref(talloc_tos(),
     636           0 :                                 handle->conn->cwd_fsp,
     637           0 :                                 full_dst->base_name,
     638             :                                 NULL,
     639             :                                 NULL,
     640             :                                 full_dst->twrp,
     641             :                                 full_dst->flags,
     642             :                                 &pathref_dst);
     643           0 :         if (!NT_STATUS_IS_OK(status)) {
     644           0 :                 errno = ENOENT;
     645           0 :                 goto fail;
     646             :         }
     647             : 
     648             :         /* (Over)write the new stream on the base file fsp. */
     649           0 :         nret = SMB_VFS_FSETXATTR(
     650             :                         pathref_dst->fsp,
     651             :                         dst_xattr_name,
     652             :                         ea.value.data,
     653             :                         ea.value.length,
     654             :                         0);
     655           0 :         if (nret < 0) {
     656           0 :                 if (errno == ENOATTR) {
     657           0 :                         errno = ENOENT;
     658             :                 }
     659           0 :                 goto fail;
     660             :         }
     661             : 
     662             :         /*
     663             :          * Remove the old stream from the base file fsp.
     664             :          */
     665           0 :         oret = SMB_VFS_FREMOVEXATTR(pathref_src->fsp,
     666             :                                     src_xattr_name);
     667           0 :         if (oret < 0) {
     668           0 :                 if (errno == ENOATTR) {
     669           0 :                         errno = ENOENT;
     670             :                 }
     671           0 :                 goto fail;
     672             :         }
     673             : 
     674           0 :  done:
     675           0 :         errno = 0;
     676           0 :         ret = 0;
     677           0 :  fail:
     678           0 :         TALLOC_FREE(pathref_src);
     679           0 :         TALLOC_FREE(pathref_dst);
     680           0 :         TALLOC_FREE(full_src);
     681           0 :         TALLOC_FREE(full_dst);
     682           0 :         TALLOC_FREE(src_xattr_name);
     683           0 :         TALLOC_FREE(dst_xattr_name);
     684           0 :         return ret;
     685             : }
     686             : 
     687        4727 : static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle,
     688             :                                 files_struct *fsp,
     689             :                                 const struct smb_filename *smb_fname,
     690             :                                 bool (*fn)(struct ea_struct *ea,
     691             :                                         void *private_data),
     692             :                                 void *private_data)
     693             : {
     694             :         NTSTATUS status;
     695             :         char **names;
     696             :         size_t i, num_names;
     697             :         struct streams_xattr_config *config;
     698             : 
     699        4727 :         SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
     700             :                                 return NT_STATUS_UNSUCCESSFUL);
     701             : 
     702        4727 :         status = get_ea_names_from_fsp(talloc_tos(),
     703        4727 :                                 smb_fname->fsp,
     704             :                                 &names,
     705             :                                 &num_names);
     706        4727 :         if (!NT_STATUS_IS_OK(status)) {
     707           0 :                 return status;
     708             :         }
     709             : 
     710       15542 :         for (i=0; i<num_names; i++) {
     711             :                 struct ea_struct ea;
     712             : 
     713             :                 /*
     714             :                  * We want to check with samba_private_attr_name()
     715             :                  * whether the xattr name is a private one,
     716             :                  * unfortunately it flags xattrs that begin with the
     717             :                  * default streams prefix as private.
     718             :                  *
     719             :                  * By only calling samba_private_attr_name() in case
     720             :                  * the xattr does NOT begin with the default prefix,
     721             :                  * we know that if it returns 'true' it definitely one
     722             :                  * of our internal xattr like "user.DOSATTRIB".
     723             :                  */
     724       10815 :                 if (strncasecmp_m(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
     725             :                                   strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) != 0) {
     726        9955 :                         if (samba_private_attr_name(names[i])) {
     727       18954 :                                 continue;
     728             :                         }
     729             :                 }
     730             : 
     731        1810 :                 if (strncmp(names[i], config->prefix,
     732             :                             config->prefix_len) != 0) {
     733         950 :                         continue;
     734             :                 }
     735             : 
     736        1716 :                 status = get_ea_value_fsp(names,
     737         860 :                                           smb_fname->fsp,
     738         860 :                                           names[i],
     739             :                                           &ea);
     740         860 :                 if (!NT_STATUS_IS_OK(status)) {
     741           0 :                         DEBUG(10, ("Could not get ea %s for file %s: %s\n",
     742             :                                 names[i],
     743             :                                 smb_fname->base_name,
     744             :                                 nt_errstr(status)));
     745           0 :                         continue;
     746             :                 }
     747             : 
     748        2572 :                 ea.name = talloc_asprintf(
     749         860 :                         ea.value.data, ":%s%s",
     750         860 :                         names[i] + config->prefix_len,
     751         860 :                         config->store_stream_type ? "" : ":$DATA");
     752         860 :                 if (ea.name == NULL) {
     753           0 :                         DEBUG(0, ("talloc failed\n"));
     754           0 :                         continue;
     755             :                 }
     756             : 
     757         860 :                 if (!fn(&ea, private_data)) {
     758           0 :                         TALLOC_FREE(ea.value.data);
     759           0 :                         return NT_STATUS_OK;
     760             :                 }
     761             : 
     762         860 :                 TALLOC_FREE(ea.value.data);
     763             :         }
     764             : 
     765        4727 :         TALLOC_FREE(names);
     766        4727 :         return NT_STATUS_OK;
     767             : }
     768             : 
     769         860 : static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
     770             :                            struct stream_struct **streams,
     771             :                            const char *name, off_t size,
     772             :                            off_t alloc_size)
     773             : {
     774             :         struct stream_struct *tmp;
     775             : 
     776         860 :         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
     777             :                                    (*num_streams)+1);
     778         860 :         if (tmp == NULL) {
     779           0 :                 return false;
     780             :         }
     781             : 
     782         860 :         tmp[*num_streams].name = talloc_strdup(tmp, name);
     783         860 :         if (tmp[*num_streams].name == NULL) {
     784           0 :                 return false;
     785             :         }
     786             : 
     787         860 :         tmp[*num_streams].size = size;
     788         860 :         tmp[*num_streams].alloc_size = alloc_size;
     789             : 
     790         860 :         *streams = tmp;
     791         860 :         *num_streams += 1;
     792         860 :         return true;
     793             : }
     794             : 
     795             : struct streaminfo_state {
     796             :         TALLOC_CTX *mem_ctx;
     797             :         vfs_handle_struct *handle;
     798             :         unsigned int num_streams;
     799             :         struct stream_struct *streams;
     800             :         NTSTATUS status;
     801             : };
     802             : 
     803         860 : static bool collect_one_stream(struct ea_struct *ea, void *private_data)
     804             : {
     805         860 :         struct streaminfo_state *state =
     806             :                 (struct streaminfo_state *)private_data;
     807             : 
     808        2572 :         if (!add_one_stream(state->mem_ctx,
     809             :                             &state->num_streams, &state->streams,
     810        1716 :                             ea->name, ea->value.length-1,
     811         860 :                             smb_roundup(state->handle->conn,
     812         860 :                                         ea->value.length-1))) {
     813           0 :                 state->status = NT_STATUS_NO_MEMORY;
     814           0 :                 return false;
     815             :         }
     816             : 
     817         860 :         return true;
     818             : }
     819             : 
     820        4727 : static NTSTATUS streams_xattr_fstreaminfo(vfs_handle_struct *handle,
     821             :                                          struct files_struct *fsp,
     822             :                                          TALLOC_CTX *mem_ctx,
     823             :                                          unsigned int *pnum_streams,
     824             :                                          struct stream_struct **pstreams)
     825             : {
     826             :         NTSTATUS status;
     827             :         struct streaminfo_state state;
     828             : 
     829        4727 :         state.streams = *pstreams;
     830        4727 :         state.num_streams = *pnum_streams;
     831        4727 :         state.mem_ctx = mem_ctx;
     832        4727 :         state.handle = handle;
     833        4727 :         state.status = NT_STATUS_OK;
     834             : 
     835        4727 :         status = walk_xattr_streams(handle,
     836             :                                     fsp,
     837        4727 :                                     fsp->fsp_name,
     838             :                                     collect_one_stream,
     839             :                                     &state);
     840             : 
     841        4727 :         if (!NT_STATUS_IS_OK(status)) {
     842           0 :                 TALLOC_FREE(state.streams);
     843           0 :                 return status;
     844             :         }
     845             : 
     846        4727 :         if (!NT_STATUS_IS_OK(state.status)) {
     847           0 :                 TALLOC_FREE(state.streams);
     848           0 :                 return state.status;
     849             :         }
     850             : 
     851        4727 :         *pnum_streams = state.num_streams;
     852        4727 :         *pstreams = state.streams;
     853             : 
     854        4727 :         return SMB_VFS_NEXT_FSTREAMINFO(handle,
     855             :                         fsp,
     856             :                         mem_ctx,
     857             :                         pnum_streams,
     858             :                         pstreams);
     859             : }
     860             : 
     861         359 : static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle,
     862             :                         enum timestamp_set_resolution *p_ts_res)
     863             : {
     864         359 :         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
     865             : }
     866             : 
     867         359 : static int streams_xattr_connect(vfs_handle_struct *handle,
     868             :                                  const char *service, const char *user)
     869             : {
     870             :         struct streams_xattr_config *config;
     871         359 :         const char *default_prefix = SAMBA_XATTR_DOSSTREAM_PREFIX;
     872             :         const char *prefix;
     873             :         int rc;
     874             : 
     875         359 :         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
     876         359 :         if (rc != 0) {
     877           0 :                 return rc;
     878             :         }
     879             : 
     880         359 :         config = talloc_zero(handle->conn, struct streams_xattr_config);
     881         359 :         if (config == NULL) {
     882           0 :                 DEBUG(1, ("talloc_zero() failed\n"));
     883           0 :                 errno = ENOMEM;
     884           0 :                 return -1;
     885             :         }
     886             : 
     887         359 :         prefix = lp_parm_const_string(SNUM(handle->conn),
     888             :                                       "streams_xattr", "prefix",
     889             :                                       default_prefix);
     890         359 :         config->prefix = talloc_strdup(config, prefix);
     891         359 :         if (config->prefix == NULL) {
     892           0 :                 DEBUG(1, ("talloc_strdup() failed\n"));
     893           0 :                 errno = ENOMEM;
     894           0 :                 return -1;
     895             :         }
     896         359 :         config->prefix_len = strlen(config->prefix);
     897         359 :         DEBUG(10, ("streams_xattr using stream prefix: %s\n", config->prefix));
     898             : 
     899         359 :         config->store_stream_type = lp_parm_bool(SNUM(handle->conn),
     900             :                                                  "streams_xattr",
     901             :                                                  "store_stream_type",
     902             :                                                  true);
     903             : 
     904         359 :         SMB_VFS_HANDLE_SET_DATA(handle, config,
     905             :                                 NULL, struct stream_xattr_config,
     906             :                                 return -1);
     907             : 
     908         359 :         return 0;
     909             : }
     910             : 
     911         832 : static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
     912             :                                     files_struct *fsp, const void *data,
     913             :                                     size_t n, off_t offset)
     914             : {
     915         830 :         struct stream_io *sio =
     916           2 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
     917             :         struct ea_struct ea;
     918             :         NTSTATUS status;
     919             :         int ret;
     920             : 
     921         832 :         DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
     922             : 
     923         832 :         if (sio == NULL) {
     924         442 :                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
     925             :         }
     926             : 
     927         390 :         if (!streams_xattr_recheck(sio)) {
     928           0 :                 return -1;
     929             :         }
     930             : 
     931         390 :         if ((offset + n) >= lp_smbd_max_xattr_size(SNUM(handle->conn))) {
     932             :                 /*
     933             :                  * Requested write is beyond what can be read based on
     934             :                  * samba configuration.
     935             :                  * ReFS returns STATUS_FILESYSTEM_LIMITATION, which causes
     936             :                  * entire file to be skipped by File Explorer. VFAT returns
     937             :                  * NT_STATUS_OBJECT_NAME_COLLISION causes user to be prompted
     938             :                  * to skip writing metadata, but copy data.
     939             :                  */
     940           0 :                 DBG_ERR("Write to xattr [%s] on file [%s] exceeds maximum "
     941             :                         "supported extended attribute size. "
     942             :                         "Depending on filesystem type and operating system "
     943             :                         "(OS) specifics, this value may be increased using "
     944             :                         "the value of the parameter: "
     945             :                         "smbd max xattr size = <bytes>. Consult OS and "
     946             :                         "filesystem manpages prior to increasing this limit.\n",
     947             :                         sio->xattr_name, sio->base);
     948           0 :                 errno = EOVERFLOW;
     949           0 :                 return -1;
     950             :         }
     951             : 
     952         390 :         status = get_ea_value_fsp(talloc_tos(),
     953         390 :                                   fsp->base_fsp,
     954         390 :                                   sio->xattr_name,
     955             :                                   &ea);
     956         390 :         if (!NT_STATUS_IS_OK(status)) {
     957           0 :                 return -1;
     958             :         }
     959             : 
     960         390 :         if ((offset + n) > ea.value.length-1) {
     961             :                 uint8_t *tmp;
     962             : 
     963         374 :                 tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
     964             :                                            offset + n + 1);
     965             : 
     966         374 :                 if (tmp == NULL) {
     967           0 :                         TALLOC_FREE(ea.value.data);
     968           0 :                         errno = ENOMEM;
     969           0 :                         return -1;
     970             :                 }
     971         374 :                 ea.value.data = tmp;
     972         374 :                 ea.value.length = offset + n + 1;
     973         374 :                 ea.value.data[offset+n] = 0;
     974             :         }
     975             : 
     976         390 :         memcpy(ea.value.data + offset, data, n);
     977             : 
     978         390 :         ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
     979             :                                 sio->xattr_name,
     980             :                                 ea.value.data,
     981             :                                 ea.value.length,
     982             :                                 0);
     983         390 :         TALLOC_FREE(ea.value.data);
     984             : 
     985         390 :         if (ret == -1) {
     986           0 :                 return -1;
     987             :         }
     988             : 
     989         390 :         return n;
     990             : }
     991             : 
     992        3466 : static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
     993             :                                    files_struct *fsp, void *data,
     994             :                                    size_t n, off_t offset)
     995             : {
     996        3466 :         struct stream_io *sio =
     997           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
     998             :         struct ea_struct ea;
     999             :         NTSTATUS status;
    1000             :         size_t length, overlap;
    1001             : 
    1002        3466 :         DEBUG(10, ("streams_xattr_pread: offset=%d, size=%d\n",
    1003             :                    (int)offset, (int)n));
    1004             : 
    1005        3466 :         if (sio == NULL) {
    1006        3146 :                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
    1007             :         }
    1008             : 
    1009         320 :         if (!streams_xattr_recheck(sio)) {
    1010           0 :                 return -1;
    1011             :         }
    1012             : 
    1013         320 :         status = get_ea_value_fsp(talloc_tos(),
    1014         320 :                                   fsp->base_fsp,
    1015         320 :                                   sio->xattr_name,
    1016             :                                   &ea);
    1017         320 :         if (!NT_STATUS_IS_OK(status)) {
    1018           0 :                 return -1;
    1019             :         }
    1020             : 
    1021         320 :         length = ea.value.length-1;
    1022             : 
    1023         320 :         DBG_DEBUG("get_ea_value_fsp returned %d bytes\n",
    1024             :                    (int)length);
    1025             : 
    1026             :         /* Attempt to read past EOF. */
    1027         320 :         if (length <= offset) {
    1028           0 :                 return 0;
    1029             :         }
    1030             : 
    1031         320 :         overlap = (offset + n) > length ? (length - offset) : n;
    1032         320 :         memcpy(data, ea.value.data + offset, overlap);
    1033             : 
    1034         320 :         TALLOC_FREE(ea.value.data);
    1035         320 :         return overlap;
    1036             : }
    1037             : 
    1038             : struct streams_xattr_pread_state {
    1039             :         ssize_t nread;
    1040             :         struct vfs_aio_state vfs_aio_state;
    1041             : };
    1042             : 
    1043             : static void streams_xattr_pread_done(struct tevent_req *subreq);
    1044             : 
    1045          12 : static struct tevent_req *streams_xattr_pread_send(
    1046             :         struct vfs_handle_struct *handle,
    1047             :         TALLOC_CTX *mem_ctx,
    1048             :         struct tevent_context *ev,
    1049             :         struct files_struct *fsp,
    1050             :         void *data,
    1051             :         size_t n, off_t offset)
    1052             : {
    1053          12 :         struct tevent_req *req = NULL;
    1054          12 :         struct tevent_req *subreq = NULL;
    1055          12 :         struct streams_xattr_pread_state *state = NULL;
    1056          12 :         struct stream_io *sio =
    1057           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1058             : 
    1059          12 :         req = tevent_req_create(mem_ctx, &state,
    1060             :                                 struct streams_xattr_pread_state);
    1061          12 :         if (req == NULL) {
    1062           0 :                 return NULL;
    1063             :         }
    1064             : 
    1065          12 :         if (sio == NULL) {
    1066           6 :                 subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp,
    1067             :                                                  data, n, offset);
    1068           6 :                 if (tevent_req_nomem(req, subreq)) {
    1069           0 :                         return tevent_req_post(req, ev);
    1070             :                 }
    1071           6 :                 tevent_req_set_callback(subreq, streams_xattr_pread_done, req);
    1072           6 :                 return req;
    1073             :         }
    1074             : 
    1075           6 :         state->nread = SMB_VFS_PREAD(fsp, data, n, offset);
    1076           6 :         if (state->nread != n) {
    1077           0 :                 if (state->nread != -1) {
    1078           0 :                         errno = EIO;
    1079             :                 }
    1080           0 :                 tevent_req_error(req, errno);
    1081           0 :                 return tevent_req_post(req, ev);
    1082             :         }
    1083             : 
    1084           6 :         tevent_req_done(req);
    1085           6 :         return tevent_req_post(req, ev);
    1086             : }
    1087             : 
    1088           6 : static void streams_xattr_pread_done(struct tevent_req *subreq)
    1089             : {
    1090           6 :         struct tevent_req *req = tevent_req_callback_data(
    1091             :                 subreq, struct tevent_req);
    1092           6 :         struct streams_xattr_pread_state *state = tevent_req_data(
    1093             :                 req, struct streams_xattr_pread_state);
    1094             : 
    1095           6 :         state->nread = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
    1096           6 :         TALLOC_FREE(subreq);
    1097             : 
    1098           6 :         if (tevent_req_error(req, state->vfs_aio_state.error)) {
    1099           0 :                 return;
    1100             :         }
    1101           6 :         tevent_req_done(req);
    1102             : }
    1103             : 
    1104          12 : static ssize_t streams_xattr_pread_recv(struct tevent_req *req,
    1105             :                                         struct vfs_aio_state *vfs_aio_state)
    1106             : {
    1107          12 :         struct streams_xattr_pread_state *state = tevent_req_data(
    1108             :                 req, struct streams_xattr_pread_state);
    1109             : 
    1110          12 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
    1111           0 :                 return -1;
    1112             :         }
    1113             : 
    1114          12 :         *vfs_aio_state = state->vfs_aio_state;
    1115          12 :         return state->nread;
    1116             : }
    1117             : 
    1118             : struct streams_xattr_pwrite_state {
    1119             :         ssize_t nwritten;
    1120             :         struct vfs_aio_state vfs_aio_state;
    1121             : };
    1122             : 
    1123             : static void streams_xattr_pwrite_done(struct tevent_req *subreq);
    1124             : 
    1125          34 : static struct tevent_req *streams_xattr_pwrite_send(
    1126             :         struct vfs_handle_struct *handle,
    1127             :         TALLOC_CTX *mem_ctx,
    1128             :         struct tevent_context *ev,
    1129             :         struct files_struct *fsp,
    1130             :         const void *data,
    1131             :         size_t n, off_t offset)
    1132             : {
    1133          34 :         struct tevent_req *req = NULL;
    1134          34 :         struct tevent_req *subreq = NULL;
    1135          34 :         struct streams_xattr_pwrite_state *state = NULL;
    1136          34 :         struct stream_io *sio =
    1137           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1138             : 
    1139          34 :         req = tevent_req_create(mem_ctx, &state,
    1140             :                                 struct streams_xattr_pwrite_state);
    1141          34 :         if (req == NULL) {
    1142           0 :                 return NULL;
    1143             :         }
    1144             : 
    1145          34 :         if (sio == NULL) {
    1146          28 :                 subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp,
    1147             :                                                   data, n, offset);
    1148          28 :                 if (tevent_req_nomem(req, subreq)) {
    1149           0 :                         return tevent_req_post(req, ev);
    1150             :                 }
    1151          28 :                 tevent_req_set_callback(subreq, streams_xattr_pwrite_done, req);
    1152          28 :                 return req;
    1153             :         }
    1154             : 
    1155           6 :         state->nwritten = SMB_VFS_PWRITE(fsp, data, n, offset);
    1156           6 :         if (state->nwritten != n) {
    1157           0 :                 if (state->nwritten != -1) {
    1158           0 :                         errno = EIO;
    1159             :                 }
    1160           0 :                 tevent_req_error(req, errno);
    1161           0 :                 return tevent_req_post(req, ev);
    1162             :         }
    1163             : 
    1164           6 :         tevent_req_done(req);
    1165           6 :         return tevent_req_post(req, ev);
    1166             : }
    1167             : 
    1168          28 : static void streams_xattr_pwrite_done(struct tevent_req *subreq)
    1169             : {
    1170          28 :         struct tevent_req *req = tevent_req_callback_data(
    1171             :                 subreq, struct tevent_req);
    1172          28 :         struct streams_xattr_pwrite_state *state = tevent_req_data(
    1173             :                 req, struct streams_xattr_pwrite_state);
    1174             : 
    1175          28 :         state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
    1176          28 :         TALLOC_FREE(subreq);
    1177             : 
    1178          28 :         if (tevent_req_error(req, state->vfs_aio_state.error)) {
    1179           0 :                 return;
    1180             :         }
    1181          28 :         tevent_req_done(req);
    1182             : }
    1183             : 
    1184          34 : static ssize_t streams_xattr_pwrite_recv(struct tevent_req *req,
    1185             :                                          struct vfs_aio_state *vfs_aio_state)
    1186             : {
    1187          34 :         struct streams_xattr_pwrite_state *state = tevent_req_data(
    1188             :                 req, struct streams_xattr_pwrite_state);
    1189             : 
    1190          34 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
    1191           0 :                 return -1;
    1192             :         }
    1193             : 
    1194          34 :         *vfs_aio_state = state->vfs_aio_state;
    1195          34 :         return state->nwritten;
    1196             : }
    1197             : 
    1198         108 : static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
    1199             :                                         struct files_struct *fsp,
    1200             :                                         off_t offset)
    1201             : {
    1202             :         int ret;
    1203             :         uint8_t *tmp;
    1204             :         struct ea_struct ea;
    1205             :         NTSTATUS status;
    1206         108 :         struct stream_io *sio =
    1207           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1208             : 
    1209         108 :         DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
    1210             :                    fsp_str_dbg(fsp), (double)offset));
    1211             : 
    1212         108 :         if (sio == NULL) {
    1213          62 :                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
    1214             :         }
    1215             : 
    1216          46 :         if (!streams_xattr_recheck(sio)) {
    1217           0 :                 return -1;
    1218             :         }
    1219             : 
    1220          46 :         status = get_ea_value_fsp(talloc_tos(),
    1221          46 :                                   fsp->base_fsp,
    1222          46 :                                   sio->xattr_name,
    1223             :                                   &ea);
    1224          46 :         if (!NT_STATUS_IS_OK(status)) {
    1225           0 :                 return -1;
    1226             :         }
    1227             : 
    1228          46 :         tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
    1229             :                                    offset + 1);
    1230             : 
    1231          46 :         if (tmp == NULL) {
    1232           0 :                 TALLOC_FREE(ea.value.data);
    1233           0 :                 errno = ENOMEM;
    1234           0 :                 return -1;
    1235             :         }
    1236             : 
    1237             :         /* Did we expand ? */
    1238          46 :         if (ea.value.length < offset + 1) {
    1239          12 :                 memset(&tmp[ea.value.length], '\0',
    1240          12 :                         offset + 1 - ea.value.length);
    1241             :         }
    1242             : 
    1243          46 :         ea.value.data = tmp;
    1244          46 :         ea.value.length = offset + 1;
    1245          46 :         ea.value.data[offset] = 0;
    1246             : 
    1247          46 :         ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
    1248             :                                 sio->xattr_name,
    1249             :                                 ea.value.data,
    1250             :                                 ea.value.length,
    1251             :                                 0);
    1252             : 
    1253          46 :         TALLOC_FREE(ea.value.data);
    1254             : 
    1255          46 :         if (ret == -1) {
    1256           0 :                 return -1;
    1257             :         }
    1258             : 
    1259          46 :         return 0;
    1260             : }
    1261             : 
    1262           0 : static int streams_xattr_fallocate(struct vfs_handle_struct *handle,
    1263             :                                         struct files_struct *fsp,
    1264             :                                         uint32_t mode,
    1265             :                                         off_t offset,
    1266             :                                         off_t len)
    1267             : {
    1268           0 :         struct stream_io *sio =
    1269           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1270             : 
    1271           0 :         DEBUG(10, ("streams_xattr_fallocate called for file %s offset %.0f"
    1272             :                 "len = %.0f\n",
    1273             :                 fsp_str_dbg(fsp), (double)offset, (double)len));
    1274             : 
    1275           0 :         if (sio == NULL) {
    1276           0 :                 return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
    1277             :         }
    1278             : 
    1279           0 :         if (!streams_xattr_recheck(sio)) {
    1280           0 :                 return -1;
    1281             :         }
    1282             : 
    1283             :         /* Let the pwrite code path handle it. */
    1284           0 :         errno = ENOSYS;
    1285           0 :         return -1;
    1286             : }
    1287             : 
    1288        1084 : static int streams_xattr_fchown(vfs_handle_struct *handle, files_struct *fsp,
    1289             :                                 uid_t uid, gid_t gid)
    1290             : {
    1291        1084 :         struct stream_io *sio =
    1292           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1293             : 
    1294        1084 :         if (sio == NULL) {
    1295        1084 :                 return SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
    1296             :         }
    1297             : 
    1298           0 :         return 0;
    1299             : }
    1300             : 
    1301          70 : static int streams_xattr_fchmod(vfs_handle_struct *handle,
    1302             :                                 files_struct *fsp,
    1303             :                                 mode_t mode)
    1304             : {
    1305          68 :         struct stream_io *sio =
    1306           2 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1307             : 
    1308          70 :         if (sio == NULL) {
    1309           6 :                 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
    1310             :         }
    1311             : 
    1312          64 :         return 0;
    1313             : }
    1314             : 
    1315       91617 : static ssize_t streams_xattr_fgetxattr(struct vfs_handle_struct *handle,
    1316             :                                        struct files_struct *fsp,
    1317             :                                        const char *name,
    1318             :                                        void *value,
    1319             :                                        size_t size)
    1320             : {
    1321       91461 :         struct stream_io *sio =
    1322         156 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1323             : 
    1324       91617 :         if (sio == NULL) {
    1325       91201 :                 return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
    1326             :         }
    1327             : 
    1328         416 :         errno = ENOTSUP;
    1329         416 :         return -1;
    1330             : }
    1331             : 
    1332        4927 : static ssize_t streams_xattr_flistxattr(struct vfs_handle_struct *handle,
    1333             :                                         struct files_struct *fsp,
    1334             :                                         char *list,
    1335             :                                         size_t size)
    1336             : {
    1337        4905 :         struct stream_io *sio =
    1338          22 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1339             : 
    1340        4927 :         if (sio == NULL) {
    1341        4927 :                 return SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
    1342             :         }
    1343             : 
    1344           0 :         errno = ENOTSUP;
    1345           0 :         return -1;
    1346             : }
    1347             : 
    1348         500 : static int streams_xattr_fremovexattr(struct vfs_handle_struct *handle,
    1349             :                                       struct files_struct *fsp,
    1350             :                                       const char *name)
    1351             : {
    1352         498 :         struct stream_io *sio =
    1353           2 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1354             : 
    1355         500 :         if (sio == NULL) {
    1356         500 :                 return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
    1357             :         }
    1358             : 
    1359           0 :         errno = ENOTSUP;
    1360           0 :         return -1;
    1361             : }
    1362             : 
    1363        3591 : static int streams_xattr_fsetxattr(struct vfs_handle_struct *handle,
    1364             :                                    struct files_struct *fsp,
    1365             :                                    const char *name,
    1366             :                                    const void *value,
    1367             :                                    size_t size,
    1368             :                                    int flags)
    1369             : {
    1370        3580 :         struct stream_io *sio =
    1371          11 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1372             : 
    1373        3591 :         if (sio == NULL) {
    1374        3383 :                 return SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value,
    1375             :                                               size, flags);
    1376             :         }
    1377             : 
    1378         208 :         errno = ENOTSUP;
    1379         208 :         return -1;
    1380             : }
    1381             : 
    1382             : struct streams_xattr_fsync_state {
    1383             :         int ret;
    1384             :         struct vfs_aio_state vfs_aio_state;
    1385             : };
    1386             : 
    1387             : static void streams_xattr_fsync_done(struct tevent_req *subreq);
    1388             : 
    1389           0 : static struct tevent_req *streams_xattr_fsync_send(
    1390             :         struct vfs_handle_struct *handle,
    1391             :         TALLOC_CTX *mem_ctx,
    1392             :         struct tevent_context *ev,
    1393             :         struct files_struct *fsp)
    1394             : {
    1395           0 :         struct tevent_req *req = NULL;
    1396           0 :         struct tevent_req *subreq = NULL;
    1397           0 :         struct streams_xattr_fsync_state *state = NULL;
    1398           0 :         struct stream_io *sio =
    1399           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1400             : 
    1401           0 :         req = tevent_req_create(mem_ctx, &state,
    1402             :                                 struct streams_xattr_fsync_state);
    1403           0 :         if (req == NULL) {
    1404           0 :                 return NULL;
    1405             :         }
    1406             : 
    1407           0 :         if (sio == NULL) {
    1408           0 :                 subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
    1409           0 :                 if (tevent_req_nomem(req, subreq)) {
    1410           0 :                         return tevent_req_post(req, ev);
    1411             :                 }
    1412           0 :                 tevent_req_set_callback(subreq, streams_xattr_fsync_done, req);
    1413           0 :                 return req;
    1414             :         }
    1415             : 
    1416             :         /*
    1417             :          * There's no pathname based sync variant and we don't have access to
    1418             :          * the basefile handle, so we can't do anything here.
    1419             :          */
    1420             : 
    1421           0 :         tevent_req_done(req);
    1422           0 :         return tevent_req_post(req, ev);
    1423             : }
    1424             : 
    1425           0 : static void streams_xattr_fsync_done(struct tevent_req *subreq)
    1426             : {
    1427           0 :         struct tevent_req *req = tevent_req_callback_data(
    1428             :                 subreq, struct tevent_req);
    1429           0 :         struct streams_xattr_fsync_state *state = tevent_req_data(
    1430             :                 req, struct streams_xattr_fsync_state);
    1431             : 
    1432           0 :         state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
    1433           0 :         TALLOC_FREE(subreq);
    1434           0 :         if (state->ret != 0) {
    1435           0 :                 tevent_req_error(req, errno);
    1436           0 :                 return;
    1437             :         }
    1438             : 
    1439           0 :         tevent_req_done(req);
    1440             : }
    1441             : 
    1442           0 : static int streams_xattr_fsync_recv(struct tevent_req *req,
    1443             :                                     struct vfs_aio_state *vfs_aio_state)
    1444             : {
    1445           0 :         struct streams_xattr_fsync_state *state = tevent_req_data(
    1446             :                 req, struct streams_xattr_fsync_state);
    1447             : 
    1448           0 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
    1449           0 :                 return -1;
    1450             :         }
    1451             : 
    1452           0 :         *vfs_aio_state = state->vfs_aio_state;
    1453           0 :         return state->ret;
    1454             : }
    1455             : 
    1456        1330 : static bool streams_xattr_lock(vfs_handle_struct *handle,
    1457             :                                files_struct *fsp,
    1458             :                                int op,
    1459             :                                off_t offset,
    1460             :                                off_t count,
    1461             :                                int type)
    1462             : {
    1463        1330 :         struct stream_io *sio =
    1464           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1465             : 
    1466        1330 :         if (sio == NULL) {
    1467        1330 :                 return SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
    1468             :         }
    1469             : 
    1470           0 :         return true;
    1471             : }
    1472             : 
    1473        4496 : static bool streams_xattr_getlock(vfs_handle_struct *handle,
    1474             :                                   files_struct *fsp,
    1475             :                                   off_t *poffset,
    1476             :                                   off_t *pcount,
    1477             :                                   int *ptype,
    1478             :                                   pid_t *ppid)
    1479             : {
    1480        4496 :         struct stream_io *sio =
    1481           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1482             : 
    1483        4496 :         if (sio == NULL) {
    1484        4496 :                 return SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset,
    1485             :                                             pcount, ptype, ppid);
    1486             :         }
    1487             : 
    1488           0 :         errno = ENOTSUP;
    1489           0 :         return false;
    1490             : }
    1491             : 
    1492           0 : static int streams_xattr_filesystem_sharemode(vfs_handle_struct *handle,
    1493             :                                               files_struct *fsp,
    1494             :                                               uint32_t share_access,
    1495             :                                               uint32_t access_mask)
    1496             : {
    1497           0 :         struct stream_io *sio =
    1498           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1499             : 
    1500           0 :         if (sio == NULL) {
    1501           0 :                 return SMB_VFS_NEXT_FILESYSTEM_SHAREMODE(handle,
    1502             :                                                          fsp,
    1503             :                                                          share_access,
    1504             :                                                          access_mask);
    1505             :         }
    1506             : 
    1507           0 :         return 0;
    1508             : }
    1509             : 
    1510          14 : static int streams_xattr_linux_setlease(vfs_handle_struct *handle,
    1511             :                                         files_struct *fsp,
    1512             :                                         int leasetype)
    1513             : {
    1514          14 :         struct stream_io *sio =
    1515           0 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1516             : 
    1517          14 :         if (sio == NULL) {
    1518          12 :                 return SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
    1519             :         }
    1520             : 
    1521           2 :         return 0;
    1522             : }
    1523             : 
    1524        2792 : static bool streams_xattr_strict_lock_check(struct vfs_handle_struct *handle,
    1525             :                                             files_struct *fsp,
    1526             :                                             struct lock_struct *plock)
    1527             : {
    1528        2790 :         struct stream_io *sio =
    1529           2 :                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
    1530             : 
    1531        2792 :         if (sio == NULL) {
    1532        2394 :                 return SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
    1533             :         }
    1534             : 
    1535         398 :         return true;
    1536             : }
    1537             : 
    1538             : static struct vfs_fn_pointers vfs_streams_xattr_fns = {
    1539             :         .fs_capabilities_fn = streams_xattr_fs_capabilities,
    1540             :         .connect_fn = streams_xattr_connect,
    1541             :         .openat_fn = streams_xattr_openat,
    1542             :         .close_fn = streams_xattr_close,
    1543             :         .stat_fn = streams_xattr_stat,
    1544             :         .fstat_fn = streams_xattr_fstat,
    1545             :         .lstat_fn = streams_xattr_lstat,
    1546             :         .pread_fn = streams_xattr_pread,
    1547             :         .pwrite_fn = streams_xattr_pwrite,
    1548             :         .pread_send_fn = streams_xattr_pread_send,
    1549             :         .pread_recv_fn = streams_xattr_pread_recv,
    1550             :         .pwrite_send_fn = streams_xattr_pwrite_send,
    1551             :         .pwrite_recv_fn = streams_xattr_pwrite_recv,
    1552             :         .unlinkat_fn = streams_xattr_unlinkat,
    1553             :         .renameat_fn = streams_xattr_renameat,
    1554             :         .ftruncate_fn = streams_xattr_ftruncate,
    1555             :         .fallocate_fn = streams_xattr_fallocate,
    1556             :         .fstreaminfo_fn = streams_xattr_fstreaminfo,
    1557             : 
    1558             :         .fsync_send_fn = streams_xattr_fsync_send,
    1559             :         .fsync_recv_fn = streams_xattr_fsync_recv,
    1560             : 
    1561             :         .lock_fn = streams_xattr_lock,
    1562             :         .getlock_fn = streams_xattr_getlock,
    1563             :         .filesystem_sharemode_fn = streams_xattr_filesystem_sharemode,
    1564             :         .linux_setlease_fn = streams_xattr_linux_setlease,
    1565             :         .strict_lock_check_fn = streams_xattr_strict_lock_check,
    1566             : 
    1567             :         .fchown_fn = streams_xattr_fchown,
    1568             :         .fchmod_fn = streams_xattr_fchmod,
    1569             : 
    1570             :         .fgetxattr_fn = streams_xattr_fgetxattr,
    1571             :         .flistxattr_fn = streams_xattr_flistxattr,
    1572             :         .fremovexattr_fn = streams_xattr_fremovexattr,
    1573             :         .fsetxattr_fn = streams_xattr_fsetxattr,
    1574             : };
    1575             : 
    1576             : static_decl_vfs;
    1577         319 : NTSTATUS vfs_streams_xattr_init(TALLOC_CTX *ctx)
    1578             : {
    1579         319 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
    1580             :                                 &vfs_streams_xattr_fns);
    1581             : }

Generated by: LCOV version 1.13