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

Generated by: LCOV version 1.13