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

Generated by: LCOV version 1.14