LCOV - code coverage report
Current view: top level - source3/modules - vfs_streams_depot.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 356 528 67.4 %
Date: 2024-06-13 04:01:37 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        4252 : static uint32_t hash_fn(DATA_BLOB key)
      40             : {
      41             :         uint32_t value; /* Used to compute the hash value.  */
      42             :         uint32_t i;     /* Used to cycle through random values. */
      43             : 
      44             :         /* Set the initial value from the key size. */
      45       72284 :         for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
      46       68032 :                 value = (value + (key.data[i] << (i*5 % 24)));
      47             : 
      48        4252 :         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         110 : static bool file_is_valid(vfs_handle_struct *handle,
      71             :                         const struct smb_filename *smb_fname)
      72             : {
      73             :         char buf;
      74             :         NTSTATUS status;
      75         110 :         struct smb_filename *pathref = NULL;
      76             :         int ret;
      77             : 
      78         110 :         DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
      79             : 
      80         165 :         status = synthetic_pathref(talloc_tos(),
      81         110 :                                 handle->conn->cwd_fsp,
      82         110 :                                 smb_fname->base_name,
      83             :                                 NULL,
      84             :                                 NULL,
      85          55 :                                 smb_fname->twrp,
      86          55 :                                 smb_fname->flags,
      87             :                                 &pathref);
      88         110 :         if (!NT_STATUS_IS_OK(status)) {
      89           0 :                 return false;
      90             :         }
      91         110 :         ret = SMB_VFS_FGETXATTR(pathref->fsp,
      92             :                                 SAMBA_XATTR_MARKER,
      93             :                                 &buf,
      94             :                                 sizeof(buf));
      95         110 :         if (ret != sizeof(buf)) {
      96           0 :                 int saved_errno = errno;
      97           0 :                 DBG_DEBUG("FGETXATTR failed: %s\n", strerror(saved_errno));
      98           0 :                 TALLOC_FREE(pathref);
      99           0 :                 errno = saved_errno;
     100           0 :                 return false;
     101             :         }
     102             : 
     103         110 :         TALLOC_FREE(pathref);
     104             : 
     105         110 :         if (buf != '1') {
     106           0 :                 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
     107           0 :                 return false;
     108             :         }
     109             : 
     110         110 :         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        4284 : static char *stream_rootdir(vfs_handle_struct *handle,
     124             :                             TALLOC_CTX *ctx)
     125             : {
     126        3820 :         const struct loadparm_substitution *lp_sub =
     127         464 :                 loadparm_s3_global_substitution();
     128             :         char *tmp;
     129             : 
     130        4284 :         tmp = talloc_asprintf(ctx,
     131             :                               "%s/.streams",
     132        4284 :                               handle->conn->connectpath);
     133        4284 :         if (tmp == NULL) {
     134           0 :                 errno = ENOMEM;
     135           0 :                 return NULL;
     136             :         }
     137             : 
     138        8104 :         return lp_parm_substituted_string(ctx,
     139             :                                           lp_sub,
     140        8104 :                                           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        4252 : 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             :         uint32_t hash;
     155        4252 :         struct smb_filename *smb_fname_hash = NULL;
     156        4252 :         char *result = NULL;
     157             :         SMB_STRUCT_STAT base_sbuf_tmp;
     158        4252 :         char *tmp = NULL;
     159             :         uint8_t first, second;
     160             :         char *id_hex;
     161             :         struct file_id id;
     162             :         uint8_t id_buf[16];
     163             :         bool check_valid;
     164        4252 :         char *rootdir = NULL;
     165        4252 :         struct smb_filename *rootdir_fname = NULL;
     166        4252 :         struct smb_filename *tmp_fname = NULL;
     167             :         int ret;
     168             : 
     169        4252 :         check_valid = lp_parm_bool(SNUM(handle->conn),
     170             :                       "streams_depot", "check_valid", true);
     171             : 
     172        4252 :         rootdir = stream_rootdir(handle,
     173             :                                  talloc_tos());
     174        4252 :         if (rootdir == NULL) {
     175           0 :                 errno = ENOMEM;
     176           0 :                 goto fail;
     177             :         }
     178             : 
     179        4252 :         rootdir_fname = synthetic_smb_fname(talloc_tos(),
     180             :                                         rootdir,
     181             :                                         NULL,
     182             :                                         NULL,
     183         448 :                                         smb_fname->twrp,
     184         448 :                                         smb_fname->flags);
     185        4252 :         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        4252 :         if (base_sbuf == NULL) {
     192             :                 struct smb_filename *smb_fname_base;
     193             : 
     194          36 :                 smb_fname_base = synthetic_smb_fname(
     195             :                                         talloc_tos(),
     196          24 :                                         smb_fname->base_name,
     197             :                                         NULL,
     198             :                                         NULL,
     199          12 :                                         smb_fname->twrp,
     200          12 :                                         smb_fname->flags);
     201          24 :                 if (smb_fname_base == NULL) {
     202           0 :                         errno = ENOMEM;
     203           0 :                         goto fail;
     204             :                 }
     205          24 :                 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
     206           0 :                         TALLOC_FREE(smb_fname_base);
     207           0 :                         goto fail;
     208             :                 }
     209          24 :                 base_sbuf_tmp = smb_fname_base->st;
     210          24 :                 TALLOC_FREE(smb_fname_base);
     211             :         } else {
     212        4228 :                 base_sbuf_tmp = *base_sbuf;
     213             :         }
     214             : 
     215        4252 :         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
     216             : 
     217        4252 :         push_file_id_16((char *)id_buf, &id);
     218             : 
     219        4252 :         hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
     220             : 
     221        4252 :         first = hash & 0xff;
     222        4252 :         second = (hash >> 8) & 0xff;
     223             : 
     224        4252 :         id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
     225             : 
     226        4252 :         if (id_hex == NULL) {
     227           0 :                 errno = ENOMEM;
     228           0 :                 goto fail;
     229             :         }
     230             : 
     231        4252 :         result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
     232             :                                  first, second, id_hex);
     233             : 
     234        4252 :         TALLOC_FREE(id_hex);
     235             : 
     236        4252 :         if (result == NULL) {
     237           0 :                 errno = ENOMEM;
     238           0 :                 return NULL;
     239             :         }
     240             : 
     241        4252 :         smb_fname_hash = synthetic_smb_fname(talloc_tos(),
     242             :                                         result,
     243             :                                         NULL,
     244             :                                         NULL,
     245         448 :                                         smb_fname->twrp,
     246         448 :                                         smb_fname->flags);
     247        4252 :         if (smb_fname_hash == NULL) {
     248           0 :                 errno = ENOMEM;
     249           0 :                 goto fail;
     250             :         }
     251             : 
     252        4252 :         if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
     253         110 :                 struct smb_filename *smb_fname_new = NULL;
     254             :                 char *newname;
     255             :                 bool delete_lost;
     256             : 
     257         110 :                 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
     258           0 :                         errno = EINVAL;
     259           0 :                         goto fail;
     260             :                 }
     261             : 
     262         220 :                 if (!check_valid ||
     263         110 :                     file_is_valid(handle, smb_fname)) {
     264         110 :                         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           0 :         again:
     274           0 :                 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
     275             :                                            "delete_lost", false);
     276             : 
     277           0 :                 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           0 :                         newname = talloc_asprintf(talloc_tos(), "lost-%lu",
     289             :                                                   random());
     290           0 :                         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           0 :                         if (newname == NULL) {
     295           0 :                                 errno = ENOMEM;
     296           0 :                                 goto fail;
     297             :                         }
     298             : 
     299           0 :                         smb_fname_new = synthetic_smb_fname(
     300             :                                                 talloc_tos(),
     301             :                                                 newname,
     302             :                                                 NULL,
     303             :                                                 NULL,
     304           0 :                                                 smb_fname->twrp,
     305           0 :                                                 smb_fname->flags);
     306           0 :                         TALLOC_FREE(newname);
     307           0 :                         if (smb_fname_new == NULL) {
     308           0 :                                 errno = ENOMEM;
     309           0 :                                 goto fail;
     310             :                         }
     311             : 
     312           0 :                         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           0 :                         TALLOC_FREE(smb_fname_new);
     325             :                 }
     326             :         }
     327             : 
     328        4142 :         if (!create_it) {
     329        4128 :                 errno = ENOENT;
     330        4128 :                 goto fail;
     331             :         }
     332             : 
     333          14 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     334             :                                 handle->conn->cwd_fsp,
     335             :                                 rootdir_fname,
     336             :                                 0755);
     337          14 :         if ((ret != 0) && (errno != EEXIST)) {
     338           0 :                 goto fail;
     339             :         }
     340             : 
     341          14 :         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
     342          14 :         if (tmp == NULL) {
     343           0 :                 errno = ENOMEM;
     344           0 :                 goto fail;
     345             :         }
     346             : 
     347          14 :         tmp_fname = synthetic_smb_fname(talloc_tos(),
     348             :                                         tmp,
     349             :                                         NULL,
     350             :                                         NULL,
     351           7 :                                         smb_fname->twrp,
     352           7 :                                         smb_fname->flags);
     353          14 :         if (tmp_fname == NULL) {
     354           0 :                 errno = ENOMEM;
     355           0 :                 goto fail;
     356             :         }
     357             : 
     358          14 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     359             :                                 handle->conn->cwd_fsp,
     360             :                                 tmp_fname,
     361             :                                 0755);
     362          14 :         if ((ret != 0) && (errno != EEXIST)) {
     363           0 :                 goto fail;
     364             :         }
     365             : 
     366          14 :         TALLOC_FREE(tmp);
     367          14 :         TALLOC_FREE(tmp_fname);
     368             : 
     369          14 :         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
     370             :                               second);
     371          14 :         if (tmp == NULL) {
     372           0 :                 errno = ENOMEM;
     373           0 :                 goto fail;
     374             :         }
     375             : 
     376          14 :         tmp_fname = synthetic_smb_fname(talloc_tos(),
     377             :                                         tmp,
     378             :                                         NULL,
     379             :                                         NULL,
     380           7 :                                         smb_fname->twrp,
     381           7 :                                         smb_fname->flags);
     382          14 :         if (tmp_fname == NULL) {
     383           0 :                 errno = ENOMEM;
     384           0 :                 goto fail;
     385             :         }
     386             : 
     387          14 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     388             :                         handle->conn->cwd_fsp,
     389             :                         tmp_fname,
     390             :                         0755);
     391          14 :         if ((ret != 0) && (errno != EEXIST)) {
     392           0 :                 goto fail;
     393             :         }
     394             : 
     395          14 :         TALLOC_FREE(tmp);
     396          14 :         TALLOC_FREE(tmp_fname);
     397             : 
     398             :         /* smb_fname_hash is the struct smb_filename version of 'result' */
     399          14 :         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     400             :                         handle->conn->cwd_fsp,
     401             :                         smb_fname_hash,
     402             :                         0755);
     403          14 :         if ((ret != 0) && (errno != EEXIST)) {
     404           0 :                 goto fail;
     405             :         }
     406             : 
     407          14 :         TALLOC_FREE(rootdir_fname);
     408          14 :         TALLOC_FREE(rootdir);
     409          14 :         TALLOC_FREE(tmp_fname);
     410          14 :         TALLOC_FREE(smb_fname_hash);
     411          14 :         return result;
     412             : 
     413        4128 :  fail:
     414        4128 :         TALLOC_FREE(rootdir_fname);
     415        4128 :         TALLOC_FREE(rootdir);
     416        4128 :         TALLOC_FREE(tmp_fname);
     417        4128 :         TALLOC_FREE(smb_fname_hash);
     418        4128 :         TALLOC_FREE(result);
     419        4128 :         return NULL;
     420             : }
     421             : /**
     422             :  * Given a stream name, populate smb_fname_out with the actual location of the
     423             :  * stream.
     424             :  */
     425          86 : 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             :         char *dirname, *stream_fname;
     432             :         const char *stype;
     433             :         NTSTATUS status;
     434             : 
     435          86 :         *smb_fname_out = NULL;
     436             : 
     437          86 :         stype = strchr_m(smb_fname->stream_name + 1, ':');
     438             : 
     439          86 :         if (stype) {
     440          48 :                 if (strcasecmp_m(stype, ":$DATA") != 0) {
     441           0 :                         return NT_STATUS_INVALID_PARAMETER;
     442             :                 }
     443             :         }
     444             : 
     445          86 :         dirname = stream_dir(handle, smb_fname, base_sbuf, create_dir);
     446             : 
     447          86 :         if (dirname == NULL) {
     448           6 :                 status = map_nt_error_from_unix(errno);
     449           6 :                 goto fail;
     450             :         }
     451             : 
     452          80 :         stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
     453          40 :                                        smb_fname->stream_name);
     454             : 
     455          80 :         if (stream_fname == NULL) {
     456           0 :                 status = NT_STATUS_NO_MEMORY;
     457           0 :                 goto fail;
     458             :         }
     459             : 
     460          80 :         if (stype == NULL) {
     461             :                 /* Append an explicit stream type if one wasn't specified. */
     462          32 :                 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
     463             :                                                stream_fname);
     464          32 :                 if (stream_fname == NULL) {
     465           0 :                         status = NT_STATUS_NO_MEMORY;
     466           0 :                         goto fail;
     467             :                 }
     468             :         } else {
     469             :                 /* Normalize the stream type to upercase. */
     470          48 :                 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
     471           0 :                         status = NT_STATUS_INVALID_PARAMETER;
     472           0 :                         goto fail;
     473             :                 }
     474             :         }
     475             : 
     476          80 :         DEBUG(10, ("stream filename = %s\n", stream_fname));
     477             : 
     478             :         /* Create an smb_filename with stream_name == NULL. */
     479          80 :         *smb_fname_out = synthetic_smb_fname(talloc_tos(),
     480             :                                         stream_fname,
     481             :                                         NULL,
     482             :                                         NULL,
     483          40 :                                         smb_fname->twrp,
     484          40 :                                         smb_fname->flags);
     485          80 :         if (*smb_fname_out == NULL) {
     486           0 :                 return NT_STATUS_NO_MEMORY;
     487             :         }
     488             : 
     489          80 :         return NT_STATUS_OK;
     490             : 
     491           6 :  fail:
     492           6 :         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
     493           6 :         TALLOC_FREE(*smb_fname_out);
     494           6 :         return status;
     495             : }
     496             : 
     497        2801 : 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             :         char *dirname;
     506        2801 :         char *rootdir = NULL;
     507        2801 :         char *orig_connectpath = NULL;
     508        2801 :         struct smb_filename *dir_smb_fname = NULL;
     509        2801 :         struct smb_Dir *dir_hnd = NULL;
     510        2801 :         const char *dname = NULL;
     511        2801 :         long offset = 0;
     512        2801 :         char *talloced = NULL;
     513             :         NTSTATUS status;
     514             : 
     515        2801 :         dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
     516             :                              false);
     517             : 
     518        2801 :         if (dirname == NULL) {
     519        2769 :                 if (errno == ENOENT) {
     520             :                         /*
     521             :                          * no stream around
     522             :                          */
     523        2769 :                         return NT_STATUS_OK;
     524             :                 }
     525           0 :                 return map_nt_error_from_unix(errno);
     526             :         }
     527             : 
     528          32 :         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
     529             : 
     530          32 :         dir_smb_fname = synthetic_smb_fname(talloc_tos(),
     531             :                                         dirname,
     532             :                                         NULL,
     533             :                                         NULL,
     534             :                                         smb_fname_base->twrp,
     535             :                                         smb_fname_base->flags);
     536          32 :         if (dir_smb_fname == NULL) {
     537           0 :                 TALLOC_FREE(dirname);
     538           0 :                 return NT_STATUS_NO_MEMORY;
     539             :         }
     540             : 
     541             :         /*
     542             :          * For OpenDir to succeed if the stream rootdir is outside
     543             :          * the share path, we must temporarily swap out the connect
     544             :          * path for this share. We're dealing with absolute paths
     545             :          * here so we don't care about chdir calls.
     546             :          */
     547          32 :         rootdir = stream_rootdir(handle, talloc_tos());
     548          32 :         if (rootdir == NULL) {
     549           0 :                 TALLOC_FREE(dir_smb_fname);
     550           0 :                 TALLOC_FREE(dirname);
     551           0 :                 return NT_STATUS_NO_MEMORY;
     552             :         }
     553             : 
     554          32 :         orig_connectpath = handle->conn->connectpath;
     555          32 :         handle->conn->connectpath = rootdir;
     556             : 
     557          32 :         status = OpenDir(
     558          32 :                 talloc_tos(), handle->conn, dir_smb_fname, NULL, 0, &dir_hnd);
     559          32 :         if (!NT_STATUS_IS_OK(status)) {
     560           0 :                 handle->conn->connectpath = orig_connectpath;
     561           0 :                 TALLOC_FREE(rootdir);
     562           0 :                 TALLOC_FREE(dir_smb_fname);
     563           0 :                 TALLOC_FREE(dirname);
     564           0 :                 return status;
     565             :         }
     566             : 
     567         144 :         while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
     568          64 :                != NULL)
     569             :         {
     570          96 :                 if (ISDOT(dname) || ISDOTDOT(dname)) {
     571          64 :                         TALLOC_FREE(talloced);
     572          64 :                         continue;
     573             :                 }
     574             : 
     575          32 :                 DBG_DEBUG("dirent=%s\n", dname);
     576             : 
     577          32 :                 if (!fn(dir_smb_fname, dname, private_data)) {
     578           0 :                         TALLOC_FREE(talloced);
     579           0 :                         break;
     580             :                 }
     581          32 :                 TALLOC_FREE(talloced);
     582             :         }
     583             : 
     584             :         /* Restore the original connectpath. */
     585          32 :         handle->conn->connectpath = orig_connectpath;
     586          32 :         TALLOC_FREE(rootdir);
     587          32 :         TALLOC_FREE(dir_smb_fname);
     588          32 :         TALLOC_FREE(dir_hnd);
     589             : 
     590          32 :         if (pdirname != NULL) {
     591           0 :                 *pdirname = dirname;
     592             :         }
     593             :         else {
     594          32 :                 TALLOC_FREE(dirname);
     595             :         }
     596             : 
     597          32 :         return NT_STATUS_OK;
     598             : }
     599             : 
     600      143013 : static int streams_depot_stat(vfs_handle_struct *handle,
     601             :                               struct smb_filename *smb_fname)
     602             : {
     603      143013 :         struct smb_filename *smb_fname_stream = NULL;
     604             :         NTSTATUS status;
     605      143013 :         int ret = -1;
     606             : 
     607      143013 :         DEBUG(10, ("streams_depot_stat called for [%s]\n",
     608             :                    smb_fname_str_dbg(smb_fname)));
     609             : 
     610      143013 :         if (!is_named_stream(smb_fname)) {
     611      143001 :                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
     612             :         }
     613             : 
     614             :         /* Stat the actual stream now. */
     615          12 :         status = stream_smb_fname(
     616             :                 handle, NULL, smb_fname, &smb_fname_stream, false);
     617          12 :         if (!NT_STATUS_IS_OK(status)) {
     618           0 :                 ret = -1;
     619           0 :                 errno = map_errno_from_nt_status(status);
     620           0 :                 goto done;
     621             :         }
     622             : 
     623          12 :         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
     624             : 
     625             :         /* Update the original smb_fname with the stat info. */
     626          12 :         smb_fname->st = smb_fname_stream->st;
     627          12 :  done:
     628          12 :         TALLOC_FREE(smb_fname_stream);
     629          12 :         return ret;
     630             : }
     631             : 
     632             : 
     633             : 
     634        1896 : static int streams_depot_lstat(vfs_handle_struct *handle,
     635             :                                struct smb_filename *smb_fname)
     636             : {
     637        1896 :         struct smb_filename *smb_fname_stream = NULL;
     638             :         NTSTATUS status;
     639        1896 :         int ret = -1;
     640             : 
     641        1896 :         DEBUG(10, ("streams_depot_lstat called for [%s]\n",
     642             :                    smb_fname_str_dbg(smb_fname)));
     643             : 
     644        1896 :         if (!is_named_stream(smb_fname)) {
     645        1896 :                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
     646             :         }
     647             : 
     648             :         /* Stat the actual stream now. */
     649           0 :         status = stream_smb_fname(
     650             :                 handle, NULL, smb_fname, &smb_fname_stream, false);
     651           0 :         if (!NT_STATUS_IS_OK(status)) {
     652           0 :                 ret = -1;
     653           0 :                 errno = map_errno_from_nt_status(status);
     654           0 :                 goto done;
     655             :         }
     656             : 
     657           0 :         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
     658             : 
     659           0 :  done:
     660           0 :         TALLOC_FREE(smb_fname_stream);
     661           0 :         return ret;
     662             : }
     663             : 
     664      153981 : static int streams_depot_openat(struct vfs_handle_struct *handle,
     665             :                                 const struct files_struct *dirfsp,
     666             :                                 const struct smb_filename *smb_fname,
     667             :                                 struct files_struct *fsp,
     668             :                                 const struct vfs_open_how *how)
     669             : {
     670      153981 :         struct smb_filename *smb_fname_stream = NULL;
     671      153981 :         struct files_struct *fspcwd = NULL;
     672             :         NTSTATUS status;
     673             :         bool create_it;
     674      153981 :         int ret = -1;
     675             : 
     676      153981 :         if (!is_named_stream(smb_fname)) {
     677      153919 :                 return SMB_VFS_NEXT_OPENAT(handle,
     678             :                                            dirfsp,
     679             :                                            smb_fname,
     680             :                                            fsp,
     681             :                                            how);
     682             :         }
     683             : 
     684          62 :         if (how->resolve != 0) {
     685           0 :                 errno = ENOSYS;
     686           0 :                 return -1;
     687             :         }
     688             : 
     689          62 :         SMB_ASSERT(fsp_is_alternate_stream(fsp));
     690          62 :         SMB_ASSERT(dirfsp == NULL);
     691          62 :         SMB_ASSERT(VALID_STAT(fsp->base_fsp->fsp_name->st));
     692             : 
     693          62 :         create_it = (how->flags & O_CREAT);
     694             : 
     695             :         /* Determine the stream name, and then open it. */
     696          93 :         status = stream_smb_fname(
     697             :                 handle,
     698          62 :                 &fsp->base_fsp->fsp_name->st,
     699          62 :                 fsp->fsp_name,
     700             :                 &smb_fname_stream,
     701             :                 create_it);
     702          62 :         if (!NT_STATUS_IS_OK(status)) {
     703           6 :                 ret = -1;
     704           6 :                 errno = map_errno_from_nt_status(status);
     705           6 :                 goto done;
     706             :         }
     707             : 
     708          56 :         if (create_it) {
     709          21 :                 bool check_valid = lp_parm_bool(
     710          21 :                         SNUM(handle->conn),
     711             :                         "streams_depot",
     712             :                         "check_valid",
     713             :                         true);
     714             : 
     715          14 :                 if (check_valid) {
     716          14 :                         char buf = '1';
     717             : 
     718          14 :                         DBG_DEBUG("marking file %s as valid\n",
     719             :                                   fsp->base_fsp->fsp_name->base_name);
     720             : 
     721          14 :                         ret = SMB_VFS_FSETXATTR(
     722             :                                 fsp->base_fsp,
     723             :                                 SAMBA_XATTR_MARKER,
     724             :                                 &buf,
     725             :                                 sizeof(buf),
     726             :                                 0);
     727             : 
     728          14 :                         if (ret == -1) {
     729           0 :                                 DBG_DEBUG("FSETXATTR failed: %s\n",
     730             :                                           strerror(errno));
     731           0 :                                 return -1;
     732             :                         }
     733             :                 }
     734             :         }
     735             : 
     736          56 :         status = vfs_at_fspcwd(talloc_tos(), handle->conn, &fspcwd);
     737          56 :         if (!NT_STATUS_IS_OK(status)) {
     738           0 :                 ret = -1;
     739           0 :                 errno = map_errno_from_nt_status(status);
     740           0 :                 goto done;
     741             :         }
     742             : 
     743          56 :         ret = SMB_VFS_NEXT_OPENAT(handle,
     744             :                                   fspcwd,
     745             :                                   smb_fname_stream,
     746             :                                   fsp,
     747             :                                   how);
     748             : 
     749          62 :  done:
     750          62 :         TALLOC_FREE(smb_fname_stream);
     751          62 :         TALLOC_FREE(fspcwd);
     752          62 :         return ret;
     753             : }
     754             : 
     755         573 : static int streams_depot_unlink_internal(vfs_handle_struct *handle,
     756             :                                 struct files_struct *dirfsp,
     757             :                                 const struct smb_filename *smb_fname,
     758             :                                 int flags)
     759             : {
     760         573 :         struct smb_filename *full_fname = NULL;
     761         573 :         char *dirname = NULL;
     762         573 :         int ret = -1;
     763             : 
     764         573 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     765             :                                                   dirfsp,
     766             :                                                   smb_fname);
     767         573 :         if (full_fname == NULL) {
     768           0 :                 return -1;
     769             :         }
     770             : 
     771         573 :         DEBUG(10, ("streams_depot_unlink called for %s\n",
     772             :                    smb_fname_str_dbg(full_fname)));
     773             : 
     774             :         /* If there is a valid stream, just unlink the stream and return. */
     775         573 :         if (is_named_stream(full_fname)) {
     776          12 :                 struct smb_filename *smb_fname_stream = NULL;
     777             :                 NTSTATUS status;
     778             : 
     779          12 :                 status = stream_smb_fname(
     780             :                         handle, NULL, full_fname, &smb_fname_stream, false);
     781          12 :                 TALLOC_FREE(full_fname);
     782          12 :                 if (!NT_STATUS_IS_OK(status)) {
     783           0 :                         errno = map_errno_from_nt_status(status);
     784           0 :                         return -1;
     785             :                 }
     786             : 
     787          12 :                 ret = SMB_VFS_NEXT_UNLINKAT(handle,
     788             :                                 dirfsp->conn->cwd_fsp,
     789             :                                 smb_fname_stream,
     790             :                                 0);
     791             : 
     792          12 :                 TALLOC_FREE(smb_fname_stream);
     793          12 :                 return ret;
     794             :         }
     795             : 
     796             :         /*
     797             :          * We potentially need to delete the per-inode streams directory
     798             :          */
     799             : 
     800         561 :         if (full_fname->flags & SMB_FILENAME_POSIX_PATH) {
     801           0 :                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
     802             :         } else {
     803         561 :                 ret = SMB_VFS_NEXT_STAT(handle, full_fname);
     804         561 :                 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
     805           0 :                         if (VALID_STAT(smb_fname->st) &&
     806           0 :                                         S_ISLNK(smb_fname->st.st_ex_mode)) {
     807             :                                 /*
     808             :                                  * Original name was a link - Could be
     809             :                                  * trying to remove a dangling symlink.
     810             :                                  */
     811           0 :                                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
     812             :                         }
     813             :                 }
     814             :         }
     815         561 :         if (ret == -1) {
     816           0 :                 TALLOC_FREE(full_fname);
     817           0 :                 return -1;
     818             :         }
     819             : 
     820             :         /*
     821             :          * We know the unlink should succeed as the ACL
     822             :          * check is already done in the caller. Remove the
     823             :          * file *after* the streams.
     824             :          */
     825         561 :         dirname = stream_dir(handle,
     826             :                              full_fname,
     827         561 :                              &full_fname->st,
     828             :                              false);
     829         561 :         TALLOC_FREE(full_fname);
     830         561 :         if (dirname != NULL) {
     831           8 :                 struct smb_filename *smb_fname_dir = NULL;
     832             : 
     833           8 :                 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
     834             :                                                     dirname,
     835             :                                                     NULL,
     836             :                                                     NULL,
     837           4 :                                                     smb_fname->twrp,
     838           4 :                                                     smb_fname->flags);
     839           8 :                 if (smb_fname_dir == NULL) {
     840           0 :                         TALLOC_FREE(dirname);
     841           0 :                         errno = ENOMEM;
     842           0 :                         return -1;
     843             :                 }
     844             : 
     845           8 :                 SMB_VFS_NEXT_UNLINKAT(handle,
     846             :                                       dirfsp->conn->cwd_fsp,
     847             :                                       smb_fname_dir,
     848             :                                       AT_REMOVEDIR);
     849           8 :                 TALLOC_FREE(smb_fname_dir);
     850           8 :                 TALLOC_FREE(dirname);
     851             :         }
     852             : 
     853         561 :         ret = SMB_VFS_NEXT_UNLINKAT(handle,
     854             :                                 dirfsp,
     855             :                                 smb_fname,
     856             :                                 flags);
     857         561 :         return ret;
     858             : }
     859             : 
     860         804 : static int streams_depot_rmdir_internal(vfs_handle_struct *handle,
     861             :                         struct files_struct *dirfsp,
     862             :                         const struct smb_filename *smb_fname)
     863             : {
     864         804 :         struct smb_filename *full_fname = NULL;
     865         804 :         struct smb_filename *smb_fname_base = NULL;
     866         804 :         int ret = -1;
     867             : 
     868         804 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     869             :                                                   dirfsp,
     870             :                                                   smb_fname);
     871         804 :         if (full_fname == NULL) {
     872           0 :                 return -1;
     873             :         }
     874             : 
     875         804 :         DBG_DEBUG("called for %s\n", full_fname->base_name);
     876             : 
     877             :         /*
     878             :          * We potentially need to delete the per-inode streams directory
     879             :          */
     880             : 
     881        1565 :         smb_fname_base = synthetic_smb_fname(talloc_tos(),
     882         804 :                                 full_fname->base_name,
     883             :                                 NULL,
     884             :                                 NULL,
     885             :                                 full_fname->twrp,
     886             :                                 full_fname->flags);
     887         804 :         TALLOC_FREE(full_fname);
     888         804 :         if (smb_fname_base == NULL) {
     889           0 :                 errno = ENOMEM;
     890           0 :                 return -1;
     891             :         }
     892             : 
     893         804 :         if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
     894           0 :                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
     895             :         } else {
     896         804 :                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
     897             :         }
     898             : 
     899         804 :         if (ret == -1) {
     900           0 :                 TALLOC_FREE(smb_fname_base);
     901           0 :                 return -1;
     902             :         }
     903             : 
     904             :         /*
     905             :          * We know the rmdir should succeed as the ACL
     906             :          * check is already done in the caller. Remove the
     907             :          * directory *after* the streams.
     908             :          */
     909             :         {
     910         804 :                 char *dirname = stream_dir(handle, smb_fname_base,
     911         804 :                                            &smb_fname_base->st, false);
     912             : 
     913         804 :                 if (dirname != NULL) {
     914           2 :                         struct smb_filename *smb_fname_dir =
     915           4 :                                 synthetic_smb_fname(talloc_tos(),
     916             :                                                 dirname,
     917             :                                                 NULL,
     918             :                                                 NULL,
     919           2 :                                                 smb_fname->twrp,
     920           2 :                                                 smb_fname->flags);
     921           4 :                         if (smb_fname_dir == NULL) {
     922           0 :                                 TALLOC_FREE(smb_fname_base);
     923           0 :                                 TALLOC_FREE(dirname);
     924           0 :                                 errno = ENOMEM;
     925           0 :                                 return -1;
     926             :                         }
     927           4 :                         SMB_VFS_NEXT_UNLINKAT(handle,
     928             :                                         dirfsp->conn->cwd_fsp,
     929             :                                         smb_fname_dir,
     930             :                                         AT_REMOVEDIR);
     931           4 :                         TALLOC_FREE(smb_fname_dir);
     932             :                 }
     933         804 :                 TALLOC_FREE(dirname);
     934             :         }
     935             : 
     936         804 :         ret = SMB_VFS_NEXT_UNLINKAT(handle,
     937             :                                 dirfsp,
     938             :                                 smb_fname,
     939             :                                 AT_REMOVEDIR);
     940         804 :         TALLOC_FREE(smb_fname_base);
     941         804 :         return ret;
     942             : }
     943             : 
     944        1377 : static int streams_depot_unlinkat(vfs_handle_struct *handle,
     945             :                         struct files_struct *dirfsp,
     946             :                         const struct smb_filename *smb_fname,
     947             :                         int flags)
     948             : {
     949             :         int ret;
     950        1377 :         if (flags & AT_REMOVEDIR) {
     951         804 :                 ret = streams_depot_rmdir_internal(handle,
     952             :                                 dirfsp,
     953             :                                 smb_fname);
     954             :         } else {
     955         573 :                 ret = streams_depot_unlink_internal(handle,
     956             :                                 dirfsp,
     957             :                                 smb_fname,
     958             :                                 flags);
     959             :         }
     960        1377 :         return ret;
     961             : }
     962             : 
     963          20 : static int streams_depot_renameat(vfs_handle_struct *handle,
     964             :                                 files_struct *srcfsp,
     965             :                                 const struct smb_filename *smb_fname_src,
     966             :                                 files_struct *dstfsp,
     967             :                                 const struct smb_filename *smb_fname_dst)
     968             : {
     969          20 :         struct smb_filename *smb_fname_src_stream = NULL;
     970          20 :         struct smb_filename *smb_fname_dst_stream = NULL;
     971          20 :         struct smb_filename *full_src = NULL;
     972          20 :         struct smb_filename *full_dst = NULL;
     973             :         bool src_is_stream, dst_is_stream;
     974             :         NTSTATUS status;
     975          20 :         int ret = -1;
     976             : 
     977          20 :         DEBUG(10, ("streams_depot_renameat called for %s => %s\n",
     978             :                    smb_fname_str_dbg(smb_fname_src),
     979             :                    smb_fname_str_dbg(smb_fname_dst)));
     980             : 
     981          20 :         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
     982          20 :         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
     983             : 
     984          20 :         if (!src_is_stream && !dst_is_stream) {
     985          20 :                 return SMB_VFS_NEXT_RENAMEAT(handle,
     986             :                                         srcfsp,
     987             :                                         smb_fname_src,
     988             :                                         dstfsp,
     989             :                                         smb_fname_dst);
     990             :         }
     991             : 
     992             :         /* for now don't allow renames from or to the default stream */
     993           0 :         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
     994           0 :             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
     995           0 :                 errno = ENOSYS;
     996           0 :                 goto done;
     997             :         }
     998             : 
     999           0 :         full_src = full_path_from_dirfsp_atname(talloc_tos(),
    1000             :                                                 srcfsp,
    1001             :                                                 smb_fname_src);
    1002           0 :         if (full_src == NULL) {
    1003           0 :                 errno = ENOMEM;
    1004           0 :                 goto done;
    1005             :         }
    1006             : 
    1007           0 :         full_dst = full_path_from_dirfsp_atname(talloc_tos(),
    1008             :                                                 dstfsp,
    1009             :                                                 smb_fname_dst);
    1010           0 :         if (full_dst == NULL) {
    1011           0 :                 errno = ENOMEM;
    1012           0 :                 goto done;
    1013             :         }
    1014             : 
    1015           0 :         status = stream_smb_fname(
    1016             :                 handle, NULL, full_src, &smb_fname_src_stream, false);
    1017           0 :         if (!NT_STATUS_IS_OK(status)) {
    1018           0 :                 errno = map_errno_from_nt_status(status);
    1019           0 :                 goto done;
    1020             :         }
    1021             : 
    1022           0 :         status = stream_smb_fname(
    1023             :                 handle, NULL, full_dst, &smb_fname_dst_stream, false);
    1024           0 :         if (!NT_STATUS_IS_OK(status)) {
    1025           0 :                 errno = map_errno_from_nt_status(status);
    1026           0 :                 goto done;
    1027             :         }
    1028             : 
    1029             :         /*
    1030             :          * We must use handle->conn->cwd_fsp as
    1031             :          * srcfsp and dstfsp directory handles here
    1032             :          * as we used the full pathname from the cwd dir
    1033             :          * to calculate the streams directory and filename
    1034             :          * within.
    1035             :          */
    1036           0 :         ret = SMB_VFS_NEXT_RENAMEAT(handle,
    1037             :                                 handle->conn->cwd_fsp,
    1038             :                                 smb_fname_src_stream,
    1039             :                                 handle->conn->cwd_fsp,
    1040             :                                 smb_fname_dst_stream);
    1041             : 
    1042           0 : done:
    1043           0 :         TALLOC_FREE(smb_fname_src_stream);
    1044           0 :         TALLOC_FREE(smb_fname_dst_stream);
    1045           0 :         return ret;
    1046             : }
    1047             : 
    1048          32 : static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
    1049             :                            struct stream_struct **streams,
    1050             :                            const char *name, off_t size,
    1051             :                            off_t alloc_size)
    1052             : {
    1053             :         struct stream_struct *tmp;
    1054             : 
    1055          32 :         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
    1056             :                                    (*num_streams)+1);
    1057          32 :         if (tmp == NULL) {
    1058           0 :                 return false;
    1059             :         }
    1060             : 
    1061          32 :         tmp[*num_streams].name = talloc_strdup(tmp, name);
    1062          32 :         if (tmp[*num_streams].name == NULL) {
    1063           0 :                 return false;
    1064             :         }
    1065             : 
    1066          32 :         tmp[*num_streams].size = size;
    1067          32 :         tmp[*num_streams].alloc_size = alloc_size;
    1068             : 
    1069          32 :         *streams = tmp;
    1070          32 :         *num_streams += 1;
    1071          32 :         return true;
    1072             : }
    1073             : 
    1074             : struct streaminfo_state {
    1075             :         TALLOC_CTX *mem_ctx;
    1076             :         vfs_handle_struct *handle;
    1077             :         unsigned int num_streams;
    1078             :         struct stream_struct *streams;
    1079             :         NTSTATUS status;
    1080             : };
    1081             : 
    1082          32 : static bool collect_one_stream(const struct smb_filename *dirfname,
    1083             :                                const char *dirent,
    1084             :                                void *private_data)
    1085             : {
    1086          32 :         const char *dirname = dirfname->base_name;
    1087          32 :         struct streaminfo_state *state =
    1088             :                 (struct streaminfo_state *)private_data;
    1089          32 :         struct smb_filename *smb_fname = NULL;
    1090          32 :         char *sname = NULL;
    1091             :         bool ret;
    1092             : 
    1093          32 :         sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
    1094          32 :         if (sname == NULL) {
    1095           0 :                 state->status = NT_STATUS_NO_MEMORY;
    1096           0 :                 ret = false;
    1097           0 :                 goto out;
    1098             :         }
    1099             : 
    1100          32 :         smb_fname = synthetic_smb_fname(talloc_tos(),
    1101             :                                         sname,
    1102             :                                         NULL,
    1103             :                                         NULL,
    1104          16 :                                         dirfname->twrp,
    1105             :                                         0);
    1106          32 :         if (smb_fname == NULL) {
    1107           0 :                 state->status = NT_STATUS_NO_MEMORY;
    1108           0 :                 ret = false;
    1109           0 :                 goto out;
    1110             :         }
    1111             : 
    1112          32 :         if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
    1113           0 :                 DEBUG(10, ("Could not stat %s: %s\n", sname,
    1114             :                            strerror(errno)));
    1115           0 :                 ret = true;
    1116           0 :                 goto out;
    1117             :         }
    1118             : 
    1119          32 :         if (!add_one_stream(state->mem_ctx,
    1120             :                             &state->num_streams, &state->streams,
    1121             :                             dirent, smb_fname->st.st_ex_size,
    1122          32 :                             SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
    1123             :                                                    &smb_fname->st))) {
    1124           0 :                 state->status = NT_STATUS_NO_MEMORY;
    1125           0 :                 ret = false;
    1126           0 :                 goto out;
    1127             :         }
    1128             : 
    1129          32 :         ret = true;
    1130          32 :  out:
    1131          32 :         TALLOC_FREE(sname);
    1132          32 :         TALLOC_FREE(smb_fname);
    1133          32 :         return ret;
    1134             : }
    1135             : 
    1136        2801 : static NTSTATUS streams_depot_fstreaminfo(vfs_handle_struct *handle,
    1137             :                                          struct files_struct *fsp,
    1138             :                                          TALLOC_CTX *mem_ctx,
    1139             :                                          unsigned int *pnum_streams,
    1140             :                                          struct stream_struct **pstreams)
    1141             : {
    1142        2801 :         struct smb_filename *smb_fname_base = NULL;
    1143             :         int ret;
    1144             :         NTSTATUS status;
    1145             :         struct streaminfo_state state;
    1146             : 
    1147        7867 :         smb_fname_base = synthetic_smb_fname(talloc_tos(),
    1148        2801 :                                         fsp->fsp_name->base_name,
    1149             :                                         NULL,
    1150             :                                         NULL,
    1151        2801 :                                         fsp->fsp_name->twrp,
    1152        2801 :                                         fsp->fsp_name->flags);
    1153        2801 :         if (smb_fname_base == NULL) {
    1154           0 :                 return NT_STATUS_NO_MEMORY;
    1155             :         }
    1156             : 
    1157        2801 :         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
    1158        2801 :         if (ret == -1) {
    1159           0 :                 status = map_nt_error_from_unix(errno);
    1160           0 :                 goto out;
    1161             :         }
    1162             : 
    1163        2801 :         state.streams = *pstreams;
    1164        2801 :         state.num_streams = *pnum_streams;
    1165        2801 :         state.mem_ctx = mem_ctx;
    1166        2801 :         state.handle = handle;
    1167        2801 :         state.status = NT_STATUS_OK;
    1168             : 
    1169        2801 :         status = walk_streams(handle,
    1170             :                                 smb_fname_base,
    1171             :                                 NULL,
    1172             :                                 collect_one_stream,
    1173             :                                 &state);
    1174             : 
    1175        2801 :         if (!NT_STATUS_IS_OK(status)) {
    1176           0 :                 TALLOC_FREE(state.streams);
    1177           0 :                 goto out;
    1178             :         }
    1179             : 
    1180        2801 :         if (!NT_STATUS_IS_OK(state.status)) {
    1181           0 :                 TALLOC_FREE(state.streams);
    1182           0 :                 status = state.status;
    1183           0 :                 goto out;
    1184             :         }
    1185             : 
    1186        2801 :         *pnum_streams = state.num_streams;
    1187        2801 :         *pstreams = state.streams;
    1188        2801 :         status = SMB_VFS_NEXT_FSTREAMINFO(handle,
    1189             :                                 fsp->base_fsp ? fsp->base_fsp : fsp,
    1190             :                                 mem_ctx,
    1191             :                                 pnum_streams,
    1192             :                                 pstreams);
    1193             : 
    1194        2801 :  out:
    1195        2801 :         TALLOC_FREE(smb_fname_base);
    1196        2801 :         return status;
    1197             : }
    1198             : 
    1199        3893 : static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
    1200             :                         enum timestamp_set_resolution *p_ts_res)
    1201             : {
    1202        3893 :         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
    1203             : }
    1204             : 
    1205             : static struct vfs_fn_pointers vfs_streams_depot_fns = {
    1206             :         .fs_capabilities_fn = streams_depot_fs_capabilities,
    1207             :         .openat_fn = streams_depot_openat,
    1208             :         .stat_fn = streams_depot_stat,
    1209             :         .lstat_fn = streams_depot_lstat,
    1210             :         .unlinkat_fn = streams_depot_unlinkat,
    1211             :         .renameat_fn = streams_depot_renameat,
    1212             :         .fstreaminfo_fn = streams_depot_fstreaminfo,
    1213             : };
    1214             : 
    1215             : static_decl_vfs;
    1216        4875 : NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
    1217             : {
    1218        4875 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
    1219             :                                 &vfs_streams_depot_fns);
    1220             : }

Generated by: LCOV version 1.13