2008-01-20 01:36:34 +03:00
/*
* Store streams in a separate subdirectory
*
* Copyright ( C ) Volker Lendecke , 2007
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2008-01-20 01:36:34 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
/*
* Excerpt from a mail from tridge :
*
* Volker , what I ' m thinking of is this :
* / mount - point / . streams / XX / YY / aaaa . bbbb / namedstream1
* / mount - point / . streams / XX / YY / aaaa . bbbb / namedstream2
*
* where XX / YY is a 2 level hash based on the fsid / inode . " aaaa.bbbb "
* is the fsid / inode . " namedstreamX " is a file named after the stream
* name .
*/
static uint32_t hash_fn ( DATA_BLOB key )
{
uint32_t value ; /* Used to compute the hash value. */
uint32_t i ; /* Used to cycle through random values. */
/* Set the initial value from the key size. */
for ( value = 0x238F13AF * key . length , i = 0 ; i < key . length ; i + + )
value = ( value + ( key . data [ i ] < < ( i * 5 % 24 ) ) ) ;
return ( 1103515243 * value + 12345 ) ;
}
/*
* With the hashing scheme based on the inode we need to protect against
* streams showing up on files with re - used inodes . This can happen if we
* create a stream directory from within Samba , and a local process or NFS
* client deletes the file without deleting the streams directory . When the
* inode is re - used and the stream directory is still around , the streams in
* there would be show up as belonging to the new file .
*
* There are several workarounds for this , probably the easiest one is on
* systems which have a true birthtime stat element : When the file has a later
* birthtime than the streams directory , then we have to recreate the
* directory .
*
* The other workaround is to somehow mark the file as generated by Samba with
* something that a NFS client would not do . The closest one is a special
* xattr value being set . On systems which do not support xattrs , it might be
* an option to put in a special ACL entry for a non - existing group .
*/
2017-05-26 02:42:04 +03:00
static bool file_is_valid ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
2008-01-20 01:36:34 +03:00
{
char buf ;
2021-06-22 22:01:13 +03:00
NTSTATUS status ;
struct smb_filename * pathref = NULL ;
int ret ;
2008-01-20 01:36:34 +03:00
2017-05-26 02:42:04 +03:00
DEBUG ( 10 , ( " file_is_valid (%s) called \n " , smb_fname - > base_name ) ) ;
2008-01-20 01:36:34 +03:00
2021-06-22 22:01:13 +03:00
status = synthetic_pathref ( talloc_tos ( ) ,
handle - > conn - > cwd_fsp ,
smb_fname - > base_name ,
NULL ,
NULL ,
smb_fname - > twrp ,
smb_fname - > flags ,
& pathref ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return false ;
}
ret = SMB_VFS_FGETXATTR ( pathref - > fsp ,
SAMBA_XATTR_MARKER ,
& buf ,
sizeof ( buf ) ) ;
if ( ret ! = sizeof ( buf ) ) {
int saved_errno = errno ;
DBG_DEBUG ( " FGETXATTR failed: %s \n " , strerror ( saved_errno ) ) ;
TALLOC_FREE ( pathref ) ;
errno = saved_errno ;
2008-01-20 01:36:34 +03:00
return false ;
}
2021-06-22 22:01:13 +03:00
TALLOC_FREE ( pathref ) ;
2008-01-20 01:36:34 +03:00
if ( buf ! = ' 1 ' ) {
DEBUG ( 10 , ( " got wrong buffer content: '%c' \n " , buf ) ) ;
return false ;
}
return true ;
}
2021-07-20 00:52:32 +03:00
/*
* Return the root of the stream directory . Can be
* external to the share definition but by default
* is " handle->conn->connectpath/.streams " .
*
* Note that this is an * absolute * path , starting
* with ' / ' , so the dirfsp being used in the
* calls below isn ' t looked at .
*/
static char * stream_rootdir ( vfs_handle_struct * handle ,
TALLOC_CTX * ctx )
{
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
char * tmp ;
tmp = talloc_asprintf ( ctx ,
" %s/.streams " ,
handle - > conn - > connectpath ) ;
if ( tmp = = NULL ) {
errno = ENOMEM ;
return NULL ;
}
return lp_parm_substituted_string ( ctx ,
lp_sub ,
SNUM ( handle - > conn ) ,
" streams_depot " ,
" directory " ,
tmp ) ;
}
2009-06-23 02:26:56 +04:00
/**
* Given an smb_filename , determine the stream directory using the file ' s
* base_name .
*/
static char * stream_dir ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
2008-01-20 01:36:34 +03:00
const SMB_STRUCT_STAT * base_sbuf , bool create_it )
{
uint32_t hash ;
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname_hash = NULL ;
2008-01-20 01:36:34 +03:00
char * result = NULL ;
2009-06-23 02:26:56 +04:00
SMB_STRUCT_STAT base_sbuf_tmp ;
2021-07-20 00:52:32 +03:00
char * tmp = NULL ;
2008-01-20 01:36:34 +03:00
uint8_t first , second ;
char * id_hex ;
struct file_id id ;
2015-05-03 06:11:02 +03:00
uint8_t id_buf [ 16 ] ;
2008-12-02 01:20:21 +03:00
bool check_valid ;
2016-03-10 23:37:49 +03:00
char * rootdir = NULL ;
2016-02-24 00:14:03 +03:00
struct smb_filename * rootdir_fname = NULL ;
struct smb_filename * tmp_fname = NULL ;
2019-09-06 20:02:27 +03:00
int ret ;
2008-01-20 01:36:34 +03:00
2008-12-02 01:20:21 +03:00
check_valid = lp_parm_bool ( SNUM ( handle - > conn ) ,
" streams_depot " , " check_valid " , true ) ;
2021-07-20 00:52:32 +03:00
rootdir = stream_rootdir ( handle ,
talloc_tos ( ) ) ;
2016-03-10 23:37:49 +03:00
if ( rootdir = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2008-01-20 01:36:34 +03:00
2016-02-24 00:14:03 +03:00
rootdir_fname = synthetic_smb_fname ( talloc_tos ( ) ,
rootdir ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2016-02-24 00:14:03 +03:00
if ( rootdir_fname = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2009-06-23 02:26:56 +04:00
/* Stat the base file if it hasn't already been done. */
2008-01-20 01:36:34 +03:00
if ( base_sbuf = = NULL ) {
2013-04-12 13:26:27 +04:00
struct smb_filename * smb_fname_base ;
smb_fname_base = synthetic_smb_fname (
2016-03-19 07:19:38 +03:00
talloc_tos ( ) ,
smb_fname - > base_name ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2013-04-12 13:26:27 +04:00
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
2009-06-23 02:26:56 +04:00
goto fail ;
}
if ( SMB_VFS_NEXT_STAT ( handle , smb_fname_base ) = = - 1 ) {
TALLOC_FREE ( smb_fname_base ) ;
2008-01-20 01:36:34 +03:00
goto fail ;
}
2009-06-23 02:26:56 +04:00
base_sbuf_tmp = smb_fname_base - > st ;
TALLOC_FREE ( smb_fname_base ) ;
} else {
base_sbuf_tmp = * base_sbuf ;
2008-01-20 01:36:34 +03:00
}
2009-06-23 02:26:56 +04:00
id = SMB_VFS_FILE_ID_CREATE ( handle - > conn , & base_sbuf_tmp ) ;
2008-01-20 01:36:34 +03:00
push_file_id_16 ( ( char * ) id_buf , & id ) ;
hash = hash_fn ( data_blob_const ( id_buf , sizeof ( id_buf ) ) ) ;
first = hash & 0xff ;
second = ( hash > > 8 ) & 0xff ;
2008-11-22 09:51:20 +03:00
id_hex = hex_encode_talloc ( talloc_tos ( ) , id_buf , sizeof ( id_buf ) ) ;
2008-01-20 01:36:34 +03:00
if ( id_hex = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
result = talloc_asprintf ( talloc_tos ( ) , " %s/%2.2X/%2.2X/%s " , rootdir ,
first , second , id_hex ) ;
TALLOC_FREE ( id_hex ) ;
if ( result = = NULL ) {
errno = ENOMEM ;
return NULL ;
}
2016-03-19 07:19:38 +03:00
smb_fname_hash = synthetic_smb_fname ( talloc_tos ( ) ,
result ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2013-04-12 13:26:27 +04:00
if ( smb_fname_hash = = NULL ) {
errno = ENOMEM ;
2009-06-23 02:26:56 +04:00
goto fail ;
}
if ( SMB_VFS_NEXT_STAT ( handle , smb_fname_hash ) = = 0 ) {
2009-07-01 04:04:38 +04:00
struct smb_filename * smb_fname_new = NULL ;
2008-01-20 01:36:34 +03:00
char * newname ;
2012-09-27 14:40:47 +04:00
bool delete_lost ;
2008-01-20 01:36:34 +03:00
2009-06-23 02:26:56 +04:00
if ( ! S_ISDIR ( smb_fname_hash - > st . st_ex_mode ) ) {
2008-01-20 01:36:34 +03:00
errno = EINVAL ;
goto fail ;
}
2012-02-01 23:40:06 +04:00
if ( ! check_valid | |
2017-05-26 02:42:04 +03:00
file_is_valid ( handle , smb_fname ) ) {
2008-01-20 01:36:34 +03:00
return result ;
}
/*
* Someone has recreated a file under an existing inode
2012-09-27 14:40:47 +04:00
* without deleting the streams directory .
* Move it away or remove if streams_depot : delete_lost is set .
2008-01-20 01:36:34 +03:00
*/
again :
2012-09-27 14:40:47 +04:00
delete_lost = lp_parm_bool ( SNUM ( handle - > conn ) , " streams_depot " ,
" delete_lost " , false ) ;
if ( delete_lost ) {
DEBUG ( 3 , ( " Someone has recreated a file under an "
" existing inode. Removing: %s \n " ,
smb_fname_hash - > base_name ) ) ;
recursive_rmdir ( talloc_tos ( ) , handle - > conn ,
smb_fname_hash ) ;
2019-10-05 01:38:45 +03:00
SMB_VFS_NEXT_UNLINKAT ( handle ,
handle - > conn - > cwd_fsp ,
smb_fname_hash ,
AT_REMOVEDIR ) ;
2012-09-27 14:40:47 +04:00
} else {
newname = talloc_asprintf ( talloc_tos ( ) , " lost-%lu " ,
random ( ) ) ;
DEBUG ( 3 , ( " Someone has recreated a file under an "
" existing inode. Renaming: %s to: %s \n " ,
smb_fname_hash - > base_name ,
newname ) ) ;
if ( newname = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2008-01-20 01:36:34 +03:00
2013-04-12 13:26:27 +04:00
smb_fname_new = synthetic_smb_fname (
2016-03-19 07:19:38 +03:00
talloc_tos ( ) ,
newname ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2012-09-27 14:40:47 +04:00
TALLOC_FREE ( newname ) ;
2013-04-12 13:26:27 +04:00
if ( smb_fname_new = = NULL ) {
errno = ENOMEM ;
2012-09-27 14:40:47 +04:00
goto fail ;
}
2009-07-01 04:04:38 +04:00
2019-08-10 02:29:58 +03:00
if ( SMB_VFS_NEXT_RENAMEAT ( handle ,
handle - > conn - > cwd_fsp ,
smb_fname_hash ,
handle - > conn - > cwd_fsp ,
smb_fname_new ) = = - 1 ) {
2012-09-27 14:40:47 +04:00
TALLOC_FREE ( smb_fname_new ) ;
if ( ( errno = = EEXIST ) | | ( errno = = ENOTEMPTY ) ) {
goto again ;
}
goto fail ;
2008-01-20 01:36:34 +03:00
}
2012-09-27 14:40:47 +04:00
TALLOC_FREE ( smb_fname_new ) ;
}
2008-01-20 01:36:34 +03:00
}
if ( ! create_it ) {
errno = ENOENT ;
goto fail ;
}
2019-09-06 20:02:27 +03:00
ret = SMB_VFS_NEXT_MKDIRAT ( handle ,
handle - > conn - > cwd_fsp ,
rootdir_fname ,
0755 ) ;
if ( ( ret ! = 0 ) & & ( errno ! = EEXIST ) ) {
2008-01-20 01:36:34 +03:00
goto fail ;
}
tmp = talloc_asprintf ( result , " %s/%2.2X " , rootdir , first ) ;
if ( tmp = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2016-03-19 07:19:38 +03:00
tmp_fname = synthetic_smb_fname ( talloc_tos ( ) ,
tmp ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2016-02-24 00:14:03 +03:00
if ( tmp_fname = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2019-09-06 20:02:27 +03:00
ret = SMB_VFS_NEXT_MKDIRAT ( handle ,
handle - > conn - > cwd_fsp ,
tmp_fname ,
0755 ) ;
if ( ( ret ! = 0 ) & & ( errno ! = EEXIST ) ) {
2008-01-20 01:36:34 +03:00
goto fail ;
}
TALLOC_FREE ( tmp ) ;
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( tmp_fname ) ;
2008-01-20 01:36:34 +03:00
tmp = talloc_asprintf ( result , " %s/%2.2X/%2.2X " , rootdir , first ,
second ) ;
if ( tmp = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2016-03-19 07:19:38 +03:00
tmp_fname = synthetic_smb_fname ( talloc_tos ( ) ,
tmp ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2016-02-24 00:14:03 +03:00
if ( tmp_fname = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2019-09-06 20:02:27 +03:00
ret = SMB_VFS_NEXT_MKDIRAT ( handle ,
handle - > conn - > cwd_fsp ,
tmp_fname ,
0755 ) ;
if ( ( ret ! = 0 ) & & ( errno ! = EEXIST ) ) {
2008-01-20 01:36:34 +03:00
goto fail ;
}
TALLOC_FREE ( tmp ) ;
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( tmp_fname ) ;
2008-01-20 01:36:34 +03:00
2016-02-24 00:14:03 +03:00
/* smb_fname_hash is the struct smb_filename version of 'result' */
2019-09-06 20:02:27 +03:00
ret = SMB_VFS_NEXT_MKDIRAT ( handle ,
handle - > conn - > cwd_fsp ,
smb_fname_hash ,
0755 ) ;
if ( ( ret ! = 0 ) & & ( errno ! = EEXIST ) ) {
2008-01-20 01:36:34 +03:00
goto fail ;
}
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( rootdir_fname ) ;
2016-03-10 23:37:49 +03:00
TALLOC_FREE ( rootdir ) ;
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( tmp_fname ) ;
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( smb_fname_hash ) ;
2008-01-20 01:36:34 +03:00
return result ;
fail :
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( rootdir_fname ) ;
2016-03-10 23:37:49 +03:00
TALLOC_FREE ( rootdir ) ;
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( tmp_fname ) ;
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( smb_fname_hash ) ;
2008-01-20 01:36:34 +03:00
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-06-16 23:01:13 +04:00
/**
* Given a stream name , populate smb_fname_out with the actual location of the
* stream .
*/
static NTSTATUS stream_smb_fname ( vfs_handle_struct * handle ,
2022-04-05 17:08:43 +03:00
const struct stat_ex * base_sbuf ,
2009-06-16 23:01:13 +04:00
const struct smb_filename * smb_fname ,
struct smb_filename * * smb_fname_out ,
bool create_dir )
{
char * dirname , * stream_fname ;
const char * stype ;
NTSTATUS status ;
* smb_fname_out = NULL ;
2009-08-18 13:34:54 +04:00
stype = strchr_m ( smb_fname - > stream_name + 1 , ' : ' ) ;
if ( stype ) {
2011-05-13 22:21:30 +04:00
if ( strcasecmp_m ( stype , " :$DATA " ) ! = 0 ) {
2009-08-18 13:34:54 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
}
2022-04-05 17:08:43 +03:00
dirname = stream_dir ( handle , smb_fname , base_sbuf , create_dir ) ;
2009-06-16 23:01:13 +04:00
if ( dirname = = NULL ) {
status = map_nt_error_from_unix ( errno ) ;
goto fail ;
}
stream_fname = talloc_asprintf ( talloc_tos ( ) , " %s/%s " , dirname ,
smb_fname - > stream_name ) ;
if ( stream_fname = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
if ( stype = = NULL ) {
/* Append an explicit stream type if one wasn't specified. */
stream_fname = talloc_asprintf ( talloc_tos ( ) , " %s:$DATA " ,
stream_fname ) ;
if ( stream_fname = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
} else {
2023-07-13 09:52:45 +03:00
/* Normalize the stream type to uppercase. */
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( strrchr_m ( stream_fname , ' : ' ) + 1 ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
2009-06-16 23:01:13 +04:00
}
DEBUG ( 10 , ( " stream filename = %s \n " , stream_fname ) ) ;
/* Create an smb_filename with stream_name == NULL. */
2016-03-19 07:19:38 +03:00
* smb_fname_out = synthetic_smb_fname ( talloc_tos ( ) ,
stream_fname ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2013-04-12 13:28:16 +04:00
if ( * smb_fname_out = = NULL ) {
return NT_STATUS_NO_MEMORY ;
2009-06-16 23:01:13 +04:00
}
return NT_STATUS_OK ;
fail :
DEBUG ( 5 , ( " stream_name failed: %s \n " , strerror ( errno ) ) ) ;
TALLOC_FREE ( * smb_fname_out ) ;
return status ;
}
2008-01-20 01:36:34 +03:00
static NTSTATUS walk_streams ( vfs_handle_struct * handle ,
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname_base ,
2008-01-20 01:36:34 +03:00
char * * pdirname ,
2020-04-30 12:42:50 +03:00
bool ( * fn ) ( const struct smb_filename * dirname ,
2008-01-20 01:36:34 +03:00
const char * dirent ,
void * private_data ) ,
void * private_data )
{
char * dirname ;
2021-07-20 01:10:41 +03:00
char * rootdir = NULL ;
char * orig_connectpath = NULL ;
2016-02-27 01:53:12 +03:00
struct smb_filename * dir_smb_fname = NULL ;
2020-03-19 14:03:27 +03:00
struct smb_Dir * dir_hnd = NULL ;
const char * dname = NULL ;
2009-11-16 11:49:23 +03:00
char * talloced = NULL ;
2022-02-21 19:19:49 +03:00
NTSTATUS status ;
2008-01-20 01:36:34 +03:00
2009-06-23 02:26:56 +04:00
dirname = stream_dir ( handle , smb_fname_base , & smb_fname_base - > st ,
false ) ;
2008-01-20 01:36:34 +03:00
if ( dirname = = NULL ) {
if ( errno = = ENOENT ) {
/*
* no stream around
*/
return NT_STATUS_OK ;
}
return map_nt_error_from_unix ( errno ) ;
}
DEBUG ( 10 , ( " walk_streams: dirname=%s \n " , dirname ) ) ;
2016-02-27 01:53:12 +03:00
dir_smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
dirname ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname_base - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname_base - > flags ) ;
2016-02-27 01:53:12 +03:00
if ( dir_smb_fname = = NULL ) {
TALLOC_FREE ( dirname ) ;
return NT_STATUS_NO_MEMORY ;
}
2021-07-20 01:10:41 +03:00
/*
* For OpenDir to succeed if the stream rootdir is outside
* the share path , we must temporarily swap out the connect
* path for this share . We ' re dealing with absolute paths
* here so we don ' t care about chdir calls .
*/
rootdir = stream_rootdir ( handle , talloc_tos ( ) ) ;
if ( rootdir = = NULL ) {
TALLOC_FREE ( dir_smb_fname ) ;
TALLOC_FREE ( dirname ) ;
return NT_STATUS_NO_MEMORY ;
}
orig_connectpath = handle - > conn - > connectpath ;
handle - > conn - > connectpath = rootdir ;
2022-03-01 01:34:48 +03:00
status = OpenDir (
2022-02-21 19:19:49 +03:00
talloc_tos ( ) , handle - > conn , dir_smb_fname , NULL , 0 , & dir_hnd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-07-20 01:10:41 +03:00
handle - > conn - > connectpath = orig_connectpath ;
TALLOC_FREE ( rootdir ) ;
2020-04-30 12:42:50 +03:00
TALLOC_FREE ( dir_smb_fname ) ;
2008-01-20 01:36:34 +03:00
TALLOC_FREE ( dirname ) ;
2022-02-21 19:19:49 +03:00
return status ;
2008-01-20 01:36:34 +03:00
}
2023-06-20 13:25:45 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & talloced ) ) ! = NULL ) {
2020-03-19 14:03:27 +03:00
if ( ISDOT ( dname ) | | ISDOTDOT ( dname ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2008-01-20 01:36:34 +03:00
continue ;
}
2020-03-19 14:03:27 +03:00
DBG_DEBUG ( " dirent=%s \n " , dname ) ;
2008-01-20 01:36:34 +03:00
2020-04-30 12:42:50 +03:00
if ( ! fn ( dir_smb_fname , dname , private_data ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2008-01-20 01:36:34 +03:00
break ;
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2008-01-20 01:36:34 +03:00
}
2021-07-20 01:10:41 +03:00
/* Restore the original connectpath. */
handle - > conn - > connectpath = orig_connectpath ;
TALLOC_FREE ( rootdir ) ;
2020-04-30 12:42:50 +03:00
TALLOC_FREE ( dir_smb_fname ) ;
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( dir_hnd ) ;
2008-01-20 01:36:34 +03:00
if ( pdirname ! = NULL ) {
* pdirname = dirname ;
}
else {
TALLOC_FREE ( dirname ) ;
}
return NT_STATUS_OK ;
}
2009-06-23 02:26:56 +04:00
static int streams_depot_stat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
struct smb_filename * smb_fname_stream = NULL ;
NTSTATUS status ;
2008-01-20 01:36:34 +03:00
int ret = - 1 ;
2009-06-23 02:26:56 +04:00
DEBUG ( 10 , ( " streams_depot_stat called for [%s] \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2008-01-20 01:36:34 +03:00
2019-09-26 20:31:51 +03:00
if ( ! is_named_stream ( smb_fname ) ) {
2009-06-23 02:26:56 +04:00
return SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
2008-01-20 01:36:34 +03:00
}
2009-06-23 02:26:56 +04:00
/* Stat the actual stream now. */
2022-04-05 17:08:43 +03:00
status = stream_smb_fname (
handle , NULL , smb_fname , & smb_fname_stream , false ) ;
2009-06-23 02:26:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = - 1 ;
errno = map_errno_from_nt_status ( status ) ;
2008-01-20 01:36:34 +03:00
goto done ;
}
2009-06-23 02:26:56 +04:00
ret = SMB_VFS_NEXT_STAT ( handle , smb_fname_stream ) ;
2008-01-20 01:36:34 +03:00
2009-06-23 02:26:56 +04:00
/* Update the original smb_fname with the stat info. */
smb_fname - > st = smb_fname_stream - > st ;
2008-01-20 01:36:34 +03:00
done :
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( smb_fname_stream ) ;
2008-01-20 01:36:34 +03:00
return ret ;
}
2009-06-23 02:26:56 +04:00
static int streams_depot_lstat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
2008-01-20 01:36:34 +03:00
{
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname_stream = NULL ;
NTSTATUS status ;
2008-01-20 01:36:34 +03:00
int ret = - 1 ;
2009-06-23 02:26:56 +04:00
DEBUG ( 10 , ( " streams_depot_lstat called for [%s] \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2019-09-26 20:31:51 +03:00
if ( ! is_named_stream ( smb_fname ) ) {
2009-06-23 02:26:56 +04:00
return SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
2008-01-20 01:36:34 +03:00
}
2009-06-23 02:26:56 +04:00
/* Stat the actual stream now. */
2022-04-05 17:08:43 +03:00
status = stream_smb_fname (
handle , NULL , smb_fname , & smb_fname_stream , false ) ;
2009-06-23 02:26:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = - 1 ;
errno = map_errno_from_nt_status ( status ) ;
2008-01-20 01:36:34 +03:00
goto done ;
}
2009-06-23 02:26:56 +04:00
ret = SMB_VFS_NEXT_LSTAT ( handle , smb_fname_stream ) ;
2008-01-20 01:36:34 +03:00
done :
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( smb_fname_stream ) ;
2008-01-20 01:36:34 +03:00
return ret ;
}
2020-05-21 00:07:20 +03:00
static int streams_depot_openat ( struct vfs_handle_struct * handle ,
const struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
struct files_struct * fsp ,
2022-06-03 16:53:29 +03:00
const struct vfs_open_how * how )
2020-05-21 00:07:20 +03:00
{
struct smb_filename * smb_fname_stream = NULL ;
struct files_struct * fspcwd = NULL ;
NTSTATUS status ;
2022-04-05 17:58:41 +03:00
bool create_it ;
2020-05-21 00:07:20 +03:00
int ret = - 1 ;
if ( ! is_named_stream ( smb_fname ) ) {
return SMB_VFS_NEXT_OPENAT ( handle ,
dirfsp ,
smb_fname ,
fsp ,
2022-06-03 16:53:29 +03:00
how ) ;
2020-05-21 00:07:20 +03:00
}
2022-06-03 17:45:41 +03:00
if ( how - > resolve ! = 0 ) {
errno = ENOSYS ;
return - 1 ;
}
2022-03-31 18:40:35 +03:00
SMB_ASSERT ( fsp_is_alternate_stream ( fsp ) ) ;
2022-06-14 17:33:57 +03:00
SMB_ASSERT ( dirfsp = = NULL ) ;
2022-03-31 19:12:32 +03:00
SMB_ASSERT ( VALID_STAT ( fsp - > base_fsp - > fsp_name - > st ) ) ;
2020-05-21 00:07:20 +03:00
2023-04-14 17:32:42 +03:00
create_it = ( how - > flags & O_CREAT ) ;
2022-04-05 17:58:41 +03:00
2020-05-21 00:07:20 +03:00
/* Determine the stream name, and then open it. */
2022-04-05 17:08:43 +03:00
status = stream_smb_fname (
handle ,
& fsp - > base_fsp - > fsp_name - > st ,
fsp - > fsp_name ,
& smb_fname_stream ,
2022-04-05 17:58:41 +03:00
create_it ) ;
2020-05-21 00:07:20 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = - 1 ;
errno = map_errno_from_nt_status ( status ) ;
goto done ;
}
2022-04-05 16:32:08 +03:00
if ( create_it ) {
bool check_valid = lp_parm_bool (
SNUM ( handle - > conn ) ,
" streams_depot " ,
" check_valid " ,
true ) ;
if ( check_valid ) {
char buf = ' 1 ' ;
DBG_DEBUG ( " marking file %s as valid \n " ,
fsp - > base_fsp - > fsp_name - > base_name ) ;
ret = SMB_VFS_FSETXATTR (
fsp - > base_fsp ,
SAMBA_XATTR_MARKER ,
& buf ,
sizeof ( buf ) ,
0 ) ;
if ( ret = = - 1 ) {
DBG_DEBUG ( " FSETXATTR failed: %s \n " ,
strerror ( errno ) ) ;
2023-09-27 08:46:36 +03:00
goto done ;
2022-04-05 16:32:08 +03:00
}
}
}
2020-05-21 00:07:20 +03:00
status = vfs_at_fspcwd ( talloc_tos ( ) , handle - > conn , & fspcwd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = - 1 ;
errno = map_errno_from_nt_status ( status ) ;
goto done ;
}
ret = SMB_VFS_NEXT_OPENAT ( handle ,
fspcwd ,
smb_fname_stream ,
fsp ,
2022-06-03 16:53:29 +03:00
how ) ;
2020-05-21 00:07:20 +03:00
done :
TALLOC_FREE ( smb_fname_stream ) ;
TALLOC_FREE ( fspcwd ) ;
return ret ;
}
2019-09-18 05:23:31 +03:00
static int streams_depot_unlink_internal ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
2008-01-20 01:36:34 +03:00
{
2021-01-21 18:06:21 +03:00
struct smb_filename * full_fname = NULL ;
2021-01-21 18:29:46 +03:00
char * dirname = NULL ;
2008-01-20 01:36:34 +03:00
int ret = - 1 ;
2021-01-21 18:06:21 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
return - 1 ;
}
2009-07-02 20:27:44 +04:00
DEBUG ( 10 , ( " streams_depot_unlink called for %s \n " ,
2021-01-21 18:06:21 +03:00
smb_fname_str_dbg ( full_fname ) ) ) ;
2008-01-20 01:36:34 +03:00
2009-07-02 20:27:44 +04:00
/* If there is a valid stream, just unlink the stream and return. */
2021-01-21 18:06:21 +03:00
if ( is_named_stream ( full_fname ) ) {
2009-07-02 20:27:44 +04:00
struct smb_filename * smb_fname_stream = NULL ;
2013-04-12 13:33:38 +04:00
NTSTATUS status ;
2008-01-20 01:36:34 +03:00
2022-04-05 17:08:43 +03:00
status = stream_smb_fname (
handle , NULL , full_fname , & smb_fname_stream , false ) ;
2021-01-21 18:06:21 +03:00
TALLOC_FREE ( full_fname ) ;
2009-07-02 20:27:44 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2008-01-20 01:36:34 +03:00
return - 1 ;
}
2019-09-18 05:26:13 +03:00
ret = SMB_VFS_NEXT_UNLINKAT ( handle ,
2021-01-21 18:06:21 +03:00
dirfsp - > conn - > cwd_fsp ,
2019-09-18 05:26:13 +03:00
smb_fname_stream ,
0 ) ;
2008-01-20 01:36:34 +03:00
2009-07-02 20:27:44 +04:00
TALLOC_FREE ( smb_fname_stream ) ;
2008-01-20 01:36:34 +03:00
return ret ;
}
/*
* We potentially need to delete the per - inode streams directory
*/
2021-01-21 18:06:21 +03:00
if ( full_fname - > flags & SMB_FILENAME_POSIX_PATH ) {
ret = SMB_VFS_NEXT_LSTAT ( handle , full_fname ) ;
2009-02-26 00:46:21 +03:00
} else {
2021-01-21 18:06:21 +03:00
ret = SMB_VFS_NEXT_STAT ( handle , full_fname ) ;
2021-10-25 22:01:58 +03:00
if ( ret = = - 1 & & ( errno = = ENOENT | | errno = = ELOOP ) ) {
if ( VALID_STAT ( smb_fname - > st ) & &
S_ISLNK ( smb_fname - > st . st_ex_mode ) ) {
/*
* Original name was a link - Could be
* trying to remove a dangling symlink .
*/
ret = SMB_VFS_NEXT_LSTAT ( handle , full_fname ) ;
}
}
2009-02-26 00:46:21 +03:00
}
if ( ret = = - 1 ) {
2021-01-21 18:06:21 +03:00
TALLOC_FREE ( full_fname ) ;
2008-01-20 01:36:34 +03:00
return - 1 ;
}
2016-10-19 21:56:49 +03:00
/*
* We know the unlink should succeed as the ACL
* check is already done in the caller . Remove the
* file * after * the streams .
*/
2021-01-21 18:29:46 +03:00
dirname = stream_dir ( handle ,
2021-01-21 18:06:21 +03:00
full_fname ,
& full_fname - > st ,
2021-01-21 18:29:46 +03:00
false ) ;
2021-01-21 18:06:21 +03:00
TALLOC_FREE ( full_fname ) ;
2021-01-21 18:29:46 +03:00
if ( dirname ! = NULL ) {
struct smb_filename * smb_fname_dir = NULL ;
smb_fname_dir = synthetic_smb_fname ( talloc_tos ( ) ,
dirname ,
NULL ,
NULL ,
smb_fname - > twrp ,
smb_fname - > flags ) ;
if ( smb_fname_dir = = NULL ) {
TALLOC_FREE ( dirname ) ;
errno = ENOMEM ;
return - 1 ;
2008-01-20 01:36:34 +03:00
}
2021-01-21 18:29:46 +03:00
SMB_VFS_NEXT_UNLINKAT ( handle ,
2021-01-21 18:06:21 +03:00
dirfsp - > conn - > cwd_fsp ,
2021-01-21 18:29:46 +03:00
smb_fname_dir ,
AT_REMOVEDIR ) ;
TALLOC_FREE ( smb_fname_dir ) ;
2008-01-20 01:36:34 +03:00
TALLOC_FREE ( dirname ) ;
}
2019-09-18 05:26:13 +03:00
ret = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2009-07-02 20:27:44 +04:00
return ret ;
2008-01-20 01:36:34 +03:00
}
2019-10-05 01:12:30 +03:00
static int streams_depot_rmdir_internal ( vfs_handle_struct * handle ,
2019-10-05 01:14:21 +03:00
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname )
2012-02-01 01:26:35 +04:00
{
2021-01-21 18:07:03 +03:00
struct smb_filename * full_fname = NULL ;
2012-02-01 01:26:35 +04:00
struct smb_filename * smb_fname_base = NULL ;
int ret = - 1 ;
2021-01-21 18:07:03 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
return - 1 ;
}
DBG_DEBUG ( " called for %s \n " , full_fname - > base_name ) ;
2012-02-01 01:26:35 +04:00
/*
* We potentially need to delete the per - inode streams directory
*/
2016-02-25 01:02:45 +03:00
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
2021-01-21 18:07:03 +03:00
full_fname - > base_name ,
2016-02-25 01:02:45 +03:00
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2021-01-21 18:07:03 +03:00
full_fname - > twrp ,
full_fname - > flags ) ;
TALLOC_FREE ( full_fname ) ;
2013-04-12 13:34:37 +04:00
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
2012-02-01 01:26:35 +04:00
return - 1 ;
}
2016-03-19 07:58:20 +03:00
if ( smb_fname_base - > flags & SMB_FILENAME_POSIX_PATH ) {
2012-02-01 01:26:35 +04:00
ret = SMB_VFS_NEXT_LSTAT ( handle , smb_fname_base ) ;
} else {
ret = SMB_VFS_NEXT_STAT ( handle , smb_fname_base ) ;
}
if ( ret = = - 1 ) {
TALLOC_FREE ( smb_fname_base ) ;
return - 1 ;
}
2016-10-19 21:56:49 +03:00
/*
* We know the rmdir should succeed as the ACL
* check is already done in the caller . Remove the
* directory * after * the streams .
*/
{
2013-11-12 19:33:20 +04:00
char * dirname = stream_dir ( handle , smb_fname_base ,
& smb_fname_base - > st , false ) ;
if ( dirname ! = NULL ) {
2016-02-25 01:02:45 +03:00
struct smb_filename * smb_fname_dir =
synthetic_smb_fname ( talloc_tos ( ) ,
dirname ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2016-03-19 07:19:38 +03:00
smb_fname - > flags ) ;
2016-02-25 01:02:45 +03:00
if ( smb_fname_dir = = NULL ) {
TALLOC_FREE ( smb_fname_base ) ;
TALLOC_FREE ( dirname ) ;
errno = ENOMEM ;
return - 1 ;
}
2019-10-05 01:16:06 +03:00
SMB_VFS_NEXT_UNLINKAT ( handle ,
2021-01-21 18:07:03 +03:00
dirfsp - > conn - > cwd_fsp ,
2019-10-05 01:16:06 +03:00
smb_fname_dir ,
AT_REMOVEDIR ) ;
2016-02-25 01:02:45 +03:00
TALLOC_FREE ( smb_fname_dir ) ;
2013-11-12 19:33:20 +04:00
}
TALLOC_FREE ( dirname ) ;
2012-02-01 01:26:35 +04:00
}
2019-10-05 01:16:06 +03:00
ret = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
2021-01-21 18:07:03 +03:00
smb_fname ,
2019-10-05 01:16:06 +03:00
AT_REMOVEDIR ) ;
2012-02-01 01:26:35 +04:00
TALLOC_FREE ( smb_fname_base ) ;
return ret ;
}
2019-09-12 23:41:10 +03:00
static int streams_depot_unlinkat ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
{
int ret ;
if ( flags & AT_REMOVEDIR ) {
2019-10-05 01:14:21 +03:00
ret = streams_depot_rmdir_internal ( handle ,
dirfsp ,
smb_fname ) ;
2019-09-12 23:41:10 +03:00
} else {
2019-09-18 05:23:31 +03:00
ret = streams_depot_unlink_internal ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2019-09-12 23:41:10 +03:00
}
return ret ;
}
2019-08-10 01:28:56 +03:00
static int streams_depot_renameat ( vfs_handle_struct * handle ,
files_struct * srcfsp ,
const struct smb_filename * smb_fname_src ,
files_struct * dstfsp ,
const struct smb_filename * smb_fname_dst )
{
struct smb_filename * smb_fname_src_stream = NULL ;
struct smb_filename * smb_fname_dst_stream = NULL ;
2021-06-18 07:05:00 +03:00
struct smb_filename * full_src = NULL ;
struct smb_filename * full_dst = NULL ;
2019-08-10 01:28:56 +03:00
bool src_is_stream , dst_is_stream ;
NTSTATUS status ;
int ret = - 1 ;
DEBUG ( 10 , ( " streams_depot_renameat called for %s => %s \n " ,
smb_fname_str_dbg ( smb_fname_src ) ,
smb_fname_str_dbg ( smb_fname_dst ) ) ) ;
src_is_stream = is_ntfs_stream_smb_fname ( smb_fname_src ) ;
dst_is_stream = is_ntfs_stream_smb_fname ( smb_fname_dst ) ;
if ( ! src_is_stream & & ! dst_is_stream ) {
return SMB_VFS_NEXT_RENAMEAT ( handle ,
srcfsp ,
smb_fname_src ,
dstfsp ,
smb_fname_dst ) ;
}
/* for now don't allow renames from or to the default stream */
if ( is_ntfs_default_stream_smb_fname ( smb_fname_src ) | |
is_ntfs_default_stream_smb_fname ( smb_fname_dst ) ) {
errno = ENOSYS ;
goto done ;
}
2021-06-18 07:05:00 +03:00
full_src = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
srcfsp ,
smb_fname_src ) ;
if ( full_src = = NULL ) {
errno = ENOMEM ;
goto done ;
}
full_dst = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dstfsp ,
smb_fname_dst ) ;
if ( full_dst = = NULL ) {
errno = ENOMEM ;
goto done ;
}
2022-04-05 17:08:43 +03:00
status = stream_smb_fname (
handle , NULL , full_src , & smb_fname_src_stream , false ) ;
2019-08-10 01:28:56 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto done ;
}
2022-04-05 17:08:43 +03:00
status = stream_smb_fname (
handle , NULL , full_dst , & smb_fname_dst_stream , false ) ;
2019-08-10 01:28:56 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto done ;
}
2021-06-18 07:05:00 +03:00
/*
* We must use handle - > conn - > cwd_fsp as
* srcfsp and dstfsp directory handles here
* as we used the full pathname from the cwd dir
* to calculate the streams directory and filename
* within .
*/
2019-08-10 01:28:56 +03:00
ret = SMB_VFS_NEXT_RENAMEAT ( handle ,
2021-06-18 07:05:00 +03:00
handle - > conn - > cwd_fsp ,
2019-08-10 01:28:56 +03:00
smb_fname_src_stream ,
2021-06-18 07:05:00 +03:00
handle - > conn - > cwd_fsp ,
2019-08-10 01:28:56 +03:00
smb_fname_dst_stream ) ;
done :
TALLOC_FREE ( smb_fname_src_stream ) ;
TALLOC_FREE ( smb_fname_dst_stream ) ;
return ret ;
}
2008-01-20 01:36:34 +03:00
static bool add_one_stream ( TALLOC_CTX * mem_ctx , unsigned int * num_streams ,
struct stream_struct * * streams ,
2012-04-05 08:53:08 +04:00
const char * name , off_t size ,
off_t alloc_size )
2008-01-20 01:36:34 +03:00
{
struct stream_struct * tmp ;
2011-06-07 05:10:15 +04:00
tmp = talloc_realloc ( mem_ctx , * streams , struct stream_struct ,
2008-01-20 01:36:34 +03:00
( * num_streams ) + 1 ) ;
if ( tmp = = NULL ) {
return false ;
}
tmp [ * num_streams ] . name = talloc_strdup ( tmp , name ) ;
if ( tmp [ * num_streams ] . name = = NULL ) {
return false ;
}
tmp [ * num_streams ] . size = size ;
tmp [ * num_streams ] . alloc_size = alloc_size ;
* streams = tmp ;
* num_streams + = 1 ;
return true ;
}
struct streaminfo_state {
TALLOC_CTX * mem_ctx ;
vfs_handle_struct * handle ;
unsigned int num_streams ;
struct stream_struct * streams ;
NTSTATUS status ;
} ;
2020-04-30 12:42:50 +03:00
static bool collect_one_stream ( const struct smb_filename * dirfname ,
2008-01-20 01:36:34 +03:00
const char * dirent ,
void * private_data )
{
2020-04-30 12:42:50 +03:00
const char * dirname = dirfname - > base_name ;
2008-01-20 01:36:34 +03:00
struct streaminfo_state * state =
( struct streaminfo_state * ) private_data ;
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname = NULL ;
char * sname = NULL ;
bool ret ;
2008-01-20 01:36:34 +03:00
2009-06-23 02:26:56 +04:00
sname = talloc_asprintf ( talloc_tos ( ) , " %s/%s " , dirname , dirent ) ;
if ( sname = = NULL ) {
2008-01-20 01:36:34 +03:00
state - > status = NT_STATUS_NO_MEMORY ;
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2008-01-20 01:36:34 +03:00
}
2009-06-23 02:26:56 +04:00
2020-04-30 12:44:15 +03:00
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
sname ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
dirfname - > twrp ,
2020-04-30 12:44:15 +03:00
0 ) ;
2013-04-12 13:36:11 +04:00
if ( smb_fname = = NULL ) {
state - > status = NT_STATUS_NO_MEMORY ;
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2008-01-20 01:36:34 +03:00
}
2009-06-23 02:26:56 +04:00
if ( SMB_VFS_NEXT_STAT ( state - > handle , smb_fname ) = = - 1 ) {
DEBUG ( 10 , ( " Could not stat %s: %s \n " , sname ,
strerror ( errno ) ) ) ;
ret = true ;
goto out ;
}
2008-01-20 01:36:34 +03:00
if ( ! add_one_stream ( state - > mem_ctx ,
& state - > num_streams , & state - > streams ,
2009-06-23 02:26:56 +04:00
dirent , smb_fname - > st . st_ex_size ,
2009-01-27 02:39:40 +03:00
SMB_VFS_GET_ALLOC_SIZE ( state - > handle - > conn , NULL ,
2009-06-23 02:26:56 +04:00
& smb_fname - > st ) ) ) {
2008-01-20 01:36:34 +03:00
state - > status = NT_STATUS_NO_MEMORY ;
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2008-01-20 01:36:34 +03:00
}
2009-06-23 02:26:56 +04:00
ret = true ;
out :
TALLOC_FREE ( sname ) ;
TALLOC_FREE ( smb_fname ) ;
return ret ;
2008-01-20 01:36:34 +03:00
}
2021-04-27 18:51:35 +03:00
static NTSTATUS streams_depot_fstreaminfo ( vfs_handle_struct * handle ,
struct files_struct * fsp ,
TALLOC_CTX * mem_ctx ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
struct smb_filename * smb_fname_base = NULL ;
int ret ;
NTSTATUS status ;
struct streaminfo_state state ;
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
fsp - > fsp_name - > base_name ,
NULL ,
NULL ,
fsp - > fsp_name - > twrp ,
fsp - > fsp_name - > flags ) ;
if ( smb_fname_base = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
ret = SMB_VFS_NEXT_FSTAT ( handle , fsp , & smb_fname_base - > st ) ;
if ( ret = = - 1 ) {
status = map_nt_error_from_unix ( errno ) ;
goto out ;
}
state . streams = * pstreams ;
state . num_streams = * pnum_streams ;
state . mem_ctx = mem_ctx ;
state . handle = handle ;
state . status = NT_STATUS_OK ;
status = walk_streams ( handle ,
smb_fname_base ,
NULL ,
collect_one_stream ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( state . streams ) ;
goto out ;
}
if ( ! NT_STATUS_IS_OK ( state . status ) ) {
TALLOC_FREE ( state . streams ) ;
status = state . status ;
goto out ;
}
* pnum_streams = state . num_streams ;
* pstreams = state . streams ;
status = SMB_VFS_NEXT_FSTREAMINFO ( handle ,
fsp - > base_fsp ? fsp - > base_fsp : fsp ,
mem_ctx ,
pnum_streams ,
pstreams ) ;
out :
TALLOC_FREE ( smb_fname_base ) ;
return status ;
}
2009-08-25 07:57:37 +04:00
static uint32_t streams_depot_fs_capabilities ( struct vfs_handle_struct * handle ,
enum timestamp_set_resolution * p_ts_res )
2008-01-20 01:36:34 +03:00
{
2009-08-25 07:57:37 +04:00
return SMB_VFS_NEXT_FS_CAPABILITIES ( handle , p_ts_res ) | FILE_NAMED_STREAMS ;
2008-01-20 01:36:34 +03:00
}
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers vfs_streams_depot_fns = {
2011-12-04 08:45:04 +04:00
. fs_capabilities_fn = streams_depot_fs_capabilities ,
2020-05-21 00:07:20 +03:00
. openat_fn = streams_depot_openat ,
2011-12-04 08:45:04 +04:00
. stat_fn = streams_depot_stat ,
. lstat_fn = streams_depot_lstat ,
2019-09-12 23:41:10 +03:00
. unlinkat_fn = streams_depot_unlinkat ,
2019-08-10 01:28:56 +03:00
. renameat_fn = streams_depot_renameat ,
2021-04-27 18:51:35 +03:00
. fstreaminfo_fn = streams_depot_fstreaminfo ,
2008-01-20 01:36:34 +03:00
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_streams_depot_init ( TALLOC_CTX * ctx )
2008-01-20 01:36:34 +03:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " streams_depot " ,
2009-07-24 04:28:58 +04:00
& vfs_streams_depot_fns ) ;
2008-01-20 01:36:34 +03:00
}