LCOV - code coverage report
Current view: top level - source3/modules - vfs_streams_xattr.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 258 684 37.7 %
Date: 2024-06-13 04:01:37 Functions: 24 43 55.8 %

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

Generated by: LCOV version 1.13