2008-12-13 01:32:48 +03:00
/*
* Unix SMB / CIFS implementation .
*
* Support for OneFS Alternate Data Streams
*
* Copyright ( C ) Tim Prouty , 2008
*
* 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/>.
*/
2009-02-28 01:47:47 +03:00
# include "includes.h"
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2008-12-13 01:32:48 +03:00
# include "onefs.h"
2009-02-28 01:47:47 +03:00
# include "onefs_config.h"
2008-12-13 01:32:48 +03:00
# include <sys/isi_enc.h>
2009-06-25 22:20:36 +04:00
NTSTATUS onefs_stream_prep_smb_fname ( TALLOC_CTX * ctx ,
const struct smb_filename * smb_fname_in ,
struct smb_filename * * smb_fname_out )
{
char * stream_name = NULL ;
NTSTATUS status ;
/*
* Only attempt to strip off the trailing : $ DATA if there is an actual
* stream there . If it is the default stream , the smb_fname_out will
* just have a NULL stream so the base file is opened .
*/
if ( smb_fname_in - > stream_name & &
! is_ntfs_default_stream_smb_fname ( smb_fname_in ) ) {
char * str_tmp = smb_fname_in - > stream_name ;
/* First strip off the leading ':' */
if ( str_tmp [ 0 ] = = ' : ' ) {
str_tmp + + ;
}
/* Create a new copy of the stream_name. */
stream_name = talloc_strdup ( ctx , str_tmp ) ;
if ( stream_name = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/* Strip off the :$DATA if one exists. */
str_tmp = strrchr_m ( stream_name , ' : ' ) ;
if ( str_tmp ) {
2011-05-13 22:21:30 +04:00
if ( strcasecmp_m ( str_tmp , " :$DATA " ) ! = 0 ) {
2009-08-18 13:34:54 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
2009-06-25 22:20:36 +04:00
str_tmp [ 0 ] = ' \0 ' ;
}
}
/*
* If there was a stream that wasn ' t the default stream the leading
* colon and trailing : $ DATA has now been stripped off . Create a new
* smb_filename to pass back .
*/
status = create_synthetic_smb_fname ( ctx , smb_fname_in - > base_name ,
stream_name , & smb_fname_in - > st ,
smb_fname_out ) ;
TALLOC_FREE ( stream_name ) ;
2009-08-29 02:53:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 5 , ( " Failed to prep stream name for %s: %s \n " ,
* smb_fname_out ?
smb_fname_str_dbg ( * smb_fname_out ) : " NULL " ,
nt_errstr ( status ) ) ) ;
}
2009-06-25 22:20:36 +04:00
return status ;
}
2008-12-13 01:32:48 +03:00
int onefs_close ( vfs_handle_struct * handle , struct files_struct * fsp )
{
int ret2 , ret = 0 ;
if ( fsp - > base_fsp ) {
ret = SMB_VFS_NEXT_CLOSE ( handle , fsp - > base_fsp ) ;
}
ret2 = SMB_VFS_NEXT_CLOSE ( handle , fsp ) ;
return ret ? ret : ret2 ;
}
/*
* Get the ADS directory fd for a file .
*/
static int get_stream_dir_fd ( connection_struct * conn , const char * base ,
int * base_fdp )
{
int base_fd ;
int dir_fd ;
int saved_errno ;
2009-08-29 02:53:05 +04:00
DEBUG ( 10 , ( " Getting stream directory fd: %s (%d) \n " , base ,
base_fdp ? * base_fdp : - 1 ) ) ;
2008-12-13 01:32:48 +03:00
/* If a valid base_fdp was given, use it. */
if ( base_fdp & & * base_fdp > = 0 ) {
base_fd = * base_fdp ;
} else {
base_fd = onefs_sys_create_file ( conn ,
- 1 ,
base ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
INTERNAL_OPEN_ONLY ,
0 ,
NULL ,
0 ,
NULL ) ;
if ( base_fd < 0 ) {
2009-08-29 02:53:05 +04:00
DEBUG ( 5 , ( " Failed getting base fd: %s \n " ,
strerror ( errno ) ) ) ;
2008-12-13 01:32:48 +03:00
return - 1 ;
}
}
/* Open the ADS directory. */
dir_fd = onefs_sys_create_file ( conn ,
base_fd ,
" . " ,
0 ,
FILE_READ_DATA ,
0 ,
0 ,
0 ,
0 ,
INTERNAL_OPEN_ONLY ,
0 ,
NULL ,
0 ,
NULL ) ;
/* Close base_fd if it's not need or on error. */
if ( ! base_fdp | | dir_fd < 0 ) {
saved_errno = errno ;
close ( base_fd ) ;
errno = saved_errno ;
}
/* Set the out base_fdp if successful and it was requested. */
if ( base_fdp & & dir_fd > = 0 ) {
* base_fdp = base_fd ;
}
2009-08-29 02:53:05 +04:00
if ( dir_fd < 0 ) {
DEBUG ( 5 , ( " Failed getting stream directory fd: %s \n " ,
strerror ( errno ) ) ) ;
}
2008-12-13 01:32:48 +03:00
return dir_fd ;
}
2009-07-01 04:04:38 +04:00
int onefs_rename ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname_src ,
const struct smb_filename * smb_fname_dst )
2008-12-13 01:32:48 +03:00
{
2009-07-01 04:04:38 +04:00
struct smb_filename * smb_fname_src_onefs = NULL ;
struct smb_filename * smb_fname_dst_onefs = NULL ;
NTSTATUS status ;
2009-01-12 10:16:37 +03:00
int saved_errno ;
2009-07-01 04:04:38 +04:00
int dir_fd = - 1 ;
int ret = - 1 ;
2008-12-13 01:32:48 +03:00
2009-02-23 21:24:33 +03:00
START_PROFILE ( syscall_rename_at ) ;
2009-07-01 04:04:38 +04:00
if ( ! is_ntfs_stream_smb_fname ( smb_fname_src ) & &
! is_ntfs_stream_smb_fname ( smb_fname_dst ) ) {
ret = SMB_VFS_NEXT_RENAME ( handle , smb_fname_src ,
smb_fname_dst ) ;
goto done ;
2009-02-23 21:24:33 +03:00
}
2008-12-13 01:32:48 +03:00
2009-07-01 04:04:38 +04: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 ) ) {
2009-08-29 02:53:05 +04:00
DEBUG ( 3 , ( " Unable to rename to/from a default stream: %s -> "
" %s \n " , smb_fname_str_dbg ( smb_fname_src ) ,
smb_fname_str_dbg ( smb_fname_dst ) ) ) ;
2009-07-01 04:04:38 +04:00
errno = ENOSYS ;
goto done ;
2009-02-23 21:24:33 +03:00
}
2009-01-24 03:55:18 +03:00
2009-07-01 04:04:38 +04:00
/* prep stream smb_filename structs. */
status = onefs_stream_prep_smb_fname ( talloc_tos ( ) , smb_fname_src ,
& smb_fname_src_onefs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto done ;
}
status = onefs_stream_prep_smb_fname ( talloc_tos ( ) , smb_fname_dst ,
& smb_fname_dst_onefs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
goto done ;
2008-12-13 01:32:48 +03:00
}
2009-07-01 04:04:38 +04:00
dir_fd = get_stream_dir_fd ( handle - > conn , smb_fname_src - > base_name ,
NULL ) ;
2008-12-13 01:32:48 +03:00
if ( dir_fd < - 1 ) {
goto done ;
}
2009-07-01 04:04:38 +04:00
DEBUG ( 8 , ( " onefs_rename called for %s => %s \n " ,
smb_fname_str_dbg ( smb_fname_src_onefs ) ,
smb_fname_str_dbg ( smb_fname_dst_onefs ) ) ) ;
2008-12-13 01:32:48 +03:00
/* Handle rename of stream to default stream specially. */
2009-07-01 04:04:38 +04:00
if ( smb_fname_dst_onefs - > stream_name = = NULL ) {
ret = enc_renameat ( dir_fd , smb_fname_src_onefs - > stream_name ,
ENC_DEFAULT , AT_FDCWD ,
smb_fname_dst_onefs - > base_name ,
ENC_DEFAULT ) ;
2008-12-13 01:32:48 +03:00
} else {
2009-07-01 04:04:38 +04:00
ret = enc_renameat ( dir_fd , smb_fname_src_onefs - > stream_name ,
ENC_DEFAULT , dir_fd ,
smb_fname_dst_onefs - > stream_name ,
2008-12-13 01:32:48 +03:00
ENC_DEFAULT ) ;
}
done :
2009-02-23 21:24:33 +03:00
END_PROFILE ( syscall_rename_at ) ;
2009-07-01 04:04:38 +04:00
TALLOC_FREE ( smb_fname_src_onefs ) ;
TALLOC_FREE ( smb_fname_dst_onefs ) ;
2009-02-23 21:24:33 +03:00
2008-12-13 01:32:48 +03:00
saved_errno = errno ;
2009-01-12 10:16:37 +03:00
if ( dir_fd > = 0 ) {
close ( dir_fd ) ;
}
2008-12-13 01:32:48 +03:00
errno = saved_errno ;
return ret ;
}
/*
* Merge a base file ' s sbuf into the a streams ' s sbuf .
*/
static void merge_stat ( SMB_STRUCT_STAT * stream_sbuf ,
const SMB_STRUCT_STAT * base_sbuf )
{
int dos_flags = ( UF_DOS_NOINDEX | UF_DOS_ARCHIVE |
UF_DOS_HIDDEN | UF_DOS_RO | UF_DOS_SYSTEM ) ;
2009-05-29 01:11:43 +04:00
stream_sbuf - > st_ex_mtime = base_sbuf - > st_ex_mtime ;
stream_sbuf - > st_ex_ctime = base_sbuf - > st_ex_ctime ;
stream_sbuf - > st_ex_atime = base_sbuf - > st_ex_atime ;
stream_sbuf - > st_ex_flags & = ~ dos_flags ;
stream_sbuf - > st_ex_flags | = base_sbuf - > st_ex_flags & dos_flags ;
2008-12-13 01:32:48 +03:00
}
2009-01-29 19:08:35 +03:00
/* fake timestamps */
2009-05-29 01:11:43 +04:00
static void onefs_adjust_stat_time ( struct connection_struct * conn ,
const char * fname , SMB_STRUCT_STAT * sbuf )
2009-01-29 19:08:35 +03:00
{
2009-02-24 01:51:17 +03:00
struct onefs_vfs_share_config cfg ;
2009-01-29 19:08:35 +03:00
struct timeval tv_now = { 0 , 0 } ;
bool static_mtime = False ;
bool static_atime = False ;
2009-05-29 01:11:43 +04:00
if ( ! onefs_get_config ( SNUM ( conn ) ,
2009-01-29 19:08:35 +03:00
ONEFS_VFS_CONFIG_FAKETIMESTAMPS , & cfg ) ) {
return ;
}
2009-05-29 01:11:43 +04:00
if ( IS_MTIME_STATIC_PATH ( conn , & cfg , fname ) ) {
sbuf - > st_ex_mtime = sbuf - > st_ex_btime ;
2009-01-29 19:08:35 +03:00
static_mtime = True ;
}
2009-05-29 01:11:43 +04:00
if ( IS_ATIME_STATIC_PATH ( conn , & cfg , fname ) ) {
sbuf - > st_ex_atime = sbuf - > st_ex_btime ;
2009-01-29 19:08:35 +03:00
static_atime = True ;
}
2009-05-29 01:11:43 +04:00
if ( IS_CTIME_NOW_PATH ( conn , & cfg , fname ) ) {
2009-01-29 19:08:35 +03:00
if ( cfg . ctime_slop < 0 ) {
2009-05-29 01:11:43 +04:00
sbuf - > st_ex_btime . tv_sec = INT_MAX - 1 ;
2009-01-29 19:08:35 +03:00
} else {
GetTimeOfDay ( & tv_now ) ;
2009-05-29 01:11:43 +04:00
sbuf - > st_ex_btime . tv_sec = tv_now . tv_sec +
cfg . ctime_slop ;
2009-01-29 19:08:35 +03:00
}
}
2009-05-29 01:11:43 +04:00
if ( ! static_mtime & & IS_MTIME_NOW_PATH ( conn , & cfg , fname ) ) {
2009-01-29 19:08:35 +03:00
if ( cfg . mtime_slop < 0 ) {
2009-05-29 01:11:43 +04:00
sbuf - > st_ex_mtime . tv_sec = INT_MAX - 1 ;
2009-01-29 19:08:35 +03:00
} else {
if ( tv_now . tv_sec = = 0 )
GetTimeOfDay ( & tv_now ) ;
2009-05-29 01:11:43 +04:00
sbuf - > st_ex_mtime . tv_sec = tv_now . tv_sec +
cfg . mtime_slop ;
2009-01-29 19:08:35 +03:00
}
}
2009-05-29 01:11:43 +04:00
if ( ! static_atime & & IS_ATIME_NOW_PATH ( conn , & cfg , fname ) ) {
2009-01-29 19:08:35 +03:00
if ( cfg . atime_slop < 0 ) {
2009-05-29 01:11:43 +04:00
sbuf - > st_ex_atime . tv_sec = INT_MAX - 1 ;
2009-01-29 19:08:35 +03:00
} else {
if ( tv_now . tv_sec = = 0 )
GetTimeOfDay ( & tv_now ) ;
2009-05-29 01:11:43 +04:00
sbuf - > st_ex_atime . tv_sec = tv_now . tv_sec +
cfg . atime_slop ;
2009-01-29 19:08:35 +03:00
}
}
}
2009-05-29 01:11:43 +04:00
static int stat_stream ( struct connection_struct * conn , const char * base ,
2008-12-13 01:32:48 +03:00
const char * stream , SMB_STRUCT_STAT * sbuf , int flags )
{
SMB_STRUCT_STAT base_sbuf ;
int base_fd = - 1 , dir_fd , ret , saved_errno ;
2009-05-29 01:11:43 +04:00
dir_fd = get_stream_dir_fd ( conn , base , & base_fd ) ;
2008-12-13 01:32:48 +03:00
if ( dir_fd < 0 ) {
return - 1 ;
}
/* Stat the stream. */
2009-05-29 01:11:43 +04:00
ret = onefs_sys_fstat_at ( dir_fd , stream , sbuf , flags ) ;
2008-12-13 01:32:48 +03:00
if ( ret ! = - 1 ) {
2009-08-29 02:53:05 +04:00
DEBUG ( 10 , ( " stat of stream '%s' failed: %s \n " , stream ,
strerror ( errno ) ) ) ;
} else {
2008-12-13 01:32:48 +03:00
/* Now stat the base file and merge the results. */
2009-05-29 01:11:43 +04:00
ret = onefs_sys_fstat ( base_fd , & base_sbuf ) ;
2008-12-13 01:32:48 +03:00
if ( ret ! = - 1 ) {
merge_stat ( sbuf , & base_sbuf ) ;
}
}
saved_errno = errno ;
close ( dir_fd ) ;
close ( base_fd ) ;
errno = saved_errno ;
return ret ;
}
2009-06-25 22:20:36 +04:00
int onefs_stat ( vfs_handle_struct * handle , struct smb_filename * smb_fname )
2008-12-13 01:32:48 +03:00
{
2009-06-25 22:20:36 +04:00
struct smb_filename * smb_fname_onefs = NULL ;
NTSTATUS status ;
2009-01-24 03:55:18 +03:00
int ret ;
2008-12-13 01:32:48 +03:00
2009-06-25 22:20:36 +04:00
status = onefs_stream_prep_smb_fname ( talloc_tos ( ) , smb_fname ,
& smb_fname_onefs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
}
2008-12-13 01:32:48 +03:00
2009-06-25 22:20:36 +04:00
/*
* If the smb_fname has no stream or is : $ DATA , then just stat the
* base stream . Otherwise stat the stream .
*/
if ( ! is_ntfs_stream_smb_fname ( smb_fname_onefs ) ) {
ret = onefs_sys_stat ( smb_fname_onefs - > base_name ,
& smb_fname - > st ) ;
2009-01-29 19:08:35 +03:00
} else {
2009-06-25 22:20:36 +04:00
ret = stat_stream ( handle - > conn , smb_fname_onefs - > base_name ,
smb_fname_onefs - > stream_name , & smb_fname - > st ,
0 ) ;
2008-12-13 01:32:48 +03:00
}
2009-06-25 22:20:36 +04:00
onefs_adjust_stat_time ( handle - > conn , smb_fname - > base_name ,
& smb_fname - > st ) ;
TALLOC_FREE ( smb_fname_onefs ) ;
2009-01-29 19:08:35 +03:00
return ret ;
2008-12-13 01:32:48 +03:00
}
int onefs_fstat ( vfs_handle_struct * handle , struct files_struct * fsp ,
SMB_STRUCT_STAT * sbuf )
{
SMB_STRUCT_STAT base_sbuf ;
int ret ;
/* Stat the stream, by calling next_fstat on the stream's fd. */
2009-05-29 01:11:43 +04:00
ret = onefs_sys_fstat ( fsp - > fh - > fd , sbuf ) ;
2008-12-13 01:32:48 +03:00
if ( ret = = - 1 ) {
return ret ;
}
/* Stat the base file and merge the results. */
if ( fsp ! = NULL & & fsp - > base_fsp ! = NULL ) {
2009-05-29 01:11:43 +04:00
ret = onefs_sys_fstat ( fsp - > base_fsp - > fh - > fd , & base_sbuf ) ;
2008-12-13 01:32:48 +03:00
if ( ret ! = - 1 ) {
merge_stat ( sbuf , & base_sbuf ) ;
}
}
2009-07-11 05:11:32 +04:00
onefs_adjust_stat_time ( handle - > conn , fsp - > fsp_name - > base_name , sbuf ) ;
2008-12-13 01:32:48 +03:00
return ret ;
}
2009-06-25 22:20:36 +04:00
int onefs_lstat ( vfs_handle_struct * handle , struct smb_filename * smb_fname )
2008-12-13 01:32:48 +03:00
{
2009-06-25 22:20:36 +04:00
struct smb_filename * smb_fname_onefs = NULL ;
NTSTATUS status ;
2009-01-24 03:55:18 +03:00
int ret ;
2008-12-13 01:32:48 +03:00
2009-06-25 22:20:36 +04:00
status = onefs_stream_prep_smb_fname ( talloc_tos ( ) , smb_fname ,
& smb_fname_onefs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
}
2008-12-13 01:32:48 +03:00
2009-06-25 22:20:36 +04:00
/*
* If the smb_fname has no stream or is : $ DATA , then just stat the
* base stream . Otherwise stat the stream .
*/
if ( ! is_ntfs_stream_smb_fname ( smb_fname_onefs ) ) {
ret = onefs_sys_lstat ( smb_fname_onefs - > base_name ,
& smb_fname - > st ) ;
2009-01-29 19:08:35 +03:00
} else {
2009-06-25 22:20:36 +04:00
ret = stat_stream ( handle - > conn , smb_fname_onefs - > base_name ,
smb_fname_onefs - > stream_name , & smb_fname - > st ,
2009-01-29 19:08:35 +03:00
AT_SYMLINK_NOFOLLOW ) ;
2008-12-13 01:32:48 +03:00
}
2009-06-25 22:20:36 +04:00
onefs_adjust_stat_time ( handle - > conn , smb_fname - > base_name ,
& smb_fname - > st ) ;
TALLOC_FREE ( smb_fname_onefs ) ;
2009-01-29 19:08:35 +03:00
return ret ;
2008-12-13 01:32:48 +03:00
}
2009-07-02 20:27:44 +04:00
int onefs_unlink ( vfs_handle_struct * handle ,
2009-07-07 02:44:09 +04:00
const struct smb_filename * smb_fname )
2008-12-13 01:32:48 +03:00
{
2009-07-02 20:27:44 +04:00
struct smb_filename * smb_fname_onefs = NULL ;
2009-01-24 03:55:18 +03:00
int ret ;
int dir_fd , saved_errno ;
2009-07-07 02:44:09 +04:00
NTSTATUS status ;
2008-12-13 01:32:48 +03:00
2009-07-02 20:27:44 +04:00
/* Not a stream. */
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
return SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2008-12-13 01:32:48 +03:00
}
2009-07-02 20:27:44 +04:00
status = onefs_stream_prep_smb_fname ( talloc_tos ( ) , smb_fname ,
& smb_fname_onefs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
2008-12-13 01:32:48 +03:00
}
2009-07-02 20:27:44 +04:00
/* Default stream (the ::$DATA was just stripped off). */
if ( ! is_ntfs_stream_smb_fname ( smb_fname_onefs ) ) {
ret = SMB_VFS_NEXT_UNLINK ( handle , smb_fname_onefs ) ;
goto out ;
2008-12-13 01:32:48 +03:00
}
2009-07-02 20:27:44 +04:00
dir_fd = get_stream_dir_fd ( handle - > conn , smb_fname_onefs - > base_name ,
NULL ) ;
2008-12-13 01:32:48 +03:00
if ( dir_fd < 0 ) {
2009-07-02 20:27:44 +04:00
ret = - 1 ;
goto out ;
2008-12-13 01:32:48 +03:00
}
2009-07-02 20:27:44 +04:00
ret = enc_unlinkat ( dir_fd , smb_fname_onefs - > stream_name , ENC_DEFAULT ,
0 ) ;
2008-12-13 01:32:48 +03:00
saved_errno = errno ;
close ( dir_fd ) ;
errno = saved_errno ;
2009-07-02 20:27:44 +04:00
out :
TALLOC_FREE ( smb_fname_onefs ) ;
2008-12-13 01:32:48 +03:00
return ret ;
}
2009-07-03 00:39:20 +04:00
int onefs_vtimes_streams ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
2009-01-24 03:55:18 +03:00
int flags , struct timespec times [ 3 ] )
{
2009-07-03 00:39:20 +04:00
struct smb_filename * smb_fname_onefs = NULL ;
2009-01-24 03:55:18 +03:00
int ret ;
int dirfd ;
int saved_errno ;
2009-07-03 00:39:20 +04:00
NTSTATUS status ;
2009-01-24 03:55:18 +03:00
START_PROFILE ( syscall_ntimes ) ;
2009-07-03 00:39:20 +04:00
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
ret = vtimes ( smb_fname - > base_name , times , flags ) ;
2009-01-24 03:55:18 +03:00
return ret ;
}
2009-07-03 00:39:20 +04:00
status = onefs_stream_prep_smb_fname ( talloc_tos ( ) , smb_fname ,
& smb_fname_onefs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2009-01-24 03:55:18 +03:00
return - 1 ;
}
2009-07-03 00:39:20 +04:00
/* Default stream (the ::$DATA was just stripped off). */
if ( ! is_ntfs_stream_smb_fname ( smb_fname_onefs ) ) {
ret = vtimes ( smb_fname_onefs - > base_name , times , flags ) ;
goto out ;
}
dirfd = get_stream_dir_fd ( handle - > conn , smb_fname - > base_name , NULL ) ;
if ( dirfd < - 1 ) {
ret = - 1 ;
goto out ;
}
2009-01-24 03:55:18 +03:00
2009-07-03 00:39:20 +04:00
ret = enc_vtimesat ( dirfd , smb_fname_onefs - > stream_name , ENC_DEFAULT ,
times , flags ) ;
2009-01-24 03:55:18 +03:00
saved_errno = errno ;
close ( dirfd ) ;
errno = saved_errno ;
2009-07-03 00:39:20 +04:00
out :
END_PROFILE ( syscall_ntimes ) ;
TALLOC_FREE ( smb_fname_onefs ) ;
2009-01-24 03:55:18 +03:00
return ret ;
}
2008-12-13 01:32:48 +03:00
/*
* Streaminfo enumeration functionality
*/
struct streaminfo_state {
TALLOC_CTX * mem_ctx ;
vfs_handle_struct * handle ;
unsigned int num_streams ;
struct stream_struct * streams ;
NTSTATUS status ;
} ;
static bool add_one_stream ( TALLOC_CTX * mem_ctx , unsigned int * num_streams ,
struct stream_struct * * streams ,
const char * name , SMB_OFF_T size ,
SMB_OFF_T alloc_size )
{
struct stream_struct * tmp ;
2011-06-07 05:10:15 +04:00
tmp = talloc_realloc ( mem_ctx , * streams , struct stream_struct ,
2008-12-13 01:32:48 +03:00
( * num_streams ) + 1 ) ;
if ( tmp = = NULL ) {
return false ;
}
tmp [ * num_streams ] . name = talloc_asprintf ( mem_ctx , " :%s:%s " , name ,
" $DATA " ) ;
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 ;
}
static NTSTATUS walk_onefs_streams ( connection_struct * conn , files_struct * fsp ,
const char * fname ,
struct streaminfo_state * state ,
SMB_STRUCT_STAT * base_sbuf )
{
NTSTATUS status = NT_STATUS_OK ;
bool opened_base_fd = false ;
int base_fd = - 1 ;
int dir_fd = - 1 ;
int stream_fd = - 1 ;
int ret ;
SMB_STRUCT_DIR * dirp = NULL ;
SMB_STRUCT_DIRENT * dp = NULL ;
files_struct fake_fs ;
struct fd_handle fake_fh ;
SMB_STRUCT_STAT stream_sbuf ;
ZERO_STRUCT ( fake_fh ) ;
ZERO_STRUCT ( fake_fs ) ;
/* If the base file is already open, use its fd. */
if ( ( fsp ! = NULL ) & & ( fsp - > fh - > fd ! = - 1 ) ) {
base_fd = fsp - > fh - > fd ;
} else {
opened_base_fd = true ;
}
dir_fd = get_stream_dir_fd ( conn , fname , & base_fd ) ;
if ( dir_fd < 0 ) {
return map_nt_error_from_unix ( errno ) ;
}
/* Open the ADS directory. */
if ( ( dirp = fdopendir ( dir_fd ) ) = = NULL ) {
DEBUG ( 0 , ( " Error on opendir %s. errno=%d (%s) \n " ,
fname , errno , strerror ( errno ) ) ) ;
status = map_nt_error_from_unix ( errno ) ;
goto out ;
}
2009-02-19 04:36:25 +03:00
/* Initialize the dir state struct and add it to the list.
* This is a layer violation , and really should be handled by a
* VFS_FDOPENDIR ( ) call which would properly setup the dir state .
* But since this is all within the onefs . so module , we cheat for
* now and call directly into the readdirplus code .
* NOTE : This state MUST be freed by a proper VFS_CLOSEDIR ( ) call . */
ret = onefs_rdp_add_dir_state ( conn , dirp ) ;
if ( ret ) {
DEBUG ( 0 , ( " Error adding dir_state to the list \n " ) ) ;
status = map_nt_error_from_unix ( errno ) ;
goto out ;
}
2008-12-13 01:32:48 +03:00
fake_fs . conn = conn ;
fake_fs . fh = & fake_fh ;
2009-07-11 05:11:32 +04:00
status = create_synthetic_smb_fname ( talloc_tos ( ) , fname , NULL , NULL ,
& fake_fs . fsp_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
2008-12-13 01:32:48 +03:00
/* Iterate over the streams in the ADS directory. */
2009-01-23 07:14:38 +03:00
while ( ( dp = SMB_VFS_READDIR ( conn , dirp , NULL ) ) ! = NULL ) {
2008-12-13 01:32:48 +03:00
/* Skip the "." and ".." entries */
if ( ( strcmp ( dp - > d_name , " . " ) = = 0 ) | |
( strcmp ( dp - > d_name , " .. " ) = = 0 ) )
continue ;
/* Open actual stream */
if ( ( stream_fd = onefs_sys_create_file ( conn ,
base_fd ,
dp - > d_name ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
INTERNAL_OPEN_ONLY ,
0 ,
NULL ,
0 ,
NULL ) ) = = - 1 ) {
DEBUG ( 0 , ( " Error opening stream %s:%s. "
" errno=%d (%s) \n " , fname , dp - > d_name , errno ,
strerror ( errno ) ) ) ;
continue ;
}
/* Figure out the stat info. */
fake_fh . fd = stream_fd ;
ret = SMB_VFS_FSTAT ( & fake_fs , & stream_sbuf ) ;
close ( stream_fd ) ;
if ( ret ) {
DEBUG ( 0 , ( " Error fstating stream %s:%s. "
" errno=%d (%s) \n " , fname , dp - > d_name , errno ,
strerror ( errno ) ) ) ;
continue ;
}
merge_stat ( & stream_sbuf , base_sbuf ) ;
if ( ! add_one_stream ( state - > mem_ctx ,
& state - > num_streams , & state - > streams ,
2009-05-29 01:11:43 +04:00
dp - > d_name , stream_sbuf . st_ex_size ,
2009-01-27 02:39:40 +03:00
SMB_VFS_GET_ALLOC_SIZE ( conn , NULL ,
& stream_sbuf ) ) ) {
2008-12-13 01:32:48 +03:00
state - > status = NT_STATUS_NO_MEMORY ;
break ;
}
}
out :
/* Cleanup everything that was opened. */
if ( dirp ! = NULL ) {
SMB_VFS_CLOSEDIR ( conn , dirp ) ;
}
if ( dir_fd > = 0 ) {
close ( dir_fd ) ;
}
if ( opened_base_fd ) {
SMB_ASSERT ( base_fd > = 0 ) ;
close ( base_fd ) ;
}
2009-07-11 05:11:32 +04:00
TALLOC_FREE ( fake_fs . fsp_name ) ;
2008-12-13 01:32:48 +03:00
return status ;
}
NTSTATUS onefs_streaminfo ( vfs_handle_struct * handle ,
struct files_struct * fsp ,
const char * fname ,
TALLOC_CTX * mem_ctx ,
unsigned int * num_streams ,
struct stream_struct * * streams )
{
SMB_STRUCT_STAT sbuf ;
int ret ;
NTSTATUS status ;
struct streaminfo_state state ;
/* Get a valid stat. */
if ( ( fsp ! = NULL ) & & ( fsp - > fh - > fd ! = - 1 ) ) {
ret = SMB_VFS_FSTAT ( fsp , & sbuf ) ;
} else {
2009-06-25 22:20:36 +04:00
struct smb_filename * smb_fname = NULL ;
status = create_synthetic_smb_fname ( talloc_tos ( ) , fname , NULL ,
NULL , & smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
ret = SMB_VFS_STAT ( handle - > conn , smb_fname ) ;
sbuf = smb_fname - > st ;
TALLOC_FREE ( smb_fname ) ;
2008-12-13 01:32:48 +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-12-13 01:32:48 +03:00
2009-02-28 03:25:31 +03:00
if ( lp_parm_bool ( SNUM ( handle - > conn ) , PARM_ONEFS_TYPE ,
PARM_IGNORE_STREAMS , PARM_IGNORE_STREAMS_DEFAULT ) ) {
goto out ;
}
2008-12-13 01:32:48 +03:00
state . mem_ctx = mem_ctx ;
state . handle = handle ;
state . status = NT_STATUS_OK ;
/* If there are more streams, add them too. */
2009-05-29 01:11:43 +04:00
if ( sbuf . st_ex_flags & UF_HASADS ) {
2008-12-13 01:32:48 +03:00
status = walk_onefs_streams ( handle - > conn , fsp , fname ,
& state , & sbuf ) ;
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 ;
}
}
2009-02-28 03:25:31 +03:00
out :
2008-12-13 01:32:48 +03:00
* num_streams = state . num_streams ;
* streams = state . streams ;
2011-10-14 02:41:53 +04:00
return SMB_VFS_NEXT_STREAMINFO ( handle , fsp , fname , mem_ctx , pnum_streams , pstreams ) ;
2008-12-13 01:32:48 +03:00
}