LCOV - code coverage report
Current view: top level - source3/modules - vfs_streams_depot.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 433 561 77.2 %
Date: 2023-11-21 12:31:41 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Store streams in a separate subdirectory
       3             :  *
       4             :  * Copyright (C) Volker Lendecke, 2007
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "includes.h"
      21             : #include "smbd/smbd.h"
      22             : #include "system/filesys.h"
      23             : 
      24             : #undef DBGC_CLASS
      25             : #define DBGC_CLASS DBGC_VFS
      26             : 
      27             : /*
      28             :  * Excerpt from a mail from tridge:
      29             :  *
      30             :  * Volker, what I'm thinking of is this:
      31             :  * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
      32             :  * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
      33             :  *
      34             :  * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
      35             :  * is the fsid/inode. "namedstreamX" is a file named after the stream
      36             :  * name.
      37             :  */
      38             : 
      39      463702 : static uint32_t hash_fn(DATA_BLOB key)
      40             : {
      41        1183 :         uint32_t value; /* Used to compute the hash value.  */
      42        1183 :         uint32_t i;     /* Used to cycle through random values. */
      43             : 
      44             :         /* Set the initial value from the key size. */
      45     7882934 :         for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
      46     7419232 :                 value = (value + (key.data[i] << (i*5 % 24)));
      47             : 
      48      463702 :         return (1103515243 * value + 12345);
      49             : }
      50             : 
      51             : /*
      52             :  * With the hashing scheme based on the inode we need to protect against
      53             :  * streams showing up on files with re-used inodes. This can happen if we
      54             :  * create a stream directory from within Samba, and a local process or NFS
      55             :  * client deletes the file without deleting the streams directory. When the
      56             :  * inode is re-used and the stream directory is still around, the streams in
      57             :  * there would be show up as belonging to the new file.
      58             :  *
      59             :  * There are several workarounds for this, probably the easiest one is on
      60             :  * systems which have a true birthtime stat element: When the file has a later
      61             :  * birthtime than the streams directory, then we have to recreate the
      62             :  * directory.
      63             :  *
      64             :  * The other workaround is to somehow mark the file as generated by Samba with
      65             :  * something that a NFS client would not do. The closest one is a special
      66             :  * xattr value being set. On systems which do not support xattrs, it might be
      67             :  * an option to put in a special ACL entry for a non-existing group.
      68             :  */
      69             : 
      70        6435 : static bool file_is_valid(vfs_handle_struct *handle,
      71             :                         const struct smb_filename *smb_fname)
      72             : {
      73           9 :         char buf;
      74           9 :         NTSTATUS status;
      75        6435 :         struct smb_filename *pathref = NULL;
      76           9 :         int ret;
      77             : 
      78        6435 :         DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
      79             : 
      80        6435 :         status = synthetic_pathref(talloc_tos(),
      81        6435 :                                 handle->conn->cwd_fsp,
      82        6435 :                                 smb_fname->base_name,
      83             :                                 NULL,
      84             :                                 NULL,
      85        6435 :                                 smb_fname->twrp,
      86        6435 :                                 smb_fname->flags,
      87             :                                 &pathref);
      88        6435 :         if (!NT_STATUS_IS_OK(status)) {
      89           0 :                 return false;
      90             :         }
      91        6435 :         ret = SMB_VFS_FGETXATTR(pathref->fsp,
      92             :                                 SAMBA_XATTR_MARKER,
      93             :                                 &buf,
      94             :                                 sizeof(buf));
      95        6435 :         if (ret != sizeof(buf)) {
      96           8 :                 int saved_errno = errno;
      97           8 :                 DBG_DEBUG("FGETXATTR failed: %s\n", strerror(saved_errno));
      98           8 :                 TALLOC_FREE(pathref);
      99           8 :                 errno = saved_errno;
     100           8 :                 return false;
     101             :         }
     102             : 
     103        6427 :         TALLOC_FREE(pathref);
     104             : 
     105        6427 :         if (buf != '1') {
     106           0 :                 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
     107           0 :                 return false;
     108             :         }
     109             : 
     110        6418 :         return true;
     111             : }
     112             : 
     113             : /*
     114             :  * Return the root of the stream directory. Can be
     115             :  * external to the share definition but by default
     116             :  * is "handle->conn->connectpath/.streams".
     117             :  *
     118             :  * Note that this is an *absolute* path, starting
     119             :  * with '/', so the dirfsp being used in the
     120             :  * calls below isn't looked at.
     121             :  */
     122             : 
     123      465609 : static char *stream_rootdir(vfs_handle_struct *handle,
     124             :                             TALLOC_CTX *ctx)
     125             : {
     126        1186 :         const struct loadparm_substitution *lp_sub =
     127      465609 :                 loadparm_s3_global_substitution();
     128        1186 :         char *tmp;
     129             : 
     130      466795 :         tmp = talloc_asprintf(ctx,
     131             :                               "%s/.streams",
     132      465609 :                               handle->conn->connectpath);
     133      465609 :         if (tmp == NULL) {
     134           0 :                 errno = ENOMEM;
     135           0 :                 return NULL;
     136             :         }
     137             : 
     138      465609 :         return lp_parm_substituted_string(ctx,
     139             :                                           lp_sub,
     140      465609 :                                           SNUM(handle->conn),
     141             :                                           "streams_depot",
     142             :                                           "directory",
     143             :                                           tmp);
     144             : }
     145             : 
     146             : /**
     147             :  * Given an smb_filename, determine the stream directory using the file's
     148             :  * base_name.
     149             :  */
     150      463702 : static char *stream_dir(vfs_handle_struct *handle,
     151             :                         const struct smb_filename *smb_fname,
     152             :                         const SMB_STRUCT_STAT *base_sbuf, bool create_it)
     153             : {
     154        1183 :         uint32_t hash;
     155      463702 :         struct smb_filename *smb_fname_hash = NULL;
     156      463702 :         char *result = NULL;
     157        1183 :         SMB_STRUCT_STAT base_sbuf_tmp;
     158      463702 :         char *tmp = NULL;
     159        1183 :         uint8_t first, second;
     160        1183 :         char *id_hex;
     161        1183 :         struct file_id id;
     162        1183 :         uint8_t id_buf[16];
     163        1183 :         bool check_valid;
     164      463702 :         char *rootdir = NULL;
     165      463702 :         struct smb_filename *rootdir_fname = NULL;
     166      463702 :         struct smb_filename *tmp_fname = NULL;
     167        1183 :         int ret;
     168             : 
     169      463702 :         check_valid = lp_parm_bool(SNUM(handle->conn),
     170             :                       "streams_depot", "check_valid", true);
     171             : 
     172      463702 :         rootdir = stream_rootdir(handle,
     173             :                                  talloc_tos());
     174      463702 :         if (rootdir == NULL) {
     175           0 :                 errno = ENOMEM;
     176           0 :                 goto fail;
     177             :         }
     178             : 
     179      463702 :         rootdir_fname = synthetic_smb_fname(talloc_tos(),
     180             :                                         rootdir,
     181             :                                         NULL,
     182             :                                         NULL,
     183      463702 :                                         smb_fname->twrp,
     184      463702 :                                         smb_fname->flags);
     185      463702 :         if (rootdir_fname == NULL) {
     186           0 :                 errno = ENOMEM;
     187           0 :                 goto fail;
     188             :         }
     189             : 
     190             :         /* Stat the base file if it hasn't already been done. */
     191      463702 :         if (base_sbuf == NULL) {
     192           2 :                 struct smb_filename *smb_fname_base;
     193             : 
     194        1128 :                 smb_fname_base = synthetic_smb_fname(
     195             :                                         talloc_tos(),
     196        1128 :                                         smb_fname->base_name,
     197             :                                         NULL,
     198             :                                         NULL,
     199        1128 :                                         smb_fname->twrp,
     200        1128 :                                         smb_fname->flags);
     201        1128 :                 if (smb_fname_base == NULL) {
     202           0 :                         errno = ENOMEM;
     203           0 :                         goto fail;
     204             :                 }
     205        1128 :                 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
     206           0 :                         TALLOC_FREE(smb_fname_base);
     207           0 :                         goto fail;
     208             :                 }
     209        1128 :                 base_sbuf_tmp = smb_fname_base->st;
     210        1128 :                 TALLOC_FREE(smb_fname_base);
     211             :         } else {
     212      462574 :                 base_sbuf_tmp = *base_sbuf;
     213             :         }
     214             : 
     215      463702 :         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
     216             : 
     217      463702 :         push_file_id_16((char *)id_buf, &id);
     218             : 
     219      463702 :         hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
     220             : 
     221      463702 :         first = hash & 0xff;
     222      463702 :         second = (hash >> 8) & 0xff;
     223             : 
     224      463702 :         id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
     225             : 
     226      463702 :         if (id_hex == NULL) {
     227           0 :                 errno = ENOMEM;
     228           0 :                 goto fail;
     229             :         }
     230             : 
     231      463702 :         result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
     232             :                                  first, second, id_hex);
     233             : 
     234      463702 :         TALLOC_FREE(id_hex);
     235             : 
     236      463702 :         if (result == NULL) {
     237           0 :                 errno = ENOMEM;
     238           0 :                 return NULL;
     239             :         }
     240             : 
     241      463702 :         smb_fname_hash = synthetic_smb_fname(talloc_tos(),
     242             :                                         result,
     243             :                                         NULL,
     244             :                                         NULL,
     245      463702 :                                         smb_fname->twrp,
     246      463702 :                                         smb_fname->flags);
     247      463702 :         if (smb_fname_hash == NULL) {
     248           0 :                 errno = ENOMEM;
     249           0 :                 goto fail;
     250             :         }
     251             : 
     252      463702 :         if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
     253        6435 :                 struct smb_filename *smb_fname_new = NULL;
     254           9 :                 char *newname;
     255           9 :                 bool delete_lost;
     256             : 
     257        6435 :                 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
     258           0 :                         errno = EINVAL;
     259           0 :                         goto fail;
     260             :                 }
     261             : 
     262       12870 :                 if (!check_valid ||
     263        6435 :                     file_is_valid(handle, smb_fname)) {
     264        6427 :                         return result;
     265             :                 }
     266             : 
     267             :                 /*
     268             :                  * Someone has recreated a file under an existing inode
     269             :                  * without deleting the streams directory.
     270             :                  * Move it away or remove if streams_depot:delete_lost is set.
     271             :                  */
     272             : 
     273           8 :         again:
     274           8 :                 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
     275             :                                            "delete_lost", false);
     276             : 
     277           8 :                 if (delete_lost) {
     278           0 :                         DEBUG(3, ("Someone has recreated a file under an "
     279             :                               "existing inode. Removing: %s\n",
     280             :                               smb_fname_hash->base_name));
     281           0 :                         recursive_rmdir(talloc_tos(), handle->conn,
     282             :                                         smb_fname_hash);
     283           0 :                         SMB_VFS_NEXT_UNLINKAT(handle,
     284             :                                         handle->conn->cwd_fsp,
     285             :                                         smb_fname_hash,
     286             :                                         AT_REMOVEDIR);
     287             :                 } else {
     288           8 :                         newname = talloc_asprintf(talloc_tos(), "lost-%lu",
     289             :                                                   random());
     290           8 :                         DEBUG(3, ("Someone has recreated a file under an "
     291             :                               "existing inode. Renaming: %s to: %s\n",
     292             :                               smb_fname_hash->base_name,
     293             :                               newname));
     294           8 :                         if (newname == NULL) {
     295           0 :                                 errno = ENOMEM;
     296           0 :                                 goto fail;
     297             :                         }
     298             : 
     299           8 :                         smb_fname_new = synthetic_smb_fname(
     300             :                                                 talloc_tos(),
     301             :                                                 newname,
     302             :                                                 NULL,
     303             :                                                 NULL,
     304           8 :                                                 smb_fname->twrp,
     305           8 :                                                 smb_fname->flags);
     306           8 :                         TALLOC_FREE(newname);
     307           8 :                         if (smb_fname_new == NULL) {
     308           0 :                                 errno = ENOMEM;
     309           0 :                                 goto fail;
     310             :                         }
     311             : 
     312           8 :                         if (SMB_VFS_NEXT_RENAMEAT(handle,
     313             :                                         handle->conn->cwd_fsp,
     314             :                                         smb_fname_hash,
     315             :                                         handle->conn->cwd_fsp,
     316             :                                         smb_fname_new) == -1) {
     317           0 :                                 TALLOC_FREE(smb_fname_new);
     318           0 :                                 if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
     319           0 :                                         goto again;
     320             :                                 }
     321           0 :                                 goto fail;
     322             :                         }
     323             : 
     324           8 :                         TALLOC_FREE(smb_fname_new);
     325             :                 }
     326             :         }
     327             : 
     328      457275 :         if (!create_it) {
     329      456912 :                 errno = ENOENT;
     330      456912 :                 goto fail;
     331             :         }
     332             : 
     333         363 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     334             :                                 handle->conn->cwd_fsp,
     335             :                                 rootdir_fname,
     336             :                                 0755);
     337         363 :         if ((ret != 0) && (errno != EEXIST)) {
     338           0 :                 goto fail;
     339             :         }
     340             : 
     341         363 :         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
     342         363 :         if (tmp == NULL) {
     343           0 :                 errno = ENOMEM;
     344           0 :                 goto fail;
     345             :         }
     346             : 
     347         363 :         tmp_fname = synthetic_smb_fname(talloc_tos(),
     348             :                                         tmp,
     349             :                                         NULL,
     350             :                                         NULL,
     351         363 :                                         smb_fname->twrp,
     352         363 :                                         smb_fname->flags);
     353         363 :         if (tmp_fname == NULL) {
     354           0 :                 errno = ENOMEM;
     355           0 :                 goto fail;
     356             :         }
     357             : 
     358         363 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     359             :                                 handle->conn->cwd_fsp,
     360             :                                 tmp_fname,
     361             :                                 0755);
     362         363 :         if ((ret != 0) && (errno != EEXIST)) {
     363           0 :                 goto fail;
     364             :         }
     365             : 
     366         363 :         TALLOC_FREE(tmp);
     367         363 :         TALLOC_FREE(tmp_fname);
     368             : 
     369         363 :         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
     370             :                               second);
     371         363 :         if (tmp == NULL) {
     372           0 :                 errno = ENOMEM;
     373           0 :                 goto fail;
     374             :         }
     375             : 
     376         363 :         tmp_fname = synthetic_smb_fname(talloc_tos(),
     377             :                                         tmp,
     378             :                                         NULL,
     379             :                                         NULL,
     380         363 :                                         smb_fname->twrp,
     381         363 :                                         smb_fname->flags);
     382         363 :         if (tmp_fname == NULL) {
     383           0 :                 errno = ENOMEM;
     384           0 :                 goto fail;
     385             :         }
     386             : 
     387         363 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     388             :                         handle->conn->cwd_fsp,
     389             :                         tmp_fname,
     390             :                         0755);
     391         363 :         if ((ret != 0) && (errno != EEXIST)) {
     392           0 :                 goto fail;
     393             :         }
     394             : 
     395         363 :         TALLOC_FREE(tmp);
     396         363 :         TALLOC_FREE(tmp_fname);
     397             : 
     398             :         /* smb_fname_hash is the struct smb_filename version of 'result' */
     399         363 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     400             :                         handle->conn->cwd_fsp,
     401             :                         smb_fname_hash,
     402             :                         0755);
     403         363 :         if ((ret != 0) && (errno != EEXIST)) {
     404           0 :                 goto fail;
     405             :         }
     406             : 
     407         363 :         TALLOC_FREE(rootdir_fname);
     408         363 :         TALLOC_FREE(rootdir);
     409         363 :         TALLOC_FREE(tmp_fname);
     410         363 :         TALLOC_FREE(smb_fname_hash);
     411         363 :         return result;
     412             : 
     413      456912 :  fail:
     414      456912 :         TALLOC_FREE(rootdir_fname);
     415      456912 :         TALLOC_FREE(rootdir);
     416      456912 :         TALLOC_FREE(tmp_fname);
     417      456912 :         TALLOC_FREE(smb_fname_hash);
     418      456912 :         TALLOC_FREE(result);
     419      455739 :         return NULL;
     420             : }
     421             : /**
     422             :  * Given a stream name, populate smb_fname_out with the actual location of the
     423             :  * stream.
     424             :  */
     425        6241 : static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
     426             :                                  const struct stat_ex *base_sbuf,
     427             :                                  const struct smb_filename *smb_fname,
     428             :                                  struct smb_filename **smb_fname_out,
     429             :                                  bool create_dir)
     430             : {
     431           7 :         char *dirname, *stream_fname;
     432           7 :         const char *stype;
     433           7 :         NTSTATUS status;
     434             : 
     435        6241 :         *smb_fname_out = NULL;
     436             : 
     437        6241 :         stype = strchr_m(smb_fname->stream_name + 1, ':');
     438             : 
     439        6241 :         if (stype) {
     440        4865 :                 if (strcasecmp_m(stype, ":$DATA") != 0) {
     441          40 :                         return NT_STATUS_INVALID_PARAMETER;
     442             :                 }
     443             :         }
     444             : 
     445        6201 :         dirname = stream_dir(handle, smb_fname, base_sbuf, create_dir);
     446             : 
     447        6201 :         if (dirname == NULL) {
     448        1663 :                 status = map_nt_error_from_unix(errno);
     449        1663 :                 goto fail;
     450             :         }
     451             : 
     452        4538 :         stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
     453        4538 :                                        smb_fname->stream_name);
     454             : 
     455        4538 :         if (stream_fname == NULL) {
     456           0 :                 status = NT_STATUS_NO_MEMORY;
     457           0 :                 goto fail;
     458             :         }
     459             : 
     460        4538 :         if (stype == NULL) {
     461             :                 /* Append an explicit stream type if one wasn't specified. */
     462        1094 :                 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
     463             :                                                stream_fname);
     464        1094 :                 if (stream_fname == NULL) {
     465           0 :                         status = NT_STATUS_NO_MEMORY;
     466           0 :                         goto fail;
     467             :                 }
     468             :         } else {
     469             :                 /* Normalize the stream type to uppercase. */
     470        3444 :                 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
     471           0 :                         status = NT_STATUS_INVALID_PARAMETER;
     472           0 :                         goto fail;
     473             :                 }
     474             :         }
     475             : 
     476        4538 :         DEBUG(10, ("stream filename = %s\n", stream_fname));
     477             : 
     478             :         /* Create an smb_filename with stream_name == NULL. */
     479        4538 :         *smb_fname_out = synthetic_smb_fname(talloc_tos(),
     480             :                                         stream_fname,
     481             :                                         NULL,
     482             :                                         NULL,
     483        4538 :                                         smb_fname->twrp,
     484        4538 :                                         smb_fname->flags);
     485        4538 :         if (*smb_fname_out == NULL) {
     486           0 :                 return NT_STATUS_NO_MEMORY;
     487             :         }
     488             : 
     489        4538 :         return NT_STATUS_OK;
     490             : 
     491        1663 :  fail:
     492        1663 :         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
     493        1663 :         TALLOC_FREE(*smb_fname_out);
     494        1663 :         return status;
     495             : }
     496             : 
     497      309748 : static NTSTATUS walk_streams(vfs_handle_struct *handle,
     498             :                              struct smb_filename *smb_fname_base,
     499             :                              char **pdirname,
     500             :                              bool (*fn)(const struct smb_filename *dirname,
     501             :                                         const char *dirent,
     502             :                                         void *private_data),
     503             :                              void *private_data)
     504             : {
     505         840 :         char *dirname;
     506      309748 :         char *rootdir = NULL;
     507      309748 :         char *orig_connectpath = NULL;
     508      309748 :         struct smb_filename *dir_smb_fname = NULL;
     509      309748 :         struct smb_Dir *dir_hnd = NULL;
     510      309748 :         const char *dname = NULL;
     511      309748 :         char *talloced = NULL;
     512         840 :         NTSTATUS status;
     513             : 
     514      309748 :         dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
     515             :                              false);
     516             : 
     517      309748 :         if (dirname == NULL) {
     518      307841 :                 if (errno == ENOENT) {
     519             :                         /*
     520             :                          * no stream around
     521             :                          */
     522      307841 :                         return NT_STATUS_OK;
     523             :                 }
     524           0 :                 return map_nt_error_from_unix(errno);
     525             :         }
     526             : 
     527        1907 :         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
     528             : 
     529        1907 :         dir_smb_fname = synthetic_smb_fname(talloc_tos(),
     530             :                                         dirname,
     531             :                                         NULL,
     532             :                                         NULL,
     533             :                                         smb_fname_base->twrp,
     534             :                                         smb_fname_base->flags);
     535        1907 :         if (dir_smb_fname == NULL) {
     536           0 :                 TALLOC_FREE(dirname);
     537           0 :                 return NT_STATUS_NO_MEMORY;
     538             :         }
     539             : 
     540             :         /*
     541             :          * For OpenDir to succeed if the stream rootdir is outside
     542             :          * the share path, we must temporarily swap out the connect
     543             :          * path for this share. We're dealing with absolute paths
     544             :          * here so we don't care about chdir calls.
     545             :          */
     546        1907 :         rootdir = stream_rootdir(handle, talloc_tos());
     547        1907 :         if (rootdir == NULL) {
     548           0 :                 TALLOC_FREE(dir_smb_fname);
     549           0 :                 TALLOC_FREE(dirname);
     550           0 :                 return NT_STATUS_NO_MEMORY;
     551             :         }
     552             : 
     553        1907 :         orig_connectpath = handle->conn->connectpath;
     554        1907 :         handle->conn->connectpath = rootdir;
     555             : 
     556        1907 :         status = OpenDir(
     557        1904 :                 talloc_tos(), handle->conn, dir_smb_fname, NULL, 0, &dir_hnd);
     558        1907 :         if (!NT_STATUS_IS_OK(status)) {
     559           0 :                 handle->conn->connectpath = orig_connectpath;
     560           0 :                 TALLOC_FREE(rootdir);
     561           0 :                 TALLOC_FREE(dir_smb_fname);
     562           0 :                 TALLOC_FREE(dirname);
     563           0 :                 return status;
     564             :         }
     565             : 
     566        7190 :         while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
     567        5283 :                 if (ISDOT(dname) || ISDOTDOT(dname)) {
     568        3814 :                         TALLOC_FREE(talloced);
     569        3814 :                         continue;
     570             :                 }
     571             : 
     572        1469 :                 DBG_DEBUG("dirent=%s\n", dname);
     573             : 
     574        1469 :                 if (!fn(dir_smb_fname, dname, private_data)) {
     575           0 :                         TALLOC_FREE(talloced);
     576           0 :                         break;
     577             :                 }
     578        1481 :                 TALLOC_FREE(talloced);
     579             :         }
     580             : 
     581             :         /* Restore the original connectpath. */
     582        1907 :         handle->conn->connectpath = orig_connectpath;
     583        1907 :         TALLOC_FREE(rootdir);
     584        1907 :         TALLOC_FREE(dir_smb_fname);
     585        1907 :         TALLOC_FREE(dir_hnd);
     586             : 
     587        1907 :         if (pdirname != NULL) {
     588           0 :                 *pdirname = dirname;
     589             :         }
     590             :         else {
     591        1907 :                 TALLOC_FREE(dirname);
     592             :         }
     593             : 
     594        1907 :         return NT_STATUS_OK;
     595             : }
     596             : 
     597     4735057 : static int streams_depot_stat(vfs_handle_struct *handle,
     598             :                               struct smb_filename *smb_fname)
     599             : {
     600     4735057 :         struct smb_filename *smb_fname_stream = NULL;
     601        9535 :         NTSTATUS status;
     602     4735057 :         int ret = -1;
     603             : 
     604     4735057 :         DEBUG(10, ("streams_depot_stat called for [%s]\n",
     605             :                    smb_fname_str_dbg(smb_fname)));
     606             : 
     607     4735057 :         if (!is_named_stream(smb_fname)) {
     608     4734582 :                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
     609             :         }
     610             : 
     611             :         /* Stat the actual stream now. */
     612         475 :         status = stream_smb_fname(
     613             :                 handle, NULL, smb_fname, &smb_fname_stream, false);
     614         475 :         if (!NT_STATUS_IS_OK(status)) {
     615          30 :                 ret = -1;
     616          30 :                 errno = map_errno_from_nt_status(status);
     617          30 :                 goto done;
     618             :         }
     619             : 
     620         445 :         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
     621             : 
     622             :         /* Update the original smb_fname with the stat info. */
     623         445 :         smb_fname->st = smb_fname_stream->st;
     624         475 :  done:
     625         475 :         TALLOC_FREE(smb_fname_stream);
     626         474 :         return ret;
     627             : }
     628             : 
     629             : 
     630             : 
     631       13008 : static int streams_depot_lstat(vfs_handle_struct *handle,
     632             :                                struct smb_filename *smb_fname)
     633             : {
     634       13008 :         struct smb_filename *smb_fname_stream = NULL;
     635          70 :         NTSTATUS status;
     636       13008 :         int ret = -1;
     637             : 
     638       13008 :         DEBUG(10, ("streams_depot_lstat called for [%s]\n",
     639             :                    smb_fname_str_dbg(smb_fname)));
     640             : 
     641       13008 :         if (!is_named_stream(smb_fname)) {
     642       13008 :                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
     643             :         }
     644             : 
     645             :         /* Stat the actual stream now. */
     646           0 :         status = stream_smb_fname(
     647             :                 handle, NULL, smb_fname, &smb_fname_stream, false);
     648           0 :         if (!NT_STATUS_IS_OK(status)) {
     649           0 :                 ret = -1;
     650           0 :                 errno = map_errno_from_nt_status(status);
     651           0 :                 goto done;
     652             :         }
     653             : 
     654           0 :         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
     655             : 
     656           0 :  done:
     657           0 :         TALLOC_FREE(smb_fname_stream);
     658           0 :         return ret;
     659             : }
     660             : 
     661     5778631 : static int streams_depot_openat(struct vfs_handle_struct *handle,
     662             :                                 const struct files_struct *dirfsp,
     663             :                                 const struct smb_filename *smb_fname,
     664             :                                 struct files_struct *fsp,
     665             :                                 const struct vfs_open_how *how)
     666             : {
     667     5778631 :         struct smb_filename *smb_fname_stream = NULL;
     668     5778631 :         struct files_struct *fspcwd = NULL;
     669       30011 :         NTSTATUS status;
     670       30011 :         bool create_it;
     671     5778631 :         int ret = -1;
     672             : 
     673     5778631 :         if (!is_named_stream(smb_fname)) {
     674     5773518 :                 return SMB_VFS_NEXT_OPENAT(handle,
     675             :                                            dirfsp,
     676             :                                            smb_fname,
     677             :                                            fsp,
     678             :                                            how);
     679             :         }
     680             : 
     681        5113 :         if (how->resolve != 0) {
     682           0 :                 errno = ENOSYS;
     683           0 :                 return -1;
     684             :         }
     685             : 
     686        5113 :         SMB_ASSERT(fsp_is_alternate_stream(fsp));
     687        5113 :         SMB_ASSERT(dirfsp == NULL);
     688        5113 :         SMB_ASSERT(VALID_STAT(fsp->base_fsp->fsp_name->st));
     689             : 
     690        5113 :         create_it = (how->flags & O_CREAT);
     691             : 
     692             :         /* Determine the stream name, and then open it. */
     693        5118 :         status = stream_smb_fname(
     694             :                 handle,
     695        5113 :                 &fsp->base_fsp->fsp_name->st,
     696        5113 :                 fsp->fsp_name,
     697             :                 &smb_fname_stream,
     698             :                 create_it);
     699        5113 :         if (!NT_STATUS_IS_OK(status)) {
     700        1639 :                 ret = -1;
     701        1639 :                 errno = map_errno_from_nt_status(status);
     702        1639 :                 goto done;
     703             :         }
     704             : 
     705        3474 :         if (create_it) {
     706         553 :                 bool check_valid = lp_parm_bool(
     707         553 :                         SNUM(handle->conn),
     708             :                         "streams_depot",
     709             :                         "check_valid",
     710             :                         true);
     711             : 
     712         553 :                 if (check_valid) {
     713         553 :                         char buf = '1';
     714             : 
     715         553 :                         DBG_DEBUG("marking file %s as valid\n",
     716             :                                   fsp->base_fsp->fsp_name->base_name);
     717             : 
     718         553 :                         ret = SMB_VFS_FSETXATTR(
     719             :                                 fsp->base_fsp,
     720             :                                 SAMBA_XATTR_MARKER,
     721             :                                 &buf,
     722             :                                 sizeof(buf),
     723             :                                 0);
     724             : 
     725         553 :                         if (ret == -1) {
     726           0 :                                 DBG_DEBUG("FSETXATTR failed: %s\n",
     727             :                                           strerror(errno));
     728           0 :                                 goto done;
     729             :                         }
     730             :                 }
     731             :         }
     732             : 
     733        3474 :         status = vfs_at_fspcwd(talloc_tos(), handle->conn, &fspcwd);
     734        3474 :         if (!NT_STATUS_IS_OK(status)) {
     735           0 :                 ret = -1;
     736           0 :                 errno = map_errno_from_nt_status(status);
     737           0 :                 goto done;
     738             :         }
     739             : 
     740        3474 :         ret = SMB_VFS_NEXT_OPENAT(handle,
     741             :                                   fspcwd,
     742             :                                   smb_fname_stream,
     743             :                                   fsp,
     744             :                                   how);
     745             : 
     746        5113 :  done:
     747        5113 :         TALLOC_FREE(smb_fname_stream);
     748        5113 :         TALLOC_FREE(fspcwd);
     749        5108 :         return ret;
     750             : }
     751             : 
     752      138210 : static int streams_depot_unlink_internal(vfs_handle_struct *handle,
     753             :                                 struct files_struct *dirfsp,
     754             :                                 const struct smb_filename *smb_fname,
     755             :                                 int flags)
     756             : {
     757      138210 :         struct smb_filename *full_fname = NULL;
     758      138210 :         char *dirname = NULL;
     759      138210 :         int ret = -1;
     760             : 
     761      138210 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     762             :                                                   dirfsp,
     763             :                                                   smb_fname);
     764      138210 :         if (full_fname == NULL) {
     765           0 :                 return -1;
     766             :         }
     767             : 
     768      138210 :         DEBUG(10, ("streams_depot_unlink called for %s\n",
     769             :                    smb_fname_str_dbg(full_fname)));
     770             : 
     771             :         /* If there is a valid stream, just unlink the stream and return. */
     772      138210 :         if (is_named_stream(full_fname)) {
     773         589 :                 struct smb_filename *smb_fname_stream = NULL;
     774           1 :                 NTSTATUS status;
     775             : 
     776         589 :                 status = stream_smb_fname(
     777             :                         handle, NULL, full_fname, &smb_fname_stream, false);
     778         589 :                 TALLOC_FREE(full_fname);
     779         589 :                 if (!NT_STATUS_IS_OK(status)) {
     780          34 :                         errno = map_errno_from_nt_status(status);
     781          34 :                         return -1;
     782             :                 }
     783             : 
     784         555 :                 ret = SMB_VFS_NEXT_UNLINKAT(handle,
     785             :                                 dirfsp->conn->cwd_fsp,
     786             :                                 smb_fname_stream,
     787             :                                 0);
     788             : 
     789         555 :                 TALLOC_FREE(smb_fname_stream);
     790         555 :                 return ret;
     791             :         }
     792             : 
     793             :         /*
     794             :          * We potentially need to delete the per-inode streams directory
     795             :          */
     796             : 
     797      137621 :         if (full_fname->flags & SMB_FILENAME_POSIX_PATH) {
     798         805 :                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
     799             :         } else {
     800      136816 :                 ret = SMB_VFS_NEXT_STAT(handle, full_fname);
     801      136816 :                 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
     802           2 :                         if (VALID_STAT(smb_fname->st) &&
     803           2 :                                         S_ISLNK(smb_fname->st.st_ex_mode)) {
     804             :                                 /*
     805             :                                  * Original name was a link - Could be
     806             :                                  * trying to remove a dangling symlink.
     807             :                                  */
     808           2 :                                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
     809             :                         }
     810             :                 }
     811             :         }
     812      137621 :         if (ret == -1) {
     813           0 :                 TALLOC_FREE(full_fname);
     814           0 :                 return -1;
     815             :         }
     816             : 
     817             :         /*
     818             :          * We know the unlink should succeed as the ACL
     819             :          * check is already done in the caller. Remove the
     820             :          * file *after* the streams.
     821             :          */
     822      137893 :         dirname = stream_dir(handle,
     823             :                              full_fname,
     824      137621 :                              &full_fname->st,
     825             :                              false);
     826      137621 :         TALLOC_FREE(full_fname);
     827      137621 :         if (dirname != NULL) {
     828         316 :                 struct smb_filename *smb_fname_dir = NULL;
     829             : 
     830         316 :                 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
     831             :                                                     dirname,
     832             :                                                     NULL,
     833             :                                                     NULL,
     834         316 :                                                     smb_fname->twrp,
     835         316 :                                                     smb_fname->flags);
     836         316 :                 if (smb_fname_dir == NULL) {
     837           0 :                         TALLOC_FREE(dirname);
     838           0 :                         errno = ENOMEM;
     839           0 :                         return -1;
     840             :                 }
     841             : 
     842         316 :                 SMB_VFS_NEXT_UNLINKAT(handle,
     843             :                                       dirfsp->conn->cwd_fsp,
     844             :                                       smb_fname_dir,
     845             :                                       AT_REMOVEDIR);
     846         316 :                 TALLOC_FREE(smb_fname_dir);
     847         316 :                 TALLOC_FREE(dirname);
     848             :         }
     849             : 
     850      137621 :         ret = SMB_VFS_NEXT_UNLINKAT(handle,
     851             :                                 dirfsp,
     852             :                                 smb_fname,
     853             :                                 flags);
     854      137621 :         return ret;
     855             : }
     856             : 
     857       10132 : static int streams_depot_rmdir_internal(vfs_handle_struct *handle,
     858             :                         struct files_struct *dirfsp,
     859             :                         const struct smb_filename *smb_fname)
     860             : {
     861       10132 :         struct smb_filename *full_fname = NULL;
     862       10132 :         struct smb_filename *smb_fname_base = NULL;
     863       10132 :         int ret = -1;
     864             : 
     865       10132 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     866             :                                                   dirfsp,
     867             :                                                   smb_fname);
     868       10132 :         if (full_fname == NULL) {
     869           0 :                 return -1;
     870             :         }
     871             : 
     872       10132 :         DBG_DEBUG("called for %s\n", full_fname->base_name);
     873             : 
     874             :         /*
     875             :          * We potentially need to delete the per-inode streams directory
     876             :          */
     877             : 
     878       10132 :         smb_fname_base = synthetic_smb_fname(talloc_tos(),
     879       10132 :                                 full_fname->base_name,
     880             :                                 NULL,
     881             :                                 NULL,
     882             :                                 full_fname->twrp,
     883             :                                 full_fname->flags);
     884       10132 :         TALLOC_FREE(full_fname);
     885       10132 :         if (smb_fname_base == NULL) {
     886           0 :                 errno = ENOMEM;
     887           0 :                 return -1;
     888             :         }
     889             : 
     890       10132 :         if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
     891         564 :                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
     892             :         } else {
     893        9568 :                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
     894             :         }
     895             : 
     896       10132 :         if (ret == -1) {
     897           0 :                 TALLOC_FREE(smb_fname_base);
     898           0 :                 return -1;
     899             :         }
     900             : 
     901             :         /*
     902             :          * We know the rmdir should succeed as the ACL
     903             :          * check is already done in the caller. Remove the
     904             :          * directory *after* the streams.
     905             :          */
     906             :         {
     907       10196 :                 char *dirname = stream_dir(handle, smb_fname_base,
     908       10132 :                                            &smb_fname_base->st, false);
     909             : 
     910       10132 :                 if (dirname != NULL) {
     911           1 :                         struct smb_filename *smb_fname_dir =
     912          29 :                                 synthetic_smb_fname(talloc_tos(),
     913             :                                                 dirname,
     914             :                                                 NULL,
     915             :                                                 NULL,
     916          29 :                                                 smb_fname->twrp,
     917          29 :                                                 smb_fname->flags);
     918          29 :                         if (smb_fname_dir == NULL) {
     919           0 :                                 TALLOC_FREE(smb_fname_base);
     920           0 :                                 TALLOC_FREE(dirname);
     921           0 :                                 errno = ENOMEM;
     922           0 :                                 return -1;
     923             :                         }
     924          29 :                         SMB_VFS_NEXT_UNLINKAT(handle,
     925             :                                         dirfsp->conn->cwd_fsp,
     926             :                                         smb_fname_dir,
     927             :                                         AT_REMOVEDIR);
     928          29 :                         TALLOC_FREE(smb_fname_dir);
     929             :                 }
     930       10132 :                 TALLOC_FREE(dirname);
     931             :         }
     932             : 
     933       10132 :         ret = SMB_VFS_NEXT_UNLINKAT(handle,
     934             :                                 dirfsp,
     935             :                                 smb_fname,
     936             :                                 AT_REMOVEDIR);
     937       10132 :         TALLOC_FREE(smb_fname_base);
     938       10132 :         return ret;
     939             : }
     940             : 
     941      148342 : static int streams_depot_unlinkat(vfs_handle_struct *handle,
     942             :                         struct files_struct *dirfsp,
     943             :                         const struct smb_filename *smb_fname,
     944             :                         int flags)
     945             : {
     946         337 :         int ret;
     947      148342 :         if (flags & AT_REMOVEDIR) {
     948       10132 :                 ret = streams_depot_rmdir_internal(handle,
     949             :                                 dirfsp,
     950             :                                 smb_fname);
     951             :         } else {
     952      138210 :                 ret = streams_depot_unlink_internal(handle,
     953             :                                 dirfsp,
     954             :                                 smb_fname,
     955             :                                 flags);
     956             :         }
     957      148342 :         return ret;
     958             : }
     959             : 
     960         952 : static int streams_depot_renameat(vfs_handle_struct *handle,
     961             :                                 files_struct *srcfsp,
     962             :                                 const struct smb_filename *smb_fname_src,
     963             :                                 files_struct *dstfsp,
     964             :                                 const struct smb_filename *smb_fname_dst)
     965             : {
     966         952 :         struct smb_filename *smb_fname_src_stream = NULL;
     967         952 :         struct smb_filename *smb_fname_dst_stream = NULL;
     968         952 :         struct smb_filename *full_src = NULL;
     969         952 :         struct smb_filename *full_dst = NULL;
     970          16 :         bool src_is_stream, dst_is_stream;
     971          16 :         NTSTATUS status;
     972         952 :         int ret = -1;
     973             : 
     974         952 :         DEBUG(10, ("streams_depot_renameat called for %s => %s\n",
     975             :                    smb_fname_str_dbg(smb_fname_src),
     976             :                    smb_fname_str_dbg(smb_fname_dst)));
     977             : 
     978         952 :         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
     979         952 :         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
     980             : 
     981         952 :         if (!src_is_stream && !dst_is_stream) {
     982         920 :                 return SMB_VFS_NEXT_RENAMEAT(handle,
     983             :                                         srcfsp,
     984             :                                         smb_fname_src,
     985             :                                         dstfsp,
     986             :                                         smb_fname_dst);
     987             :         }
     988             : 
     989             :         /* for now don't allow renames from or to the default stream */
     990          64 :         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
     991          32 :             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
     992           0 :                 errno = ENOSYS;
     993           0 :                 goto done;
     994             :         }
     995             : 
     996          32 :         full_src = full_path_from_dirfsp_atname(talloc_tos(),
     997             :                                                 srcfsp,
     998             :                                                 smb_fname_src);
     999          32 :         if (full_src == NULL) {
    1000           0 :                 errno = ENOMEM;
    1001           0 :                 goto done;
    1002             :         }
    1003             : 
    1004          32 :         full_dst = full_path_from_dirfsp_atname(talloc_tos(),
    1005             :                                                 dstfsp,
    1006             :                                                 smb_fname_dst);
    1007          32 :         if (full_dst == NULL) {
    1008           0 :                 errno = ENOMEM;
    1009           0 :                 goto done;
    1010             :         }
    1011             : 
    1012          32 :         status = stream_smb_fname(
    1013             :                 handle, NULL, full_src, &smb_fname_src_stream, false);
    1014          32 :         if (!NT_STATUS_IS_OK(status)) {
    1015           0 :                 errno = map_errno_from_nt_status(status);
    1016           0 :                 goto done;
    1017             :         }
    1018             : 
    1019          32 :         status = stream_smb_fname(
    1020             :                 handle, NULL, full_dst, &smb_fname_dst_stream, false);
    1021          32 :         if (!NT_STATUS_IS_OK(status)) {
    1022           0 :                 errno = map_errno_from_nt_status(status);
    1023           0 :                 goto done;
    1024             :         }
    1025             : 
    1026             :         /*
    1027             :          * We must use handle->conn->cwd_fsp as
    1028             :          * srcfsp and dstfsp directory handles here
    1029             :          * as we used the full pathname from the cwd dir
    1030             :          * to calculate the streams directory and filename
    1031             :          * within.
    1032             :          */
    1033          32 :         ret = SMB_VFS_NEXT_RENAMEAT(handle,
    1034             :                                 handle->conn->cwd_fsp,
    1035             :                                 smb_fname_src_stream,
    1036             :                                 handle->conn->cwd_fsp,
    1037             :                                 smb_fname_dst_stream);
    1038             : 
    1039          32 : done:
    1040          32 :         TALLOC_FREE(smb_fname_src_stream);
    1041          32 :         TALLOC_FREE(smb_fname_dst_stream);
    1042          32 :         return ret;
    1043             : }
    1044             : 
    1045        1469 : static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
    1046             :                            struct stream_struct **streams,
    1047             :                            const char *name, off_t size,
    1048             :                            off_t alloc_size)
    1049             : {
    1050           3 :         struct stream_struct *tmp;
    1051             : 
    1052        1469 :         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
    1053             :                                    (*num_streams)+1);
    1054        1469 :         if (tmp == NULL) {
    1055           0 :                 return false;
    1056             :         }
    1057             : 
    1058        1469 :         tmp[*num_streams].name = talloc_strdup(tmp, name);
    1059        1469 :         if (tmp[*num_streams].name == NULL) {
    1060           0 :                 return false;
    1061             :         }
    1062             : 
    1063        1469 :         tmp[*num_streams].size = size;
    1064        1469 :         tmp[*num_streams].alloc_size = alloc_size;
    1065             : 
    1066        1469 :         *streams = tmp;
    1067        1469 :         *num_streams += 1;
    1068        1469 :         return true;
    1069             : }
    1070             : 
    1071             : struct streaminfo_state {
    1072             :         TALLOC_CTX *mem_ctx;
    1073             :         vfs_handle_struct *handle;
    1074             :         unsigned int num_streams;
    1075             :         struct stream_struct *streams;
    1076             :         NTSTATUS status;
    1077             : };
    1078             : 
    1079        1469 : static bool collect_one_stream(const struct smb_filename *dirfname,
    1080             :                                const char *dirent,
    1081             :                                void *private_data)
    1082             : {
    1083        1469 :         const char *dirname = dirfname->base_name;
    1084        1469 :         struct streaminfo_state *state =
    1085             :                 (struct streaminfo_state *)private_data;
    1086        1469 :         struct smb_filename *smb_fname = NULL;
    1087        1469 :         char *sname = NULL;
    1088           3 :         bool ret;
    1089             : 
    1090        1469 :         sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
    1091        1469 :         if (sname == NULL) {
    1092           0 :                 state->status = NT_STATUS_NO_MEMORY;
    1093           0 :                 ret = false;
    1094           0 :                 goto out;
    1095             :         }
    1096             : 
    1097        1469 :         smb_fname = synthetic_smb_fname(talloc_tos(),
    1098             :                                         sname,
    1099             :                                         NULL,
    1100             :                                         NULL,
    1101        1469 :                                         dirfname->twrp,
    1102             :                                         0);
    1103        1469 :         if (smb_fname == NULL) {
    1104           0 :                 state->status = NT_STATUS_NO_MEMORY;
    1105           0 :                 ret = false;
    1106           0 :                 goto out;
    1107             :         }
    1108             : 
    1109        1469 :         if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
    1110           0 :                 DEBUG(10, ("Could not stat %s: %s\n", sname,
    1111             :                            strerror(errno)));
    1112           0 :                 ret = true;
    1113           0 :                 goto out;
    1114             :         }
    1115             : 
    1116        1469 :         if (!add_one_stream(state->mem_ctx,
    1117             :                             &state->num_streams, &state->streams,
    1118             :                             dirent, smb_fname->st.st_ex_size,
    1119        1469 :                             SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
    1120             :                                                    &smb_fname->st))) {
    1121           0 :                 state->status = NT_STATUS_NO_MEMORY;
    1122           0 :                 ret = false;
    1123           0 :                 goto out;
    1124             :         }
    1125             : 
    1126        1466 :         ret = true;
    1127        1469 :  out:
    1128        1469 :         TALLOC_FREE(sname);
    1129        1469 :         TALLOC_FREE(smb_fname);
    1130        1469 :         return ret;
    1131             : }
    1132             : 
    1133      309748 : static NTSTATUS streams_depot_fstreaminfo(vfs_handle_struct *handle,
    1134             :                                          struct files_struct *fsp,
    1135             :                                          TALLOC_CTX *mem_ctx,
    1136             :                                          unsigned int *pnum_streams,
    1137             :                                          struct stream_struct **pstreams)
    1138             : {
    1139      309748 :         struct smb_filename *smb_fname_base = NULL;
    1140         840 :         int ret;
    1141         840 :         NTSTATUS status;
    1142         840 :         struct streaminfo_state state;
    1143             : 
    1144      309748 :         smb_fname_base = synthetic_smb_fname(talloc_tos(),
    1145      309748 :                                         fsp->fsp_name->base_name,
    1146             :                                         NULL,
    1147             :                                         NULL,
    1148      308908 :                                         fsp->fsp_name->twrp,
    1149      309748 :                                         fsp->fsp_name->flags);
    1150      309748 :         if (smb_fname_base == NULL) {
    1151           0 :                 return NT_STATUS_NO_MEMORY;
    1152             :         }
    1153             : 
    1154      309748 :         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
    1155      309748 :         if (ret == -1) {
    1156           0 :                 status = map_nt_error_from_unix(errno);
    1157           0 :                 goto out;
    1158             :         }
    1159             : 
    1160      309748 :         state.streams = *pstreams;
    1161      309748 :         state.num_streams = *pnum_streams;
    1162      309748 :         state.mem_ctx = mem_ctx;
    1163      309748 :         state.handle = handle;
    1164      309748 :         state.status = NT_STATUS_OK;
    1165             : 
    1166      309748 :         status = walk_streams(handle,
    1167             :                                 smb_fname_base,
    1168             :                                 NULL,
    1169             :                                 collect_one_stream,
    1170             :                                 &state);
    1171             : 
    1172      309748 :         if (!NT_STATUS_IS_OK(status)) {
    1173           0 :                 TALLOC_FREE(state.streams);
    1174           0 :                 goto out;
    1175             :         }
    1176             : 
    1177      309748 :         if (!NT_STATUS_IS_OK(state.status)) {
    1178           0 :                 TALLOC_FREE(state.streams);
    1179           0 :                 status = state.status;
    1180           0 :                 goto out;
    1181             :         }
    1182             : 
    1183      309748 :         *pnum_streams = state.num_streams;
    1184      309748 :         *pstreams = state.streams;
    1185      309749 :         status = SMB_VFS_NEXT_FSTREAMINFO(handle,
    1186             :                                 fsp->base_fsp ? fsp->base_fsp : fsp,
    1187             :                                 mem_ctx,
    1188             :                                 pnum_streams,
    1189             :                                 pstreams);
    1190             : 
    1191      309748 :  out:
    1192      309748 :         TALLOC_FREE(smb_fname_base);
    1193      309748 :         return status;
    1194             : }
    1195             : 
    1196       25826 : static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
    1197             :                         enum timestamp_set_resolution *p_ts_res)
    1198             : {
    1199       25826 :         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
    1200             : }
    1201             : 
    1202             : static struct vfs_fn_pointers vfs_streams_depot_fns = {
    1203             :         .fs_capabilities_fn = streams_depot_fs_capabilities,
    1204             :         .openat_fn = streams_depot_openat,
    1205             :         .stat_fn = streams_depot_stat,
    1206             :         .lstat_fn = streams_depot_lstat,
    1207             :         .unlinkat_fn = streams_depot_unlinkat,
    1208             :         .renameat_fn = streams_depot_renameat,
    1209             :         .fstreaminfo_fn = streams_depot_fstreaminfo,
    1210             : };
    1211             : 
    1212             : static_decl_vfs;
    1213       28119 : NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
    1214             : {
    1215       28119 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
    1216             :                                 &vfs_streams_depot_fns);
    1217             : }

Generated by: LCOV version 1.14