2008-01-20 01:33:11 +03:00
/*
* Store streams in xattrs
*
* Copyright ( C ) Volker Lendecke , 2008
*
* Partly based on James Peach ' s Darwin module , which is
*
* Copyright ( C ) James Peach 2006 - 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"
2017-05-12 08:58:01 +03:00
# include "lib/util/tevent_unix.h"
2017-05-11 19:05:18 +03:00
# include "librpc/gen_ndr/ioctl.h"
2019-06-18 18:09:29 +03:00
# include "hash_inode.h"
2018-11-05 19:41:42 +03:00
2008-01-20 01:33:11 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
2014-05-20 17:17:01 +04:00
struct streams_xattr_config {
const char * prefix ;
size_t prefix_len ;
bool store_stream_type ;
} ;
2008-01-20 01:33:11 +03:00
struct stream_io {
char * base ;
char * xattr_name ;
2008-12-02 01:25:20 +03:00
void * fsp_name_ptr ;
files_struct * fsp ;
vfs_handle_struct * handle ;
2008-01-20 01:33:11 +03:00
} ;
2021-06-23 03:03:20 +03:00
static ssize_t get_xattr_size_fsp ( struct files_struct * fsp ,
const char * xattr_name )
2008-01-20 01:33:11 +03:00
{
NTSTATUS status ;
struct ea_struct ea ;
ssize_t result ;
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( talloc_tos ( ) ,
fsp ,
xattr_name ,
& ea ) ;
2008-01-20 01:33:11 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return - 1 ;
}
result = ea . value . length - 1 ;
TALLOC_FREE ( ea . value . data ) ;
return result ;
}
2009-06-16 23:01:13 +04:00
/**
* Given a stream name , populate xattr_name with the xattr name to use for
* accessing the stream .
*/
2014-05-20 17:17:01 +04:00
static NTSTATUS streams_xattr_get_name ( vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
2009-06-16 23:01:13 +04:00
const char * stream_name ,
char * * xattr_name )
{
2022-09-16 19:54:05 +03:00
size_t stream_name_len = strlen ( stream_name ) ;
2009-06-16 23:01:13 +04:00
char * stype ;
2014-05-20 17:17:01 +04:00
struct streams_xattr_config * config ;
SMB_VFS_HANDLE_GET_DATA ( handle , config , struct streams_xattr_config ,
return NT_STATUS_UNSUCCESSFUL ) ;
2009-06-16 23:01:13 +04:00
2022-09-16 19:54:05 +03:00
SMB_ASSERT ( stream_name [ 0 ] = = ' : ' ) ;
stream_name + = 1 ;
2015-08-24 18:45:14 +03:00
2015-05-09 16:02:03 +03:00
/*
* With vfs_fruit option " fruit:encoding = native " we ' re
* already converting stream names that contain illegal NTFS
* characters from their on - the - wire Unicode Private Range
* encoding to their native ASCII representation .
*
* As as result the name of xattrs storing the streams ( via
* vfs_streams_xattr ) may contain a colon , so we have to use
* strrchr_m ( ) instead of strchr_m ( ) for matching the stream
* type suffix .
*
* In check_path_syntax ( ) we ' ve already ensured the streamname
* we got from the client is valid .
*/
2022-09-16 19:54:05 +03:00
stype = strrchr_m ( stream_name , ' : ' ) ;
2009-06-16 23:01:13 +04:00
2014-11-21 16:56:08 +03:00
if ( stype ) {
2015-08-24 18:45:14 +03:00
/*
* We only support one stream type : " $DATA "
*/
2014-11-21 16:56:08 +03:00
if ( strcasecmp_m ( stype , " :$DATA " ) ! = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2015-08-24 18:45:14 +03:00
/* Split name and type */
2022-09-16 19:54:05 +03:00
stream_name_len = ( stype - stream_name ) ;
2014-11-21 16:56:08 +03:00
}
2022-09-16 19:54:05 +03:00
* xattr_name = talloc_asprintf ( ctx , " %s%.*s%s " ,
2014-05-20 17:17:01 +04:00
config - > prefix ,
2022-09-16 19:54:05 +03:00
( int ) stream_name_len ,
stream_name ,
2015-08-24 18:45:14 +03:00
config - > store_stream_type ? " :$DATA " : " " ) ;
2009-06-16 23:01:13 +04:00
if ( * xattr_name = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 10 , ( " xattr_name: %s, stream_name: %s \n " , * xattr_name ,
stream_name ) ) ;
return NT_STATUS_OK ;
}
2008-12-02 01:25:20 +03:00
static bool streams_xattr_recheck ( struct stream_io * sio )
{
NTSTATUS status ;
char * xattr_name = NULL ;
if ( sio - > fsp - > fsp_name = = sio - > fsp_name_ptr ) {
return true ;
}
2009-07-11 05:11:32 +04:00
if ( sio - > fsp - > fsp_name - > stream_name = = NULL ) {
2008-12-02 01:25:20 +03:00
/* how can this happen */
errno = EINVAL ;
return false ;
}
2014-05-20 17:17:01 +04:00
status = streams_xattr_get_name ( sio - > handle , talloc_tos ( ) ,
2009-07-11 05:11:32 +04:00
sio - > fsp - > fsp_name - > stream_name ,
2009-07-09 01:08:04 +04:00
& xattr_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-12-02 01:25:20 +03:00
return false ;
}
TALLOC_FREE ( sio - > xattr_name ) ;
TALLOC_FREE ( sio - > base ) ;
sio - > xattr_name = talloc_strdup ( VFS_MEMCTX_FSP_EXTENSION ( sio - > handle , sio - > fsp ) ,
xattr_name ) ;
2018-08-08 15:20:58 +03:00
if ( sio - > xattr_name = = NULL ) {
DBG_DEBUG ( " sio->xattr_name==NULL \n " ) ;
return false ;
}
2009-07-09 01:08:04 +04:00
TALLOC_FREE ( xattr_name ) ;
2018-08-08 15:20:58 +03:00
sio - > base = talloc_strdup ( VFS_MEMCTX_FSP_EXTENSION ( sio - > handle , sio - > fsp ) ,
sio - > fsp - > fsp_name - > base_name ) ;
if ( sio - > base = = NULL ) {
DBG_DEBUG ( " sio->base==NULL \n " ) ;
2008-12-02 01:25:20 +03:00
return false ;
}
2018-08-08 15:20:58 +03:00
sio - > fsp_name_ptr = sio - > fsp - > fsp_name ;
2008-12-02 01:25:20 +03:00
return true ;
}
2008-01-20 01:33:11 +03:00
static int streams_xattr_fstat ( vfs_handle_struct * handle , files_struct * fsp ,
SMB_STRUCT_STAT * sbuf )
{
2009-02-26 00:46:21 +03:00
int ret = - 1 ;
2008-01-20 01:33:11 +03:00
struct stream_io * io = ( struct stream_io * )
VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
2022-02-11 11:37:35 +03:00
if ( io = = NULL | | ! fsp_is_alternate_stream ( fsp ) ) {
2008-01-20 01:33:11 +03:00
return SMB_VFS_NEXT_FSTAT ( handle , fsp , sbuf ) ;
}
2017-09-14 02:23:53 +03:00
DBG_DEBUG ( " streams_xattr_fstat called for %s \n " , fsp_str_dbg ( io - > fsp ) ) ;
2008-12-02 01:25:20 +03:00
if ( ! streams_xattr_recheck ( io ) ) {
return - 1 ;
}
2021-06-22 23:47:46 +03:00
ret = SMB_VFS_NEXT_FSTAT ( handle , fsp - > base_fsp , sbuf ) ;
2009-02-26 00:46:21 +03:00
if ( ret = = - 1 ) {
2008-01-20 01:33:11 +03:00
return - 1 ;
}
2021-06-23 03:03:20 +03:00
sbuf - > st_ex_size = get_xattr_size_fsp ( fsp - > base_fsp ,
io - > xattr_name ) ;
2009-05-14 17:34:42 +04:00
if ( sbuf - > st_ex_size = = - 1 ) {
2017-05-11 08:59:20 +03:00
SET_STAT_INVALID ( * sbuf ) ;
2008-01-20 01:33:11 +03:00
return - 1 ;
}
2009-05-14 17:34:42 +04:00
DEBUG ( 10 , ( " sbuf->st_ex_size = %d \n " , ( int ) sbuf - > st_ex_size ) ) ;
2008-01-20 15:55:27 +03:00
2019-06-18 18:09:29 +03:00
sbuf - > st_ex_ino = hash_inode ( sbuf , io - > xattr_name ) ;
2009-05-14 17:34:42 +04:00
sbuf - > st_ex_mode & = ~ S_IFMT ;
2018-04-11 18:41:00 +03:00
sbuf - > st_ex_mode & = ~ S_IFDIR ;
2009-05-14 17:34:42 +04:00
sbuf - > st_ex_mode | = S_IFREG ;
2010-06-09 17:24:26 +04:00
sbuf - > st_ex_blocks = sbuf - > st_ex_size / STAT_ST_BLOCKSIZE + 1 ;
2008-01-20 01:33:11 +03:00
return 0 ;
}
2009-06-23 02:26:56 +04:00
static int streams_xattr_stat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
2008-01-20 01:33:11 +03:00
{
NTSTATUS status ;
int result = - 1 ;
2009-06-23 02:26:56 +04:00
char * xattr_name = NULL ;
2021-06-23 00:19:13 +03:00
char * tmp_stream_name = NULL ;
2021-07-13 21:41:05 +03:00
struct smb_filename * pathref = NULL ;
2021-06-23 02:49:11 +03:00
struct files_struct * fsp = smb_fname - > fsp ;
2008-01-20 01:33:11 +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:33:11 +03:00
}
2009-10-17 05:13:06 +04:00
/* Note if lp_posix_paths() is true, we can never
2019-09-26 20:31:51 +03:00
* get here as is_named_stream ( ) is
2009-10-17 05:13:06 +04:00
* always false . So we never need worry about
* not following links here . */
2009-06-23 02:26:56 +04:00
/* Populate the stat struct with info from the base file. */
2021-06-23 00:19:13 +03:00
tmp_stream_name = smb_fname - > stream_name ;
smb_fname - > stream_name = NULL ;
result = SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
smb_fname - > stream_name = tmp_stream_name ;
if ( result = = - 1 ) {
2009-06-23 02:26:56 +04:00
return - 1 ;
2008-01-20 01:33:11 +03:00
}
2009-06-23 02:26:56 +04:00
/* Derive the xattr name to lookup. */
2014-05-20 17:17:01 +04:00
status = streams_xattr_get_name ( handle , talloc_tos ( ) ,
smb_fname - > stream_name , & xattr_name ) ;
2009-06-23 02:26:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
2008-01-20 01:33:11 +03:00
}
2009-06-23 02:26:56 +04:00
/* Augment the base file's stat information before returning. */
2021-06-23 02:49:11 +03:00
if ( fsp = = NULL ) {
2021-07-13 21:41:05 +03:00
status = synthetic_pathref ( talloc_tos ( ) ,
handle - > conn - > cwd_fsp ,
smb_fname - > base_name ,
NULL ,
NULL ,
smb_fname - > twrp ,
smb_fname - > flags ,
& pathref ) ;
2021-06-23 02:49:11 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( xattr_name ) ;
SET_STAT_INVALID ( smb_fname - > st ) ;
errno = ENOENT ;
return - 1 ;
}
2021-07-13 21:41:05 +03:00
fsp = pathref - > fsp ;
} else {
fsp = fsp - > base_fsp ;
2021-06-23 00:24:15 +03:00
}
2021-06-23 02:49:11 +03:00
2021-07-13 21:41:05 +03:00
smb_fname - > st . st_ex_size = get_xattr_size_fsp ( fsp ,
2021-06-23 03:03:20 +03:00
xattr_name ) ;
2009-06-23 02:26:56 +04:00
if ( smb_fname - > st . st_ex_size = = - 1 ) {
2021-06-23 02:49:11 +03:00
TALLOC_FREE ( xattr_name ) ;
2021-07-13 21:41:05 +03:00
TALLOC_FREE ( pathref ) ;
2017-05-11 08:59:20 +03:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2008-01-20 01:33:11 +03:00
errno = ENOENT ;
2021-06-23 02:49:11 +03:00
return - 1 ;
2008-01-20 01:33:11 +03:00
}
2019-06-18 18:09:29 +03:00
smb_fname - > st . st_ex_ino = hash_inode ( & smb_fname - > st , xattr_name ) ;
2009-06-23 02:26:56 +04:00
smb_fname - > st . st_ex_mode & = ~ S_IFMT ;
smb_fname - > st . st_ex_mode | = S_IFREG ;
smb_fname - > st . st_ex_blocks =
2010-06-09 17:24:26 +04:00
smb_fname - > st . st_ex_size / STAT_ST_BLOCKSIZE + 1 ;
2008-01-20 01:33:11 +03:00
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( xattr_name ) ;
2021-07-13 21:41:05 +03:00
TALLOC_FREE ( pathref ) ;
2021-06-23 02:49:11 +03:00
return 0 ;
2008-01-20 01:33:11 +03:00
}
2009-06-23 02:26:56 +04:00
static int streams_xattr_lstat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
2008-01-20 01:33:11 +03:00
{
2021-06-23 00:16:04 +03:00
if ( is_named_stream ( smb_fname ) ) {
/*
* There can never be EA ' s on a symlink .
* Windows will never see a symlink , and
* in SMB_FILENAME_POSIX_PATH mode we don ' t
* allow EA ' s on a symlink .
*/
2017-05-11 08:59:20 +03:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2008-01-20 01:33:11 +03:00
errno = ENOENT ;
2021-06-23 00:16:04 +03:00
return - 1 ;
2008-01-20 01:33:11 +03:00
}
2021-06-23 00:16:04 +03:00
return SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
2008-01-20 01:33:11 +03:00
}
2020-05-20 23:18:54 +03:00
static int streams_xattr_openat ( struct vfs_handle_struct * handle ,
const struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
files_struct * fsp ,
2022-06-03 16:53:29 +03:00
const struct vfs_open_how * how )
2020-05-20 23:18:54 +03:00
{
NTSTATUS status ;
struct streams_xattr_config * config = NULL ;
struct stream_io * sio = NULL ;
struct ea_struct ea ;
char * xattr_name = NULL ;
int fakefd = - 1 ;
bool set_empty_xattr = false ;
int ret ;
SMB_VFS_HANDLE_GET_DATA ( handle , config , struct streams_xattr_config ,
return - 1 ) ;
2021-12-21 14:54:56 +03:00
DBG_DEBUG ( " called for %s with flags 0x%x \n " ,
smb_fname_str_dbg ( smb_fname ) ,
2022-06-03 16:53:29 +03:00
how - > flags ) ;
2020-05-20 23:18:54 +03:00
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-20 23:18:54 +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 18:40:35 +03:00
2020-05-20 23:18:54 +03:00
status = streams_xattr_get_name ( handle , talloc_tos ( ) ,
smb_fname - > stream_name , & xattr_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto fail ;
}
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( talloc_tos ( ) ,
fsp - > base_fsp ,
xattr_name ,
& ea ) ;
2020-05-20 23:18:54 +03:00
2021-06-23 03:53:29 +03:00
DBG_DEBUG ( " get_ea_value_fsp returned %s \n " , nt_errstr ( status ) ) ;
2020-05-20 23:18:54 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
/*
* The base file is not there . This is an error even if
* we got O_CREAT , the higher levels should have created
* the base file for us .
*/
DBG_DEBUG ( " streams_xattr_open: base file %s not around, "
" returning ENOENT \n " , smb_fname - > base_name ) ;
errno = ENOENT ;
goto fail ;
}
2022-06-03 16:53:29 +03:00
if ( ! ( how - > flags & O_CREAT ) ) {
2020-05-20 23:18:54 +03:00
errno = ENOATTR ;
goto fail ;
}
set_empty_xattr = true ;
}
2022-06-03 16:53:29 +03:00
if ( how - > flags & O_TRUNC ) {
2020-05-20 23:18:54 +03:00
set_empty_xattr = true ;
}
if ( set_empty_xattr ) {
/*
* The attribute does not exist or needs to be truncated
*/
/*
* Darn , xattrs need at least 1 byte
*/
char null = ' \0 ' ;
DEBUG ( 10 , ( " creating or truncating attribute %s on file %s \n " ,
xattr_name , smb_fname - > base_name ) ) ;
2021-06-23 03:23:32 +03:00
ret = SMB_VFS_FSETXATTR ( fsp - > base_fsp ,
2020-05-20 23:18:54 +03:00
xattr_name ,
& null , sizeof ( null ) ,
2022-06-03 16:53:29 +03:00
how - > flags & O_EXCL ? XATTR_CREATE : 0 ) ;
2020-05-20 23:18:54 +03:00
if ( ret ! = 0 ) {
goto fail ;
}
}
2020-07-23 08:32:11 +03:00
fakefd = vfs_fake_fd ( ) ;
2020-05-20 23:18:54 +03:00
sio = VFS_ADD_FSP_EXTENSION ( handle , fsp , struct stream_io , NULL ) ;
if ( sio = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
sio - > xattr_name = talloc_strdup ( VFS_MEMCTX_FSP_EXTENSION ( handle , fsp ) ,
xattr_name ) ;
if ( sio - > xattr_name = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
/*
* so - > base needs to be a copy of fsp - > fsp_name - > base_name ,
* making it identical to streams_xattr_recheck ( ) . If the
* open is changing directories , fsp - > fsp_name - > base_name
* will be the full path from the share root , whilst
* smb_fname will be relative to the $ cwd .
*/
sio - > base = talloc_strdup ( VFS_MEMCTX_FSP_EXTENSION ( handle , fsp ) ,
fsp - > fsp_name - > base_name ) ;
if ( sio - > base = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
sio - > fsp_name_ptr = fsp - > fsp_name ;
sio - > handle = handle ;
sio - > fsp = fsp ;
return fakefd ;
fail :
if ( fakefd > = 0 ) {
2020-12-18 16:36:00 +03:00
vfs_fake_fd_close ( fakefd ) ;
2020-05-20 23:18:54 +03:00
fakefd = - 1 ;
}
return - 1 ;
}
2018-12-18 19:20:29 +03:00
static int streams_xattr_close ( vfs_handle_struct * handle ,
files_struct * fsp )
{
int ret ;
int fd ;
2020-10-03 22:24:29 +03:00
fd = fsp_get_pathref_fd ( fsp ) ;
2018-12-18 19:20:29 +03:00
DBG_DEBUG ( " streams_xattr_close called [%s] fd [%d] \n " ,
smb_fname_str_dbg ( fsp - > fsp_name ) , fd ) ;
2022-02-11 11:59:16 +03:00
if ( ! fsp_is_alternate_stream ( fsp ) ) {
2018-12-18 19:20:29 +03:00
return SMB_VFS_NEXT_CLOSE ( handle , fsp ) ;
}
2020-12-18 16:36:00 +03:00
ret = vfs_fake_fd_close ( fd ) ;
2020-09-26 22:46:51 +03:00
fsp_set_fd ( fsp , - 1 ) ;
2018-12-18 19:20:29 +03:00
return ret ;
}
2022-02-11 12:20:54 +03:00
static int streams_xattr_unlinkat ( vfs_handle_struct * handle ,
2019-09-18 05:08:26 +03:00
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
2008-01-20 01:33:11 +03:00
{
NTSTATUS status ;
int ret = - 1 ;
2014-11-21 16:54:17 +03:00
char * xattr_name = NULL ;
2022-06-18 03:51:35 +03:00
struct smb_filename * pathref = NULL ;
struct files_struct * fsp = smb_fname - > fsp ;
2008-01-20 01:33:11 +03:00
2019-09-26 20:31:51 +03:00
if ( ! is_named_stream ( smb_fname ) ) {
2019-09-18 05:10:24 +03:00
return SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2008-01-20 01:33:11 +03:00
}
2022-02-11 12:20:54 +03:00
/* A stream can never be rmdir'ed */
SMB_ASSERT ( ( flags & AT_REMOVEDIR ) = = 0 ) ;
2014-05-20 17:17:01 +04:00
status = streams_xattr_get_name ( handle , talloc_tos ( ) ,
smb_fname - > stream_name , & xattr_name ) ;
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:33:11 +03:00
goto fail ;
}
2022-06-18 03:51:35 +03:00
if ( fsp = = NULL ) {
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 ) ) {
errno = ENOENT ;
goto fail ;
}
fsp = pathref - > fsp ;
} else {
SMB_ASSERT ( fsp_is_alternate_stream ( smb_fname - > fsp ) ) ;
fsp = fsp - > base_fsp ;
}
2021-01-20 17:19:31 +03:00
2022-06-18 03:51:35 +03:00
ret = SMB_VFS_FREMOVEXATTR ( fsp , xattr_name ) ;
2008-01-20 01:33:11 +03:00
if ( ( ret = = - 1 ) & & ( errno = = ENOATTR ) ) {
errno = ENOENT ;
goto fail ;
}
ret = 0 ;
fail :
2009-07-02 20:27:44 +04:00
TALLOC_FREE ( xattr_name ) ;
2022-06-18 03:51:35 +03:00
TALLOC_FREE ( pathref ) ;
2008-01-20 01:33:11 +03:00
return ret ;
}
2019-08-10 01:31:03 +03:00
static int streams_xattr_renameat ( vfs_handle_struct * handle ,
files_struct * srcfsp ,
const struct smb_filename * smb_fname_src ,
files_struct * dstfsp ,
2024-08-06 14:21:34 +03:00
const struct smb_filename * smb_fname_dst ,
const struct vfs_rename_how * how )
2019-08-10 01:31:03 +03:00
{
NTSTATUS status ;
int ret = - 1 ;
char * src_xattr_name = NULL ;
char * dst_xattr_name = NULL ;
bool src_is_stream , dst_is_stream ;
ssize_t oret ;
ssize_t nret ;
struct ea_struct ea ;
2021-06-18 07:36:33 +03:00
struct smb_filename * pathref_src = NULL ;
struct smb_filename * pathref_dst = NULL ;
struct smb_filename * full_src = NULL ;
struct smb_filename * full_dst = NULL ;
2019-08-10 01:31:03 +03:00
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 ,
2024-08-06 14:21:34 +03:00
smb_fname_dst ,
how ) ;
}
if ( how - > flags ! = 0 ) {
errno = EINVAL ;
goto done ;
2019-08-10 01:31:03 +03:00
}
/* 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 ;
}
/* Don't rename if the streams are identical. */
if ( strcasecmp_m ( smb_fname_src - > stream_name ,
smb_fname_dst - > stream_name ) = = 0 ) {
goto done ;
}
/* Get the xattr names. */
status = streams_xattr_get_name ( handle , talloc_tos ( ) ,
smb_fname_src - > stream_name ,
& src_xattr_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto fail ;
}
status = streams_xattr_get_name ( handle , talloc_tos ( ) ,
smb_fname_dst - > stream_name ,
& dst_xattr_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto fail ;
}
2021-06-18 07:36:33 +03:00
full_src = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
srcfsp ,
smb_fname_src ) ;
if ( full_src = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
full_dst = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dstfsp ,
smb_fname_dst ) ;
if ( full_dst = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
/* Get a pathref for full_src (base file, no stream name). */
status = synthetic_pathref ( talloc_tos ( ) ,
handle - > conn - > cwd_fsp ,
full_src - > base_name ,
NULL ,
NULL ,
full_src - > twrp ,
full_src - > flags ,
& pathref_src ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = ENOENT ;
goto fail ;
}
/* Read the old stream from the base file fsp. */
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( talloc_tos ( ) ,
pathref_src - > fsp ,
src_xattr_name ,
& ea ) ;
2019-08-10 01:31:03 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-02-18 23:18:46 +03:00
errno = map_errno_from_nt_status ( status ) ;
2019-08-10 01:31:03 +03:00
goto fail ;
}
2021-06-18 07:36:33 +03:00
/* Get a pathref for full_dst (base file, no stream name). */
status = synthetic_pathref ( talloc_tos ( ) ,
2021-02-18 23:18:46 +03:00
handle - > conn - > cwd_fsp ,
2021-06-18 07:36:33 +03:00
full_dst - > base_name ,
2021-02-18 23:18:46 +03:00
NULL ,
NULL ,
2021-06-18 07:36:33 +03:00
full_dst - > twrp ,
full_dst - > flags ,
& pathref_dst ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = ENOENT ;
goto fail ;
2021-02-18 23:18:46 +03:00
}
2021-06-18 07:36:33 +03:00
/* (Over)write the new stream on the base file fsp. */
2021-02-18 23:18:46 +03:00
nret = SMB_VFS_FSETXATTR (
2021-06-18 07:36:33 +03:00
pathref_dst - > fsp ,
dst_xattr_name ,
ea . value . data ,
ea . value . length ,
2021-02-18 23:18:46 +03:00
0 ) ;
2019-08-10 01:31:03 +03:00
if ( nret < 0 ) {
if ( errno = = ENOATTR ) {
errno = ENOENT ;
}
goto fail ;
}
2021-03-13 01:36:49 +03:00
/*
2021-06-18 07:36:33 +03:00
* Remove the old stream from the base file fsp .
2021-03-13 01:36:49 +03:00
*/
2021-06-18 07:36:33 +03:00
oret = SMB_VFS_FREMOVEXATTR ( pathref_src - > fsp ,
src_xattr_name ) ;
2019-08-10 01:31:03 +03:00
if ( oret < 0 ) {
if ( errno = = ENOATTR ) {
errno = ENOENT ;
}
goto fail ;
}
done :
errno = 0 ;
ret = 0 ;
fail :
2021-06-18 07:36:33 +03:00
TALLOC_FREE ( pathref_src ) ;
TALLOC_FREE ( pathref_dst ) ;
TALLOC_FREE ( full_src ) ;
TALLOC_FREE ( full_dst ) ;
2019-08-10 01:31:03 +03:00
TALLOC_FREE ( src_xattr_name ) ;
TALLOC_FREE ( dst_xattr_name ) ;
return ret ;
}
2016-03-12 02:11:20 +03:00
static NTSTATUS walk_xattr_streams ( vfs_handle_struct * handle ,
files_struct * fsp ,
const struct smb_filename * smb_fname ,
bool ( * fn ) ( struct ea_struct * ea ,
void * private_data ) ,
void * private_data )
2008-01-20 01:33:11 +03:00
{
NTSTATUS status ;
char * * names ;
size_t i , num_names ;
2014-05-20 17:17:01 +04:00
struct streams_xattr_config * config ;
SMB_VFS_HANDLE_GET_DATA ( handle , config , struct streams_xattr_config ,
return NT_STATUS_UNSUCCESSFUL ) ;
2008-01-20 01:33:11 +03:00
2021-06-23 22:12:30 +03:00
status = get_ea_names_from_fsp ( talloc_tos ( ) ,
2021-01-31 22:18:03 +03:00
smb_fname - > fsp ,
2016-03-12 02:11:20 +03:00
& names ,
& num_names ) ;
2008-01-20 01:33:11 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
for ( i = 0 ; i < num_names ; i + + ) {
struct ea_struct ea ;
2014-11-20 18:33:22 +03:00
/*
* We want to check with samba_private_attr_name ( )
* whether the xattr name is a private one ,
* unfortunately it flags xattrs that begin with the
* default streams prefix as private .
*
* By only calling samba_private_attr_name ( ) in case
* the xattr does NOT begin with the default prefix ,
* we know that if it returns ' true ' it definitely one
* of our internal xattr like " user.DOSATTRIB " .
*/
if ( strncasecmp_m ( names [ i ] , SAMBA_XATTR_DOSSTREAM_PREFIX ,
strlen ( SAMBA_XATTR_DOSSTREAM_PREFIX ) ) ! = 0 ) {
if ( samba_private_attr_name ( names [ i ] ) ) {
continue ;
}
}
2014-05-20 17:17:01 +04:00
if ( strncmp ( names [ i ] , config - > prefix ,
config - > prefix_len ) ! = 0 ) {
continue ;
}
2008-01-20 01:33:11 +03:00
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( names ,
smb_fname - > fsp ,
names [ i ] ,
& ea ) ;
2008-01-20 01:33:11 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Could not get ea %s for file %s: %s \n " ,
2016-03-12 02:11:20 +03:00
names [ i ] ,
smb_fname - > base_name ,
nt_errstr ( status ) ) ) ;
2008-01-20 01:33:11 +03:00
continue ;
}
2014-05-20 17:17:01 +04:00
ea . name = talloc_asprintf (
ea . value . data , " :%s%s " ,
names [ i ] + config - > prefix_len ,
config - > store_stream_type ? " " : " :$DATA " ) ;
2008-01-20 01:33:11 +03:00
if ( ea . name = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
continue ;
}
if ( ! fn ( & ea , private_data ) ) {
TALLOC_FREE ( ea . value . data ) ;
return NT_STATUS_OK ;
}
TALLOC_FREE ( ea . value . data ) ;
}
TALLOC_FREE ( names ) ;
return NT_STATUS_OK ;
}
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:33:11 +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:33:11 +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 ;
} ;
static bool collect_one_stream ( struct ea_struct * ea , void * private_data )
{
struct streaminfo_state * state =
( struct streaminfo_state * ) private_data ;
if ( ! add_one_stream ( state - > mem_ctx ,
& state - > num_streams , & state - > streams ,
ea - > name , ea - > value . length - 1 ,
smb_roundup ( state - > handle - > conn ,
ea - > value . length - 1 ) ) ) {
state - > status = NT_STATUS_NO_MEMORY ;
return false ;
}
return true ;
}
2021-04-27 18:57:57 +03:00
static NTSTATUS streams_xattr_fstreaminfo ( vfs_handle_struct * handle ,
struct files_struct * fsp ,
TALLOC_CTX * mem_ctx ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
NTSTATUS status ;
struct streaminfo_state state ;
state . streams = * pstreams ;
state . num_streams = * pnum_streams ;
state . mem_ctx = mem_ctx ;
state . handle = handle ;
state . status = NT_STATUS_OK ;
status = walk_xattr_streams ( handle ,
fsp ,
fsp - > fsp_name ,
collect_one_stream ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( state . streams ) ;
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . status ) ) {
TALLOC_FREE ( state . streams ) ;
return state . status ;
}
* pnum_streams = state . num_streams ;
* pstreams = state . streams ;
return SMB_VFS_NEXT_FSTREAMINFO ( handle ,
fsp ,
mem_ctx ,
pnum_streams ,
pstreams ) ;
}
2009-08-25 07:57:37 +04:00
static uint32_t streams_xattr_fs_capabilities ( struct vfs_handle_struct * handle ,
enum timestamp_set_resolution * p_ts_res )
2008-01-20 01:33:11 +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:33:11 +03:00
}
2014-05-20 17:17:01 +04:00
static int streams_xattr_connect ( vfs_handle_struct * handle ,
const char * service , const char * user )
{
struct streams_xattr_config * config ;
const char * default_prefix = SAMBA_XATTR_DOSSTREAM_PREFIX ;
const char * prefix ;
2014-12-11 21:06:11 +03:00
int rc ;
rc = SMB_VFS_NEXT_CONNECT ( handle , service , user ) ;
if ( rc ! = 0 ) {
return rc ;
}
2014-05-20 17:17:01 +04:00
config = talloc_zero ( handle - > conn , struct streams_xattr_config ) ;
if ( config = = NULL ) {
DEBUG ( 1 , ( " talloc_zero() failed \n " ) ) ;
errno = ENOMEM ;
return - 1 ;
}
prefix = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" streams_xattr " , " prefix " ,
default_prefix ) ;
config - > prefix = talloc_strdup ( config , prefix ) ;
if ( config - > prefix = = NULL ) {
DEBUG ( 1 , ( " talloc_strdup() failed \n " ) ) ;
errno = ENOMEM ;
return - 1 ;
}
config - > prefix_len = strlen ( config - > prefix ) ;
DEBUG ( 10 , ( " streams_xattr using stream prefix: %s \n " , config - > prefix ) ) ;
config - > store_stream_type = lp_parm_bool ( SNUM ( handle - > conn ) ,
" streams_xattr " ,
" store_stream_type " ,
true ) ;
SMB_VFS_HANDLE_SET_DATA ( handle , config ,
NULL , struct stream_xattr_config ,
return - 1 ) ;
return 0 ;
}
2008-01-20 01:33:11 +03:00
static ssize_t streams_xattr_pwrite ( vfs_handle_struct * handle ,
files_struct * fsp , const void * data ,
2012-04-05 08:53:08 +04:00
size_t n , off_t offset )
2008-01-20 01:33:11 +03:00
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
struct ea_struct ea ;
NTSTATUS status ;
int ret ;
2008-01-20 15:55:27 +03:00
DEBUG ( 10 , ( " streams_xattr_pwrite called for %d bytes \n " , ( int ) n ) ) ;
2008-01-20 01:33:11 +03:00
if ( sio = = NULL ) {
return SMB_VFS_NEXT_PWRITE ( handle , fsp , data , n , offset ) ;
}
2008-12-02 01:25:20 +03:00
if ( ! streams_xattr_recheck ( sio ) ) {
return - 1 ;
}
2021-05-07 13:37:25 +03:00
if ( ( offset + n ) > = lp_smbd_max_xattr_size ( SNUM ( handle - > conn ) ) ) {
/*
* Requested write is beyond what can be read based on
* samba configuration .
* ReFS returns STATUS_FILESYSTEM_LIMITATION , which causes
* entire file to be skipped by File Explorer . VFAT returns
* NT_STATUS_OBJECT_NAME_COLLISION causes user to be prompted
* to skip writing metadata , but copy data .
*/
DBG_ERR ( " Write to xattr [%s] on file [%s] exceeds maximum "
" supported extended attribute size. "
" Depending on filesystem type and operating system "
" (OS) specifics, this value may be increased using "
" the value of the parameter: "
" smbd max xattr size = <bytes>. Consult OS and "
" filesystem manpages prior to increasing this limit. \n " ,
sio - > xattr_name , sio - > base ) ;
errno = EOVERFLOW ;
return - 1 ;
}
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( talloc_tos ( ) ,
fsp - > base_fsp ,
sio - > xattr_name ,
& ea ) ;
2008-01-20 01:33:11 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return - 1 ;
}
if ( ( offset + n ) > ea . value . length - 1 ) {
2015-05-03 06:11:02 +03:00
uint8_t * tmp ;
2008-01-20 01:33:11 +03:00
2015-05-03 06:11:02 +03:00
tmp = talloc_realloc ( talloc_tos ( ) , ea . value . data , uint8_t ,
2008-01-20 01:33:11 +03:00
offset + n + 1 ) ;
if ( tmp = = NULL ) {
TALLOC_FREE ( ea . value . data ) ;
errno = ENOMEM ;
return - 1 ;
}
ea . value . data = tmp ;
ea . value . length = offset + n + 1 ;
ea . value . data [ offset + n ] = 0 ;
}
memcpy ( ea . value . data + offset , data , n ) ;
2021-06-23 03:10:50 +03:00
ret = SMB_VFS_FSETXATTR ( fsp - > base_fsp ,
sio - > xattr_name ,
ea . value . data ,
ea . value . length ,
0 ) ;
2008-01-20 01:33:11 +03:00
TALLOC_FREE ( ea . value . data ) ;
2008-01-20 19:35:25 +03:00
if ( ret = = - 1 ) {
return - 1 ;
}
2008-01-20 01:33:11 +03:00
return n ;
}
static ssize_t streams_xattr_pread ( vfs_handle_struct * handle ,
files_struct * fsp , void * data ,
2012-04-05 08:53:08 +04:00
size_t n , off_t offset )
2008-01-20 01:33:11 +03:00
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
struct ea_struct ea ;
NTSTATUS status ;
2008-11-22 02:42:03 +03:00
size_t length , overlap ;
2008-01-20 01:33:11 +03:00
2009-09-16 05:15:53 +04:00
DEBUG ( 10 , ( " streams_xattr_pread: offset=%d, size=%d \n " ,
( int ) offset , ( int ) n ) ) ;
2008-01-20 01:33:11 +03:00
if ( sio = = NULL ) {
return SMB_VFS_NEXT_PREAD ( handle , fsp , data , n , offset ) ;
}
2008-12-02 01:25:20 +03:00
if ( ! streams_xattr_recheck ( sio ) ) {
return - 1 ;
}
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( talloc_tos ( ) ,
fsp - > base_fsp ,
sio - > xattr_name ,
& ea ) ;
2008-01-20 01:33:11 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return - 1 ;
}
length = ea . value . length - 1 ;
2021-06-23 03:53:29 +03:00
DBG_DEBUG ( " get_ea_value_fsp returned %d bytes \n " ,
( int ) length ) ;
2009-09-16 05:15:53 +04:00
2008-01-20 01:33:11 +03:00
/* Attempt to read past EOF. */
if ( length < = offset ) {
2009-09-16 05:20:49 +04:00
return 0 ;
2008-01-20 01:33:11 +03:00
}
overlap = ( offset + n ) > length ? ( length - offset ) : n ;
memcpy ( data , ea . value . data + offset , overlap ) ;
TALLOC_FREE ( ea . value . data ) ;
return overlap ;
}
2017-05-12 08:58:01 +03:00
struct streams_xattr_pread_state {
ssize_t nread ;
struct vfs_aio_state vfs_aio_state ;
} ;
static void streams_xattr_pread_done ( struct tevent_req * subreq ) ;
static struct tevent_req * streams_xattr_pread_send (
struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct files_struct * fsp ,
void * data ,
size_t n , off_t offset )
{
struct tevent_req * req = NULL ;
struct tevent_req * subreq = NULL ;
struct streams_xattr_pread_state * state = NULL ;
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
req = tevent_req_create ( mem_ctx , & state ,
struct streams_xattr_pread_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( sio = = NULL ) {
subreq = SMB_VFS_NEXT_PREAD_SEND ( state , ev , handle , fsp ,
data , n , offset ) ;
if ( tevent_req_nomem ( req , subreq ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , streams_xattr_pread_done , req ) ;
return req ;
}
state - > nread = SMB_VFS_PREAD ( fsp , data , n , offset ) ;
if ( state - > nread ! = n ) {
if ( state - > nread ! = - 1 ) {
errno = EIO ;
}
tevent_req_error ( req , errno ) ;
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static void streams_xattr_pread_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct streams_xattr_pread_state * state = tevent_req_data (
req , struct streams_xattr_pread_state ) ;
state - > nread = SMB_VFS_PREAD_RECV ( subreq , & state - > vfs_aio_state ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_error ( req , state - > vfs_aio_state . error ) ) {
return ;
}
tevent_req_done ( req ) ;
}
static ssize_t streams_xattr_pread_recv ( struct tevent_req * req ,
struct vfs_aio_state * vfs_aio_state )
{
struct streams_xattr_pread_state * state = tevent_req_data (
req , struct streams_xattr_pread_state ) ;
if ( tevent_req_is_unix_error ( req , & vfs_aio_state - > error ) ) {
return - 1 ;
}
* vfs_aio_state = state - > vfs_aio_state ;
return state - > nread ;
}
struct streams_xattr_pwrite_state {
ssize_t nwritten ;
struct vfs_aio_state vfs_aio_state ;
} ;
static void streams_xattr_pwrite_done ( struct tevent_req * subreq ) ;
static struct tevent_req * streams_xattr_pwrite_send (
struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct files_struct * fsp ,
const void * data ,
size_t n , off_t offset )
{
struct tevent_req * req = NULL ;
struct tevent_req * subreq = NULL ;
struct streams_xattr_pwrite_state * state = NULL ;
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
req = tevent_req_create ( mem_ctx , & state ,
struct streams_xattr_pwrite_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( sio = = NULL ) {
subreq = SMB_VFS_NEXT_PWRITE_SEND ( state , ev , handle , fsp ,
data , n , offset ) ;
if ( tevent_req_nomem ( req , subreq ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , streams_xattr_pwrite_done , req ) ;
return req ;
}
state - > nwritten = SMB_VFS_PWRITE ( fsp , data , n , offset ) ;
if ( state - > nwritten ! = n ) {
if ( state - > nwritten ! = - 1 ) {
errno = EIO ;
}
tevent_req_error ( req , errno ) ;
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static void streams_xattr_pwrite_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct streams_xattr_pwrite_state * state = tevent_req_data (
req , struct streams_xattr_pwrite_state ) ;
state - > nwritten = SMB_VFS_PWRITE_RECV ( subreq , & state - > vfs_aio_state ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_error ( req , state - > vfs_aio_state . error ) ) {
return ;
}
tevent_req_done ( req ) ;
}
static ssize_t streams_xattr_pwrite_recv ( struct tevent_req * req ,
struct vfs_aio_state * vfs_aio_state )
{
struct streams_xattr_pwrite_state * state = tevent_req_data (
req , struct streams_xattr_pwrite_state ) ;
if ( tevent_req_is_unix_error ( req , & vfs_aio_state - > error ) ) {
return - 1 ;
}
* vfs_aio_state = state - > vfs_aio_state ;
return state - > nwritten ;
}
2008-11-22 02:42:03 +03:00
static int streams_xattr_ftruncate ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
2012-04-05 08:53:08 +04:00
off_t offset )
2008-11-22 02:42:03 +03:00
{
int ret ;
2015-05-03 06:11:02 +03:00
uint8_t * tmp ;
2008-11-22 02:42:03 +03:00
struct ea_struct ea ;
NTSTATUS status ;
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
DEBUG ( 10 , ( " streams_xattr_ftruncate called for file %s offset %.0f \n " ,
2009-07-11 05:11:32 +04:00
fsp_str_dbg ( fsp ) , ( double ) offset ) ) ;
2008-11-22 02:42:03 +03:00
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FTRUNCATE ( handle , fsp , offset ) ;
}
2008-12-02 01:25:20 +03:00
if ( ! streams_xattr_recheck ( sio ) ) {
return - 1 ;
}
2021-06-23 03:53:29 +03:00
status = get_ea_value_fsp ( talloc_tos ( ) ,
fsp - > base_fsp ,
sio - > xattr_name ,
& ea ) ;
2008-11-22 02:42:03 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return - 1 ;
}
2015-05-03 06:11:02 +03:00
tmp = talloc_realloc ( talloc_tos ( ) , ea . value . data , uint8_t ,
2008-11-22 02:42:03 +03:00
offset + 1 ) ;
if ( tmp = = NULL ) {
TALLOC_FREE ( ea . value . data ) ;
errno = ENOMEM ;
return - 1 ;
}
/* Did we expand ? */
if ( ea . value . length < offset + 1 ) {
memset ( & tmp [ ea . value . length ] , ' \0 ' ,
offset + 1 - ea . value . length ) ;
}
ea . value . data = tmp ;
ea . value . length = offset + 1 ;
ea . value . data [ offset ] = 0 ;
2021-06-23 03:36:28 +03:00
ret = SMB_VFS_FSETXATTR ( fsp - > base_fsp ,
sio - > xattr_name ,
ea . value . data ,
ea . value . length ,
0 ) ;
2021-02-18 21:56:56 +03:00
2008-11-22 02:42:03 +03:00
TALLOC_FREE ( ea . value . data ) ;
if ( ret = = - 1 ) {
return - 1 ;
}
return 0 ;
}
2010-12-18 10:08:01 +03:00
static int streams_xattr_fallocate ( struct vfs_handle_struct * handle ,
2010-12-03 03:25:59 +03:00
struct files_struct * fsp ,
2015-02-09 20:21:59 +03:00
uint32_t mode ,
2012-04-05 08:53:08 +04:00
off_t offset ,
off_t len )
2010-12-03 03:25:59 +03:00
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
2010-12-18 10:08:01 +03:00
DEBUG ( 10 , ( " streams_xattr_fallocate called for file %s offset %.0f "
2010-12-03 03:25:59 +03:00
" len = %.0f \n " ,
fsp_str_dbg ( fsp ) , ( double ) offset , ( double ) len ) ) ;
if ( sio = = NULL ) {
2010-12-18 10:08:01 +03:00
return SMB_VFS_NEXT_FALLOCATE ( handle , fsp , mode , offset , len ) ;
2010-12-03 03:25:59 +03:00
}
if ( ! streams_xattr_recheck ( sio ) ) {
2014-12-06 02:37:11 +03:00
return - 1 ;
2010-12-03 03:25:59 +03:00
}
/* Let the pwrite code path handle it. */
2014-12-06 02:37:11 +03:00
errno = ENOSYS ;
return - 1 ;
2010-12-03 03:25:59 +03:00
}
2017-05-11 19:05:18 +03:00
static int streams_xattr_fchown ( vfs_handle_struct * handle , files_struct * fsp ,
uid_t uid , gid_t gid )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FCHOWN ( handle , fsp , uid , gid ) ;
}
return 0 ;
}
static int streams_xattr_fchmod ( vfs_handle_struct * handle ,
files_struct * fsp ,
mode_t mode )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FCHMOD ( handle , fsp , mode ) ;
}
return 0 ;
}
static ssize_t streams_xattr_fgetxattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
const char * name ,
void * value ,
size_t size )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FGETXATTR ( handle , fsp , name , value , size ) ;
}
errno = ENOTSUP ;
return - 1 ;
}
static ssize_t streams_xattr_flistxattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
char * list ,
size_t size )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FLISTXATTR ( handle , fsp , list , size ) ;
}
errno = ENOTSUP ;
return - 1 ;
}
static int streams_xattr_fremovexattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
const char * name )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FREMOVEXATTR ( handle , fsp , name ) ;
}
errno = ENOTSUP ;
return - 1 ;
}
static int streams_xattr_fsetxattr ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
const char * name ,
const void * value ,
size_t size ,
int flags )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FSETXATTR ( handle , fsp , name , value ,
size , flags ) ;
}
errno = ENOTSUP ;
return - 1 ;
}
struct streams_xattr_fsync_state {
int ret ;
struct vfs_aio_state vfs_aio_state ;
} ;
static void streams_xattr_fsync_done ( struct tevent_req * subreq ) ;
static struct tevent_req * streams_xattr_fsync_send (
struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct files_struct * fsp )
{
struct tevent_req * req = NULL ;
struct tevent_req * subreq = NULL ;
struct streams_xattr_fsync_state * state = NULL ;
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
req = tevent_req_create ( mem_ctx , & state ,
struct streams_xattr_fsync_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( sio = = NULL ) {
subreq = SMB_VFS_NEXT_FSYNC_SEND ( state , ev , handle , fsp ) ;
if ( tevent_req_nomem ( req , subreq ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , streams_xattr_fsync_done , req ) ;
return req ;
}
/*
* There ' s no pathname based sync variant and we don ' t have access to
* the basefile handle , so we can ' t do anything here .
*/
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static void streams_xattr_fsync_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct streams_xattr_fsync_state * state = tevent_req_data (
req , struct streams_xattr_fsync_state ) ;
state - > ret = SMB_VFS_FSYNC_RECV ( subreq , & state - > vfs_aio_state ) ;
TALLOC_FREE ( subreq ) ;
if ( state - > ret ! = 0 ) {
tevent_req_error ( req , errno ) ;
return ;
}
tevent_req_done ( req ) ;
}
static int streams_xattr_fsync_recv ( struct tevent_req * req ,
struct vfs_aio_state * vfs_aio_state )
{
struct streams_xattr_fsync_state * state = tevent_req_data (
req , struct streams_xattr_fsync_state ) ;
if ( tevent_req_is_unix_error ( req , & vfs_aio_state - > error ) ) {
return - 1 ;
}
* vfs_aio_state = state - > vfs_aio_state ;
return state - > ret ;
}
static bool streams_xattr_lock ( vfs_handle_struct * handle ,
files_struct * fsp ,
int op ,
off_t offset ,
off_t count ,
int type )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_LOCK ( handle , fsp , op , offset , count , type ) ;
}
return true ;
}
static bool streams_xattr_getlock ( vfs_handle_struct * handle ,
files_struct * fsp ,
off_t * poffset ,
off_t * pcount ,
int * ptype ,
pid_t * ppid )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_GETLOCK ( handle , fsp , poffset ,
pcount , ptype , ppid ) ;
}
errno = ENOTSUP ;
return false ;
}
2021-09-21 01:25:21 +03:00
static int streams_xattr_filesystem_sharemode ( vfs_handle_struct * handle ,
files_struct * fsp ,
uint32_t share_access ,
uint32_t access_mask )
2017-05-11 19:05:18 +03:00
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
2021-09-21 00:51:02 +03:00
return SMB_VFS_NEXT_FILESYSTEM_SHAREMODE ( handle ,
fsp ,
share_access ,
access_mask ) ;
2017-05-11 19:05:18 +03:00
}
return 0 ;
}
static int streams_xattr_linux_setlease ( vfs_handle_struct * handle ,
files_struct * fsp ,
int leasetype )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_LINUX_SETLEASE ( handle , fsp , leasetype ) ;
}
return 0 ;
}
static bool streams_xattr_strict_lock_check ( struct vfs_handle_struct * handle ,
files_struct * fsp ,
struct lock_struct * plock )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_STRICT_LOCK_CHECK ( handle , fsp , plock ) ;
}
return true ;
}
2022-07-29 08:07:25 +03:00
static int streams_xattr_fcntl ( vfs_handle_struct * handle ,
files_struct * fsp ,
int cmd ,
va_list cmd_arg )
{
va_list dup_cmd_arg ;
void * arg ;
int ret ;
if ( fsp_is_alternate_stream ( fsp ) ) {
switch ( cmd ) {
case F_GETFL :
case F_SETFL :
break ;
default :
DBG_ERR ( " Unsupported fcntl() cmd [%d] on [%s] \n " ,
cmd , fsp_str_dbg ( fsp ) ) ;
errno = EINVAL ;
return - 1 ;
}
}
va_copy ( dup_cmd_arg , cmd_arg ) ;
arg = va_arg ( dup_cmd_arg , void * ) ;
ret = SMB_VFS_NEXT_FCNTL ( handle , fsp , cmd , arg ) ;
va_end ( dup_cmd_arg ) ;
return ret ;
}
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers vfs_streams_xattr_fns = {
2011-12-04 08:45:04 +04:00
. fs_capabilities_fn = streams_xattr_fs_capabilities ,
2014-05-20 17:17:01 +04:00
. connect_fn = streams_xattr_connect ,
2020-05-20 23:18:54 +03:00
. openat_fn = streams_xattr_openat ,
2018-12-18 19:20:29 +03:00
. close_fn = streams_xattr_close ,
2011-12-04 08:45:04 +04:00
. stat_fn = streams_xattr_stat ,
. fstat_fn = streams_xattr_fstat ,
. lstat_fn = streams_xattr_lstat ,
. pread_fn = streams_xattr_pread ,
. pwrite_fn = streams_xattr_pwrite ,
2017-05-12 08:58:01 +03:00
. pread_send_fn = streams_xattr_pread_send ,
. pread_recv_fn = streams_xattr_pread_recv ,
. pwrite_send_fn = streams_xattr_pwrite_send ,
. pwrite_recv_fn = streams_xattr_pwrite_recv ,
2019-09-13 00:00:24 +03:00
. unlinkat_fn = streams_xattr_unlinkat ,
2019-08-10 01:31:03 +03:00
. renameat_fn = streams_xattr_renameat ,
2011-12-04 08:45:04 +04:00
. ftruncate_fn = streams_xattr_ftruncate ,
. fallocate_fn = streams_xattr_fallocate ,
2021-04-27 18:57:57 +03:00
. fstreaminfo_fn = streams_xattr_fstreaminfo ,
2017-05-11 19:05:18 +03:00
. fsync_send_fn = streams_xattr_fsync_send ,
. fsync_recv_fn = streams_xattr_fsync_recv ,
. lock_fn = streams_xattr_lock ,
. getlock_fn = streams_xattr_getlock ,
2021-09-21 01:25:21 +03:00
. filesystem_sharemode_fn = streams_xattr_filesystem_sharemode ,
2017-05-11 19:05:18 +03:00
. linux_setlease_fn = streams_xattr_linux_setlease ,
. strict_lock_check_fn = streams_xattr_strict_lock_check ,
2022-07-29 08:07:25 +03:00
. fcntl_fn = streams_xattr_fcntl ,
2017-05-11 19:05:18 +03:00
. fchown_fn = streams_xattr_fchown ,
. fchmod_fn = streams_xattr_fchmod ,
. fgetxattr_fn = streams_xattr_fgetxattr ,
. flistxattr_fn = streams_xattr_flistxattr ,
. fremovexattr_fn = streams_xattr_fremovexattr ,
. fsetxattr_fn = streams_xattr_fsetxattr ,
2008-01-20 01:33:11 +03:00
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_streams_xattr_init ( TALLOC_CTX * ctx )
2008-01-20 01:33:11 +03:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " streams_xattr " ,
2009-07-24 04:28:58 +04:00
& vfs_streams_xattr_fns ) ;
2008-01-20 01:33:11 +03:00
}