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
} ;
2008-11-22 03:02:31 +03:00
static ssize_t get_xattr_size ( connection_struct * conn ,
2017-05-26 02:42:04 +03:00
const struct smb_filename * smb_fname ,
2008-11-22 03:02:31 +03:00
const char * xattr_name )
2008-01-20 01:33:11 +03:00
{
NTSTATUS status ;
struct ea_struct ea ;
ssize_t result ;
2017-05-11 18:36:15 +03:00
status = get_ea_value ( talloc_tos ( ) , conn , NULL , smb_fname ,
2008-01-20 01:33:11 +03:00
xattr_name , & ea ) ;
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 )
{
2015-08-24 18:45:14 +03:00
char * sname ;
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
2015-08-24 18:45:14 +03:00
sname = talloc_strdup ( ctx , stream_name + 1 ) ;
if ( sname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
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 .
*/
2015-08-24 18:45:14 +03:00
stype = strrchr_m ( sname , ' : ' ) ;
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 ) {
2015-08-24 18:45:14 +03:00
talloc_free ( sname ) ;
2014-11-21 16:56:08 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
2015-08-24 18:45:14 +03:00
/* Split name and type */
stype [ 0 ] = ' \0 ' ;
2014-11-21 16:56:08 +03:00
}
2015-08-24 18:45:14 +03:00
* xattr_name = talloc_asprintf ( ctx , " %s%s%s " ,
2014-05-20 17:17:01 +04:00
config - > prefix ,
2015-08-24 18:45:14 +03:00
sname ,
config - > store_stream_type ? " :$DATA " : " " ) ;
2009-06-16 23:01:13 +04:00
if ( * xattr_name = = NULL ) {
2015-08-24 18:45:14 +03:00
talloc_free ( sname ) ;
2009-06-16 23:01:13 +04:00
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 10 , ( " xattr_name: %s, stream_name: %s \n " , * xattr_name ,
stream_name ) ) ;
2015-08-24 18:45:14 +03:00
talloc_free ( sname ) ;
2009-06-16 23:01:13 +04:00
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
2009-06-23 02:26:56 +04:00
/**
* Helper to stat / lstat the base file of an smb_fname .
*/
static int streams_xattr_stat_base ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname ,
bool follow_links )
{
char * tmp_stream_name ;
int result ;
tmp_stream_name = smb_fname - > stream_name ;
smb_fname - > stream_name = NULL ;
if ( follow_links ) {
result = SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
} else {
result = SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
}
smb_fname - > stream_name = tmp_stream_name ;
return result ;
}
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-06-23 02:26:56 +04:00
struct smb_filename * smb_fname_base = NULL ;
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 ) ;
2008-12-02 00:54:53 +03:00
if ( io = = NULL | | fsp - > base_fsp = = NULL ) {
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 ;
}
2009-06-23 02:26:56 +04:00
/* Create an smb_filename with stream_name == NULL. */
2016-03-19 07:19:38 +03:00
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
io - > base ,
NULL ,
NULL ,
fsp - > fsp_name - > flags ) ;
2013-04-12 13:13:32 +04:00
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
2009-06-23 02:26:56 +04:00
return - 1 ;
}
2016-03-19 07:58:20 +03:00
if ( smb_fname_base - > flags & SMB_FILENAME_POSIX_PATH ) {
2009-06-23 02:26:56 +04:00
ret = SMB_VFS_LSTAT ( handle - > conn , smb_fname_base ) ;
2009-02-26 00:46:21 +03:00
} else {
2009-06-23 02:26:56 +04:00
ret = SMB_VFS_STAT ( handle - > conn , smb_fname_base ) ;
2009-02-26 00:46:21 +03:00
}
2009-06-23 02:26:56 +04:00
* sbuf = smb_fname_base - > st ;
2009-02-26 00:46:21 +03:00
if ( ret = = - 1 ) {
2017-05-26 02:42:04 +03:00
TALLOC_FREE ( smb_fname_base ) ;
2008-01-20 01:33:11 +03:00
return - 1 ;
}
2017-05-11 18:36:15 +03:00
sbuf - > st_ex_size = get_xattr_size ( handle - > conn ,
2017-05-26 02:42:04 +03:00
smb_fname_base , io - > xattr_name ) ;
2009-05-14 17:34:42 +04:00
if ( sbuf - > st_ex_size = = - 1 ) {
2017-05-26 02:42:04 +03:00
TALLOC_FREE ( smb_fname_base ) ;
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
2017-05-26 02:42:04 +03:00
TALLOC_FREE ( smb_fname_base ) ;
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 ;
2008-01-20 01:33:11 +03:00
2009-06-23 02:26:56 +04:00
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
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
* get here as is_ntfs_stream_smb_fname ( ) is
* always false . So we never need worry about
* not following links here . */
2009-06-23 02:26:56 +04:00
/* If the default stream is requested, just stat the base file. */
if ( is_ntfs_default_stream_smb_fname ( smb_fname ) ) {
return streams_xattr_stat_base ( handle , smb_fname , true ) ;
2008-12-02 00:54:53 +03:00
}
2009-06-23 02:26:56 +04:00
/* Populate the stat struct with info from the base file. */
if ( streams_xattr_stat_base ( handle , smb_fname , true ) = = - 1 ) {
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. */
2017-05-11 18:36:15 +03:00
smb_fname - > st . st_ex_size = get_xattr_size ( handle - > conn ,
2017-05-26 02:42:04 +03:00
smb_fname ,
2009-06-23 02:26:56 +04:00
xattr_name ) ;
if ( smb_fname - > st . st_ex_size = = - 1 ) {
2017-05-11 08:59:20 +03:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2008-01-20 01:33:11 +03:00
errno = ENOENT ;
2009-06-23 02:26:56 +04:00
result = - 1 ;
2008-01-20 01:33:11 +03:00
goto fail ;
}
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 ;
2018-04-11 18:41:00 +03:00
smb_fname - > st . st_ex_mode & = ~ S_IFDIR ;
2009-06-23 02:26:56 +04:00
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
result = 0 ;
fail :
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( xattr_name ) ;
2008-01-20 01:33:11 +03:00
return result ;
}
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
{
NTSTATUS status ;
int result = - 1 ;
2009-06-23 02:26:56 +04:00
char * xattr_name = NULL ;
2008-01-20 01:33:11 +03:00
2009-06-23 02:26:56 +04:00
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
return SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
2008-01-20 01:33:11 +03:00
}
2009-10-17 05:13:06 +04:00
/* If the default stream is requested, just stat the base file. */
2009-06-23 02:26:56 +04:00
if ( is_ntfs_default_stream_smb_fname ( smb_fname ) ) {
return streams_xattr_stat_base ( handle , smb_fname , false ) ;
2008-12-02 00:54:53 +03:00
}
2009-06-23 02:26:56 +04:00
/* Populate the stat struct with info from the base file. */
if ( streams_xattr_stat_base ( handle , smb_fname , false ) = = - 1 ) {
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. */
2017-05-11 18:36:15 +03:00
smb_fname - > st . st_ex_size = get_xattr_size ( handle - > conn ,
2017-05-26 02:42:04 +03:00
smb_fname ,
2009-06-23 02:26:56 +04:00
xattr_name ) ;
if ( smb_fname - > st . st_ex_size = = - 1 ) {
2017-05-11 08:59:20 +03:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2008-01-20 01:33:11 +03:00
errno = ENOENT ;
2009-06-23 02:26:56 +04:00
result = - 1 ;
2008-01-20 01:33:11 +03:00
goto fail ;
}
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
result = 0 ;
2009-06-23 02:26:56 +04:00
2008-01-20 01:33:11 +03:00
fail :
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( xattr_name ) ;
2008-01-20 01:33:11 +03:00
return result ;
}
2009-06-16 23:01:13 +04:00
static int streams_xattr_open ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname ,
2008-01-20 01:33:11 +03:00
files_struct * fsp , int flags , mode_t mode )
{
NTSTATUS status ;
2017-05-11 19:08:56 +03:00
struct streams_xattr_config * config = NULL ;
struct stream_io * sio = NULL ;
2008-01-20 01:33:11 +03:00
struct ea_struct ea ;
2009-06-16 23:01:13 +04:00
char * xattr_name = NULL ;
2017-05-11 19:08:56 +03:00
int pipe_fds [ 2 ] ;
int fakefd = - 1 ;
2018-08-23 13:07:20 +03:00
bool set_empty_xattr = false ;
2017-02-17 10:10:53 +03:00
int ret ;
2008-01-20 01:33:11 +03:00
2017-05-11 19:08:56 +03:00
SMB_VFS_HANDLE_GET_DATA ( handle , config , struct streams_xattr_config ,
return - 1 ) ;
2013-06-13 01:55:15 +04:00
DEBUG ( 10 , ( " streams_xattr_open called for %s with flags 0x%x \n " ,
smb_fname_str_dbg ( smb_fname ) , flags ) ) ;
2008-01-20 15:55:27 +03:00
2009-06-16 23:01:13 +04:00
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
return SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
2008-01-20 01:33:11 +03:00
}
2009-06-16 23:01:13 +04:00
/* If the default stream is requested, just open the base file. */
if ( is_ntfs_default_stream_smb_fname ( smb_fname ) ) {
char * tmp_stream_name ;
2008-01-20 01:33:11 +03:00
2009-06-16 23:01:13 +04:00
tmp_stream_name = smb_fname - > stream_name ;
smb_fname - > stream_name = NULL ;
ret = SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
smb_fname - > stream_name = tmp_stream_name ;
return ret ;
2008-01-20 01:33:11 +03:00
}
2014-05-20 17:17:01 +04:00
status = streams_xattr_get_name ( handle , talloc_tos ( ) ,
smb_fname - > stream_name , & xattr_name ) ;
2009-06-16 23:01:13 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto fail ;
2008-12-02 00:54:53 +03:00
}
2009-06-16 23:01:13 +04:00
status = get_ea_value ( talloc_tos ( ) , handle - > conn , NULL ,
2017-05-26 02:42:04 +03:00
smb_fname , xattr_name , & ea ) ;
2008-01-20 01:33:11 +03:00
2008-01-20 15:55:27 +03:00
DEBUG ( 10 , ( " get_ea_value returned %s \n " , nt_errstr ( status ) ) ) ;
2018-08-23 13:07:20 +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 ;
}
if ( ! ( flags & O_CREAT ) ) {
errno = ENOATTR ;
goto fail ;
}
set_empty_xattr = true ;
}
if ( flags & O_TRUNC ) {
set_empty_xattr = true ;
2008-01-20 01:33:11 +03:00
}
2018-08-23 13:07:20 +03:00
if ( set_empty_xattr ) {
2008-01-20 01:33:11 +03:00
/*
2013-06-13 01:55:15 +04:00
* The attribute does not exist or needs to be truncated
2008-01-20 01:33:11 +03:00
*/
2013-06-13 01:55:15 +04:00
/*
* Darn , xattrs need at least 1 byte
*/
char null = ' \0 ' ;
2008-01-20 01:33:11 +03:00
2013-06-13 01:55:15 +04:00
DEBUG ( 10 , ( " creating or truncating attribute %s on file %s \n " ,
xattr_name , smb_fname - > base_name ) ) ;
2008-01-20 15:49:38 +03:00
2017-05-11 16:05:23 +03:00
ret = SMB_VFS_SETXATTR ( fsp - > conn ,
smb_fname ,
xattr_name ,
& null , sizeof ( null ) ,
flags & O_EXCL ? XATTR_CREATE : 0 ) ;
2017-02-17 10:10:53 +03:00
if ( ret ! = 0 ) {
goto fail ;
2008-01-20 01:33:11 +03:00
}
}
2018-08-23 13:07:20 +03:00
/*
* Return a valid fd , but ensure any attempt to use it returns an error
* ( EPIPE ) .
*/
ret = pipe ( pipe_fds ) ;
if ( ret ! = 0 ) {
goto fail ;
}
close ( pipe_fds [ 1 ] ) ;
pipe_fds [ 1 ] = - 1 ;
fakefd = pipe_fds [ 0 ] ;
2017-12-05 15:21:04 +03:00
sio = VFS_ADD_FSP_EXTENSION ( handle , fsp , struct stream_io , NULL ) ;
2008-01-20 01:33:11 +03:00
if ( sio = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
sio - > xattr_name = talloc_strdup ( VFS_MEMCTX_FSP_EXTENSION ( handle , fsp ) ,
xattr_name ) ;
2018-08-08 15:20:58 +03:00
if ( sio - > xattr_name = = NULL ) {
errno = ENOMEM ;
goto fail ;
}
2017-02-01 22:36:25 +03:00
/*
* 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 .
*/
2008-01-20 01:33:11 +03:00
sio - > base = talloc_strdup ( VFS_MEMCTX_FSP_EXTENSION ( handle , fsp ) ,
2017-02-01 22:36:25 +03:00
fsp - > fsp_name - > base_name ) ;
2018-08-08 15:20:58 +03:00
if ( sio - > base = = NULL ) {
2008-01-20 01:33:11 +03:00
errno = ENOMEM ;
goto fail ;
}
2018-08-08 15:20:58 +03:00
sio - > fsp_name_ptr = fsp - > fsp_name ;
sio - > handle = handle ;
sio - > fsp = fsp ;
2017-05-11 19:08:56 +03:00
return fakefd ;
2008-01-20 01:33:11 +03:00
fail :
2017-05-11 19:08:56 +03:00
if ( fakefd > = 0 ) {
close ( fakefd ) ;
fakefd = - 1 ;
2008-01-20 01:33:11 +03:00
}
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 ;
fd = fsp - > fh - > fd ;
DBG_DEBUG ( " streams_xattr_close called [%s] fd [%d] \n " ,
smb_fname_str_dbg ( fsp - > fsp_name ) , fd ) ;
if ( ! is_ntfs_stream_smb_fname ( fsp - > fsp_name ) ) {
return SMB_VFS_NEXT_CLOSE ( handle , fsp ) ;
}
if ( is_ntfs_default_stream_smb_fname ( fsp - > fsp_name ) ) {
return SMB_VFS_NEXT_CLOSE ( handle , fsp ) ;
}
ret = close ( fd ) ;
fsp - > fh - > fd = - 1 ;
return ret ;
}
2009-07-02 20:27:44 +04:00
static int streams_xattr_unlink ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
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 ;
2008-01-20 01:33:11 +03:00
2009-07-02 20:27:44 +04:00
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
return SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2008-01-20 01:33:11 +03:00
}
2009-07-02 20:27:44 +04:00
/* If the default stream is requested, just open the base file. */
if ( is_ntfs_default_stream_smb_fname ( smb_fname ) ) {
struct smb_filename * smb_fname_base = NULL ;
2013-04-11 17:36:18 +04:00
smb_fname_base = cp_smb_filename ( talloc_tos ( ) , smb_fname ) ;
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
2009-07-02 20:27:44 +04:00
return - 1 ;
}
2008-01-20 01:33:11 +03:00
2009-07-02 20:27:44 +04:00
ret = SMB_VFS_NEXT_UNLINK ( handle , smb_fname_base ) ;
TALLOC_FREE ( smb_fname_base ) ;
return ret ;
2008-12-02 00:54:53 +03:00
}
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 ;
}
2017-05-24 21:35:50 +03:00
ret = SMB_VFS_REMOVEXATTR ( handle - > conn , smb_fname , 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 ) ;
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 ,
const struct smb_filename * smb_fname_dst )
{
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 ;
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 ;
}
/* 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 ;
}
/* read the old stream */
status = get_ea_value ( talloc_tos ( ) , handle - > conn , NULL ,
smb_fname_src , src_xattr_name , & ea ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = ENOENT ;
goto fail ;
}
/* (over)write the new stream */
nret = SMB_VFS_SETXATTR ( handle - > conn , smb_fname_src ,
dst_xattr_name , ea . value . data , ea . value . length ,
0 ) ;
if ( nret < 0 ) {
if ( errno = = ENOATTR ) {
errno = ENOENT ;
}
goto fail ;
}
/* remove the old stream */
oret = SMB_VFS_REMOVEXATTR ( handle - > conn , smb_fname_src ,
src_xattr_name ) ;
if ( oret < 0 ) {
if ( errno = = ENOATTR ) {
errno = ENOENT ;
}
goto fail ;
}
done :
errno = 0 ;
ret = 0 ;
fail :
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
2016-03-12 02:11:20 +03:00
status = get_ea_names_from_file ( talloc_tos ( ) ,
handle - > conn ,
fsp ,
2016-03-12 02:34:58 +03:00
smb_fname ,
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
2016-03-12 02:11:20 +03:00
status = get_ea_value ( names ,
handle - > conn ,
2017-05-11 18:38:00 +03:00
NULL ,
2017-05-26 02:42:04 +03:00
smb_fname ,
2016-03-12 02:11:20 +03:00
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 ;
}
static NTSTATUS streams_xattr_streaminfo ( vfs_handle_struct * handle ,
struct files_struct * fsp ,
2016-03-05 01:16:13 +03:00
const struct smb_filename * smb_fname ,
2008-01-20 01:33:11 +03:00
TALLOC_CTX * mem_ctx ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
SMB_STRUCT_STAT sbuf ;
int ret ;
NTSTATUS status ;
struct streaminfo_state state ;
2017-05-11 16:05:23 +03:00
ret = vfs_stat_smb_basename ( handle - > conn , smb_fname , & sbuf ) ;
2008-01-20 01:33:11 +03:00
if ( ret = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
2011-10-14 02:41:53 +04:00
state . streams = * pstreams ;
state . num_streams = * pnum_streams ;
2008-01-20 01:33:11 +03:00
state . mem_ctx = mem_ctx ;
state . handle = handle ;
state . status = NT_STATUS_OK ;
2014-02-07 22:19:26 +04:00
if ( S_ISLNK ( sbuf . st_ex_mode ) ) {
/*
* Currently we do ' t have SMB_VFS_LLISTXATTR
* inside the VFS which means there ' s no way
* to cope with a symlink when lp_posix_pathnames ( ) .
* returns true . For now ignore links .
* FIXME - by adding SMB_VFS_LLISTXATTR . JRA .
*/
status = NT_STATUS_OK ;
} else {
2016-03-12 02:11:20 +03:00
status = walk_xattr_streams ( handle , fsp , smb_fname ,
2008-01-20 01:33:11 +03:00
collect_one_stream , & state ) ;
2014-02-07 22:19:26 +04:00
}
2008-01-20 01:33:11 +03:00
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 ;
2011-10-14 02:41:53 +04:00
2016-03-05 01:16:13 +03:00
return SMB_VFS_NEXT_STREAMINFO ( handle ,
fsp ,
smb_fname ,
mem_ctx ,
pnum_streams ,
pstreams ) ;
2008-01-20 01:33:11 +03:00
}
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 ;
2017-05-26 02:42:04 +03:00
struct smb_filename * smb_fname_base = NULL ;
2008-01-20 01:33:11 +03:00
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 ;
}
2017-05-26 02:42:04 +03:00
/* Create an smb_filename with stream_name == NULL. */
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
sio - > base ,
NULL ,
NULL ,
fsp - > fsp_name - > flags ) ;
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
2017-05-11 18:38:00 +03:00
status = get_ea_value ( talloc_tos ( ) , handle - > conn , NULL ,
2017-05-26 02:42:04 +03:00
smb_fname_base , 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 ) ;
2017-05-11 16:05:23 +03:00
ret = SMB_VFS_SETXATTR ( fsp - > conn ,
fsp - > fsp_name ,
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 ;
2017-05-26 02:42:04 +03:00
struct smb_filename * smb_fname_base = NULL ;
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 ;
}
2017-05-26 02:42:04 +03:00
/* Create an smb_filename with stream_name == NULL. */
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
sio - > base ,
NULL ,
NULL ,
fsp - > fsp_name - > flags ) ;
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
2017-05-11 18:38:00 +03:00
status = get_ea_value ( talloc_tos ( ) , handle - > conn , NULL ,
2017-05-26 02:42:04 +03:00
smb_fname_base , 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 ;
2009-09-16 05:15:53 +04:00
DEBUG ( 10 , ( " streams_xattr_pread: get_ea_value returned %d bytes \n " ,
( int ) length ) ) ;
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 ) ;
2017-05-26 02:42:04 +03:00
struct smb_filename * smb_fname_base = NULL ;
2008-11-22 02:42:03 +03:00
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 ;
}
2017-05-26 02:42:04 +03:00
/* Create an smb_filename with stream_name == NULL. */
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
sio - > base ,
NULL ,
NULL ,
fsp - > fsp_name - > flags ) ;
if ( smb_fname_base = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
2017-05-11 18:38:00 +03:00
status = get_ea_value ( talloc_tos ( ) , handle - > conn , NULL ,
2017-05-26 02:42:04 +03:00
smb_fname_base , 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 ;
2017-05-11 16:05:23 +03:00
ret = SMB_VFS_SETXATTR ( fsp - > conn ,
fsp - > fsp_name ,
sio - > xattr_name ,
ea . value . data , ea . value . length , 0 ) ;
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 ;
}
static SMB_ACL_T streams_xattr_sys_acl_get_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
TALLOC_CTX * mem_ctx )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_SYS_ACL_GET_FD ( handle , fsp , mem_ctx ) ;
}
return SMB_VFS_NEXT_SYS_ACL_GET_FILE (
handle , fsp - > base_fsp - > fsp_name ,
SMB_ACL_TYPE_ACCESS , mem_ctx ) ;
}
static int streams_xattr_sys_acl_set_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
SMB_ACL_T theacl )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_SYS_ACL_SET_FD ( handle , fsp , theacl ) ;
}
return 0 ;
}
static int streams_xattr_sys_acl_blob_get_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
TALLOC_CTX * mem_ctx ,
char * * blob_description ,
DATA_BLOB * blob )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD ( handle , fsp , mem_ctx ,
blob_description , blob ) ;
}
return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE (
handle , fsp - > base_fsp - > fsp_name , mem_ctx ,
blob_description , blob ) ;
}
static NTSTATUS streams_xattr_fget_nt_acl ( vfs_handle_struct * handle ,
files_struct * fsp ,
uint32_t security_info ,
TALLOC_CTX * mem_ctx ,
struct security_descriptor * * ppdesc )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FGET_NT_ACL ( handle , fsp , security_info ,
mem_ctx , ppdesc ) ;
}
return SMB_VFS_NEXT_GET_NT_ACL ( handle , fsp - > base_fsp - > fsp_name ,
security_info , mem_ctx , ppdesc ) ;
}
static NTSTATUS streams_xattr_fset_nt_acl ( vfs_handle_struct * handle ,
files_struct * fsp ,
uint32_t security_info_sent ,
const struct security_descriptor * psd )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_FSET_NT_ACL ( handle , fsp ,
security_info_sent , psd ) ;
}
return NT_STATUS_OK ;
}
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 ;
}
static int streams_xattr_kernel_flock ( vfs_handle_struct * handle ,
files_struct * fsp ,
uint32_t share_mode ,
uint32_t access_mask )
{
struct stream_io * sio =
( struct stream_io * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( sio = = NULL ) {
return SMB_VFS_NEXT_KERNEL_FLOCK ( handle , fsp ,
share_mode , access_mask ) ;
}
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 ;
}
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 ,
2011-04-21 00:55:25 +04:00
. open_fn = streams_xattr_open ,
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 ,
2011-12-04 08:45:04 +04:00
. unlink_fn = streams_xattr_unlink ,
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 ,
. streaminfo_fn = streams_xattr_streaminfo ,
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 ,
. kernel_flock_fn = streams_xattr_kernel_flock ,
. linux_setlease_fn = streams_xattr_linux_setlease ,
. strict_lock_check_fn = streams_xattr_strict_lock_check ,
. 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 ,
. sys_acl_get_fd_fn = streams_xattr_sys_acl_get_fd ,
. sys_acl_blob_get_fd_fn = streams_xattr_sys_acl_blob_get_fd ,
. sys_acl_set_fd_fn = streams_xattr_sys_acl_set_fd ,
. fget_nt_acl_fn = streams_xattr_fget_nt_acl ,
. fset_nt_acl_fn = streams_xattr_fset_nt_acl ,
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
}