2019-03-26 18:35:18 +03:00
/*
* Module for accessing CephFS snapshots as Previous Versions . This module is
* separate to vfs_ceph , so that it can also be used atop a CephFS kernel backed
* share with vfs_default .
*
* Copyright ( C ) David Disseldorp 2019
*
* 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 <dirent.h>
# include <libgen.h>
# include "includes.h"
# include "include/ntioctl.h"
# include "include/smb.h"
# include "system/filesys.h"
# include "smbd/smbd.h"
# include "lib/util/tevent_ntstatus.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
/*
* CephFS has a magic snapshots subdirectory in all parts of the directory tree .
* This module automatically makes all snapshots in this subdir visible to SMB
* clients ( if permitted by corresponding access control ) .
*/
# define CEPH_SNAP_SUBDIR_DEFAULT ".snap"
/*
* The ceph . snap . btime ( virtual ) extended attribute carries the snapshot
* creation time in $ secs . $ nsecs format . It was added as part of
* https : //tracker.ceph.com/issues/38838. Running Samba atop old Ceph versions
* which don ' t provide this xattr will not be able to enumerate or access
* snapshots using this module . As an alternative , vfs_shadow_copy2 could be
* used instead , alongside special shadow : format snapshot directory names .
*/
# define CEPH_SNAP_BTIME_XATTR "ceph.snap.btime"
static int ceph_snap_get_btime ( struct vfs_handle_struct * handle ,
struct smb_filename * smb_fname ,
time_t * _snap_secs )
{
int ret ;
char snap_btime [ 33 ] ;
char * s = NULL ;
char * endptr = NULL ;
struct timespec snap_timespec ;
int err ;
ret = SMB_VFS_NEXT_GETXATTR ( handle , smb_fname , CEPH_SNAP_BTIME_XATTR ,
snap_btime , sizeof ( snap_btime ) ) ;
if ( ret < 0 ) {
DBG_ERR ( " failed to get %s xattr: %s \n " ,
CEPH_SNAP_BTIME_XATTR , strerror ( errno ) ) ;
return - errno ;
}
if ( ret = = 0 | | ret > = sizeof ( snap_btime ) - 1 ) {
return - EINVAL ;
}
/* ensure zero termination */
snap_btime [ ret ] = ' \0 ' ;
/* format is sec.nsec */
s = strchr ( snap_btime , ' . ' ) ;
if ( s = = NULL ) {
DBG_ERR ( " invalid %s xattr value: %s \n " ,
CEPH_SNAP_BTIME_XATTR , snap_btime ) ;
return - EINVAL ;
}
/* First component is seconds, extract it */
* s = ' \0 ' ;
2019-06-04 10:04:15 +03:00
snap_timespec . tv_sec = smb_strtoull ( snap_btime ,
& endptr ,
10 ,
& err ,
SMB_STR_FULL_STR_CONV ) ;
2019-03-26 18:35:18 +03:00
if ( err ! = 0 ) {
return - err ;
}
/* second component is nsecs */
s + + ;
2019-06-04 10:04:15 +03:00
snap_timespec . tv_nsec = smb_strtoul ( s ,
& endptr ,
10 ,
& err ,
SMB_STR_FULL_STR_CONV ) ;
2019-03-26 18:35:18 +03:00
if ( err ! = 0 ) {
return - err ;
}
/*
* > > 30 is a rough divide by ~ 10 * * 9. No need to be exact , as @ GMT
* tokens only offer 1 - second resolution ( while twrp is nsec ) .
*/
* _snap_secs = snap_timespec . tv_sec + ( snap_timespec . tv_nsec > > 30 ) ;
return 0 ;
}
/*
* XXX Ceph snapshots can be created with sub - second granularity , which means
* that multiple snapshots may be mapped to the same @ GMT - label .
*
* @ this_label is a pre - zeroed buffer to be filled with a @ GMT label
* @ return 0 if label successfully filled or - errno on error .
*/
static int ceph_snap_fill_label ( struct vfs_handle_struct * handle ,
TALLOC_CTX * tmp_ctx ,
const char * parent_snapsdir ,
const char * subdir ,
SHADOW_COPY_LABEL this_label )
{
struct smb_filename * smb_fname ;
time_t snap_secs ;
struct tm gmt_snap_time ;
struct tm * tm_ret ;
size_t str_sz ;
char snap_path [ PATH_MAX + 1 ] ;
int ret ;
/*
* CephFS snapshot creation times are available via a special
* xattr - snapshot b / m / ctimes all match the snap source .
*/
ret = snprintf ( snap_path , sizeof ( snap_path ) , " %s/%s " ,
parent_snapsdir , subdir ) ;
if ( ret > = sizeof ( snap_path ) ) {
return - EINVAL ;
}
2020-05-03 09:32:53 +03:00
smb_fname = synthetic_smb_fname ( tmp_ctx ,
snap_path ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2020-05-03 09:32:53 +03:00
0 ) ;
2019-03-26 18:35:18 +03:00
if ( smb_fname = = NULL ) {
return - ENOMEM ;
}
ret = ceph_snap_get_btime ( handle , smb_fname , & snap_secs ) ;
if ( ret < 0 ) {
return ret ;
}
tm_ret = gmtime_r ( & snap_secs , & gmt_snap_time ) ;
if ( tm_ret = = NULL ) {
return - EINVAL ;
}
str_sz = strftime ( this_label , sizeof ( SHADOW_COPY_LABEL ) ,
" @GMT-%Y.%m.%d-%H.%M.%S " , & gmt_snap_time ) ;
if ( str_sz = = 0 ) {
DBG_ERR ( " failed to convert tm to @GMT token \n " ) ;
return - EINVAL ;
}
DBG_DEBUG ( " mapped snapshot at %s to enum snaps label %s \n " ,
snap_path , this_label ) ;
return 0 ;
}
static int ceph_snap_enum_snapdir ( struct vfs_handle_struct * handle ,
struct smb_filename * snaps_dname ,
bool labels ,
struct shadow_copy_data * sc_data )
{
2020-03-19 14:03:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct smb_Dir * dir_hnd = NULL ;
const char * dname = NULL ;
char * talloced = NULL ;
long offset = 0 ;
2019-03-26 18:35:18 +03:00
NTSTATUS status ;
int ret ;
uint32_t slots ;
status = smbd_check_access_rights ( handle - > conn ,
2020-05-01 02:02:43 +03:00
handle - > conn - > cwd_fsp ,
2019-03-26 18:35:18 +03:00
snaps_dname ,
false ,
SEC_DIR_LIST ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " user does not have list permission "
" on snapdir %s \n " ,
snaps_dname - > base_name ) ) ;
ret = - map_errno_from_nt_status ( status ) ;
goto err_out ;
}
DBG_DEBUG ( " enumerating shadow copy dir at %s \n " ,
snaps_dname - > base_name ) ;
/*
* CephFS stat ( dir ) . size * normally * returns the number of child entries
* for a given dir , but it unfortunately that ' s not the case for the one
* place we need it ( dir = . snap ) , so we need to dynamically determine it
* via readdir .
*/
2020-03-19 14:03:27 +03:00
dir_hnd = OpenDir ( frame , handle - > conn , snaps_dname , NULL , 0 ) ;
if ( dir_hnd = = NULL ) {
2019-03-26 18:35:18 +03:00
ret = - errno ;
goto err_out ;
}
slots = 0 ;
sc_data - > num_volumes = 0 ;
sc_data - > labels = NULL ;
2020-03-19 14:03:27 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & offset , NULL , & talloced ) )
! = NULL )
{
if ( ISDOT ( dname ) | | ISDOTDOT ( dname ) ) {
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
continue ;
}
sc_data - > num_volumes + + ;
if ( ! labels ) {
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
continue ;
}
if ( sc_data - > num_volumes > slots ) {
uint32_t new_slot_count = slots + 10 ;
SMB_ASSERT ( new_slot_count > slots ) ;
sc_data - > labels = talloc_realloc ( sc_data ,
sc_data - > labels ,
SHADOW_COPY_LABEL ,
new_slot_count ) ;
if ( sc_data - > labels = = NULL ) {
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
ret = - ENOMEM ;
goto err_closedir ;
}
memset ( sc_data - > labels [ slots ] , 0 ,
sizeof ( SHADOW_COPY_LABEL ) * 10 ) ;
DBG_DEBUG ( " %d->%d slots for enum_snaps response \n " ,
slots , new_slot_count ) ;
slots = new_slot_count ;
}
DBG_DEBUG ( " filling shadow copy label for %s/%s \n " ,
2020-03-19 14:03:27 +03:00
snaps_dname - > base_name , dname ) ;
2019-03-26 18:35:18 +03:00
ret = ceph_snap_fill_label ( handle , snaps_dname ,
2020-03-19 14:03:27 +03:00
snaps_dname - > base_name , dname ,
2019-03-26 18:35:18 +03:00
sc_data - > labels [ sc_data - > num_volumes - 1 ] ) ;
if ( ret < 0 ) {
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
goto err_closedir ;
}
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
}
DBG_DEBUG ( " %s shadow copy enumeration found %d labels \n " ,
snaps_dname - > base_name , sc_data - > num_volumes ) ;
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( frame ) ;
2019-03-26 18:35:18 +03:00
return 0 ;
err_closedir :
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( frame ) ;
2019-03-26 18:35:18 +03:00
err_out :
TALLOC_FREE ( sc_data - > labels ) ;
return ret ;
}
/*
* Prior reading : The Meaning of Path Names
* https : //wiki.samba.org/index.php/Writing_a_Samba_VFS_Module
*
* translate paths so that we can use the parent dir for . snap access :
* myfile - > parent = trimmed = myfile
* / a - > parent = / trimmed = a
* dir / sub / file - > parent = dir / sub trimmed = file
* / dir / sub - > parent = / dir / trimmed = sub
*/
static int ceph_snap_get_parent_path ( const char * connectpath ,
const char * path ,
char * _parent_buf ,
size_t buflen ,
const char * * _trimmed )
{
const char * p ;
size_t len ;
int ret ;
if ( ! strcmp ( path , " / " ) ) {
DBG_ERR ( " can't go past root for %s .snap dir \n " , path ) ;
return - EINVAL ;
}
p = strrchr_m ( path , ' / ' ) ; /* Find final '/', if any */
if ( p = = NULL ) {
DBG_DEBUG ( " parent .snap dir for %s is cwd \n " , path ) ;
ret = strlcpy ( _parent_buf , " " , buflen ) ;
if ( ret > = buflen ) {
return - EINVAL ;
}
if ( _trimmed ! = NULL ) {
* _trimmed = path ;
}
return 0 ;
}
SMB_ASSERT ( p > = path ) ;
len = p - path ;
ret = snprintf ( _parent_buf , buflen , " %.*s " , ( int ) len , path ) ;
if ( ret > = buflen ) {
return - EINVAL ;
}
/* for absolute paths, check that we're not going outside the share */
if ( ( len > 0 ) & & ( _parent_buf [ 0 ] = = ' / ' ) ) {
bool connectpath_match = false ;
size_t clen = strlen ( connectpath ) ;
DBG_DEBUG ( " checking absolute path %s lies within share at %s \n " ,
_parent_buf , connectpath ) ;
/* need to check for separator, to avoid /x/abcd vs /x/ab */
connectpath_match = ( strncmp ( connectpath ,
_parent_buf ,
clen ) = = 0 ) ;
if ( ! connectpath_match
| | ( ( _parent_buf [ clen ] ! = ' / ' ) & & ( _parent_buf [ clen ] ! = ' \0 ' ) ) ) {
DBG_ERR ( " %s parent path is outside of share at %s \n " ,
_parent_buf , connectpath ) ;
return - EINVAL ;
}
}
if ( _trimmed ! = NULL ) {
/*
* point to path component which was trimmed from _parent_buf
* excluding path separator .
*/
* _trimmed = p + 1 ;
}
DBG_DEBUG ( " generated parent .snap path for %s as %s (trimmed \" %s \" ) \n " ,
path , _parent_buf , p + 1 ) ;
return 0 ;
}
static int ceph_snap_get_shadow_copy_data ( struct vfs_handle_struct * handle ,
struct files_struct * fsp ,
struct shadow_copy_data * sc_data ,
bool labels )
{
int ret ;
TALLOC_CTX * tmp_ctx ;
const char * parent_dir = NULL ;
char tmp [ PATH_MAX + 1 ] ;
char snaps_path [ PATH_MAX + 1 ] ;
struct smb_filename * snaps_dname = NULL ;
const char * snapdir = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" ceph " , " snapdir " ,
CEPH_SNAP_SUBDIR_DEFAULT ) ;
DBG_DEBUG ( " getting shadow copy data for %s \n " ,
fsp - > fsp_name - > base_name ) ;
tmp_ctx = talloc_new ( fsp ) ;
if ( tmp_ctx = = NULL ) {
ret = - ENOMEM ;
goto err_out ;
}
if ( sc_data = = NULL ) {
ret = - EINVAL ;
goto err_out ;
}
2020-04-02 19:21:11 +03:00
if ( fsp - > fsp_flags . is_directory ) {
2019-03-26 18:35:18 +03:00
parent_dir = fsp - > fsp_name - > base_name ;
} else {
ret = ceph_snap_get_parent_path ( handle - > conn - > connectpath ,
fsp - > fsp_name - > base_name ,
tmp ,
sizeof ( tmp ) ,
NULL ) ; /* trimmed */
if ( ret < 0 ) {
goto err_out ;
}
parent_dir = tmp ;
}
2019-12-13 00:14:50 +03:00
if ( strlen ( parent_dir ) = = 0 ) {
ret = strlcpy ( snaps_path , snapdir , sizeof ( snaps_path ) ) ;
} else {
ret = snprintf ( snaps_path , sizeof ( snaps_path ) , " %s/%s " ,
parent_dir , snapdir ) ;
}
2019-03-26 18:35:18 +03:00
if ( ret > = sizeof ( snaps_path ) ) {
ret = - EINVAL ;
goto err_out ;
}
snaps_dname = synthetic_smb_fname ( tmp_ctx ,
snaps_path ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2019-03-26 18:35:18 +03:00
fsp - > fsp_name - > flags ) ;
if ( snaps_dname = = NULL ) {
ret = - ENOMEM ;
goto err_out ;
}
ret = ceph_snap_enum_snapdir ( handle , snaps_dname , labels , sc_data ) ;
if ( ret < 0 ) {
goto err_out ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
err_out :
talloc_free ( tmp_ctx ) ;
errno = - ret ;
return - 1 ;
}
2020-05-04 11:19:35 +03:00
static int ceph_snap_gmt_strip_snapshot ( struct vfs_handle_struct * handle ,
2020-05-02 12:39:58 +03:00
const struct smb_filename * smb_fname ,
2019-03-26 18:35:18 +03:00
time_t * _timestamp ,
char * _stripped_buf ,
size_t buflen )
{
2020-05-04 11:21:41 +03:00
size_t len ;
2019-03-26 18:35:18 +03:00
2020-05-02 12:45:11 +03:00
if ( smb_fname - > twrp = = 0 ) {
goto no_snapshot ;
}
2019-03-26 18:35:18 +03:00
if ( _stripped_buf ! = NULL ) {
2020-05-04 11:21:41 +03:00
len = strlcpy ( _stripped_buf , smb_fname - > base_name , buflen ) ;
if ( len > = buflen ) {
return - ENAMETOOLONG ;
2019-03-26 18:35:18 +03:00
}
}
2020-05-04 11:21:41 +03:00
2020-05-02 12:45:11 +03:00
* _timestamp = nt_time_to_unix ( smb_fname - > twrp ) ;
2019-03-26 18:35:18 +03:00
return 0 ;
no_snapshot :
* _timestamp = 0 ;
return 0 ;
}
static int ceph_snap_gmt_convert_dir ( struct vfs_handle_struct * handle ,
const char * name ,
time_t timestamp ,
char * _converted_buf ,
size_t buflen )
{
int ret ;
NTSTATUS status ;
2020-03-19 14:03:27 +03:00
struct smb_Dir * dir_hnd = NULL ;
const char * dname = NULL ;
char * talloced = NULL ;
long offset = 0 ;
2019-03-26 18:35:18 +03:00
struct smb_filename * snaps_dname = NULL ;
const char * snapdir = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" ceph " , " snapdir " ,
CEPH_SNAP_SUBDIR_DEFAULT ) ;
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
if ( tmp_ctx = = NULL ) {
ret = - ENOMEM ;
goto err_out ;
}
/*
* Temporally use the caller ' s return buffer for this .
*/
2019-12-13 00:14:50 +03:00
if ( strlen ( name ) = = 0 ) {
ret = strlcpy ( _converted_buf , snapdir , buflen ) ;
} else {
ret = snprintf ( _converted_buf , buflen , " %s/%s " , name , snapdir ) ;
}
2019-03-26 18:35:18 +03:00
if ( ret > = buflen ) {
ret = - EINVAL ;
goto err_out ;
}
snaps_dname = synthetic_smb_fname ( tmp_ctx ,
_converted_buf ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2019-03-26 18:35:18 +03:00
0 ) ; /* XXX check? */
if ( snaps_dname = = NULL ) {
ret = - ENOMEM ;
goto err_out ;
}
/* stat first to trigger error fallback in ceph_snap_gmt_convert() */
ret = SMB_VFS_NEXT_STAT ( handle , snaps_dname ) ;
if ( ret < 0 ) {
ret = - errno ;
goto err_out ;
}
status = smbd_check_access_rights ( handle - > conn ,
2020-05-01 02:02:43 +03:00
handle - > conn - > cwd_fsp ,
2019-03-26 18:35:18 +03:00
snaps_dname ,
false ,
SEC_DIR_LIST ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " user does not have list permission "
" on snapdir %s \n " ,
snaps_dname - > base_name ) ) ;
ret = - map_errno_from_nt_status ( status ) ;
goto err_out ;
}
DBG_DEBUG ( " enumerating shadow copy dir at %s \n " ,
snaps_dname - > base_name ) ;
2020-03-19 14:03:27 +03:00
dir_hnd = OpenDir ( tmp_ctx , handle - > conn , snaps_dname , NULL , 0 ) ;
if ( dir_hnd = = NULL ) {
2019-03-26 18:35:18 +03:00
ret = - errno ;
goto err_out ;
}
2020-03-19 14:03:27 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & offset , NULL , & talloced ) )
! = NULL )
{
2019-03-26 18:35:18 +03:00
struct smb_filename * smb_fname ;
time_t snap_secs ;
2020-03-19 14:03:27 +03:00
if ( ISDOT ( dname ) | | ISDOTDOT ( dname ) ) {
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
continue ;
}
ret = snprintf ( _converted_buf , buflen , " %s/%s " ,
2020-03-19 14:03:27 +03:00
snaps_dname - > base_name , dname ) ;
2019-03-26 18:35:18 +03:00
if ( ret > = buflen ) {
ret = - EINVAL ;
2020-03-19 14:03:27 +03:00
goto err_out ;
2019-03-26 18:35:18 +03:00
}
2020-05-03 09:33:51 +03:00
smb_fname = synthetic_smb_fname ( tmp_ctx ,
_converted_buf ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2020-05-03 09:33:51 +03:00
0 ) ;
2019-03-26 18:35:18 +03:00
if ( smb_fname = = NULL ) {
ret = - ENOMEM ;
2020-03-19 14:03:27 +03:00
goto err_out ;
2019-03-26 18:35:18 +03:00
}
ret = ceph_snap_get_btime ( handle , smb_fname , & snap_secs ) ;
if ( ret < 0 ) {
2020-03-19 14:03:27 +03:00
goto err_out ;
2019-03-26 18:35:18 +03:00
}
/*
* check gmt_snap_time matches @ timestamp
*/
if ( timestamp = = snap_secs ) {
break ;
}
DBG_DEBUG ( " [connectpath %s] %s@%lld no match for snap %s@%lld \n " ,
handle - > conn - > connectpath , name , ( long long ) timestamp ,
2020-03-19 14:03:27 +03:00
dname , ( long long ) snap_secs ) ;
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
}
2020-03-19 14:03:27 +03:00
if ( dname = = NULL ) {
2019-03-26 18:35:18 +03:00
DBG_INFO ( " [connectpath %s] failed to find %s @ time %lld \n " ,
handle - > conn - > connectpath , name , ( long long ) timestamp ) ;
ret = - ENOENT ;
2020-03-19 14:03:27 +03:00
goto err_out ;
2019-03-26 18:35:18 +03:00
}
/* found, _converted_buf already contains path of interest */
DBG_DEBUG ( " [connectpath %s] converted %s @ time %lld to %s \n " ,
handle - > conn - > connectpath , name , ( long long ) timestamp ,
_converted_buf ) ;
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
talloc_free ( tmp_ctx ) ;
return 0 ;
err_out :
2020-03-19 14:03:27 +03:00
TALLOC_FREE ( talloced ) ;
2019-03-26 18:35:18 +03:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
static int ceph_snap_gmt_convert ( struct vfs_handle_struct * handle ,
const char * name ,
time_t timestamp ,
char * _converted_buf ,
size_t buflen )
{
int ret ;
char parent [ PATH_MAX + 1 ] ;
const char * trimmed = NULL ;
/*
* CephFS Snapshots for a given dir are nested under the . / . snap subdir
* * or * under . . / . snap / dir ( and subsequent parent dirs ) .
* Child dirs inherit snapshots created in parent dirs if the child
* exists at the time of snapshot creation .
*
* At this point we don ' t know whether @ name refers to a file or dir , so
* first assume it ' s a dir ( with a corresponding . snaps subdir )
*/
ret = ceph_snap_gmt_convert_dir ( handle ,
name ,
timestamp ,
_converted_buf ,
buflen ) ;
if ( ret > = 0 ) {
/* all done: .snap subdir exists - @name is a dir */
DBG_DEBUG ( " %s is a dir, accessing snaps via .snap \n " , name ) ;
return ret ;
}
/* @name/.snap access failed, attempt snapshot access via parent */
DBG_DEBUG ( " %s/.snap access failed, attempting parent access \n " ,
name ) ;
ret = ceph_snap_get_parent_path ( handle - > conn - > connectpath ,
name ,
parent ,
sizeof ( parent ) ,
& trimmed ) ;
if ( ret < 0 ) {
return ret ;
}
ret = ceph_snap_gmt_convert_dir ( handle ,
parent ,
timestamp ,
_converted_buf ,
buflen ) ;
if ( ret < 0 ) {
return ret ;
}
/*
* found snapshot via parent . Append the child path component
* that was trimmed . . . + 1 for path separator + 1 for null termination .
*/
if ( strlen ( _converted_buf ) + 1 + strlen ( trimmed ) + 1 > buflen ) {
return - EINVAL ;
}
strlcat ( _converted_buf , " / " , buflen ) ;
strlcat ( _converted_buf , trimmed , buflen ) ;
return 0 ;
}
2019-08-09 23:49:46 +03:00
static int ceph_snap_gmt_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 )
{
int ret ;
time_t timestamp_src , timestamp_dst ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
smb_fname_src ,
2019-08-09 23:49:46 +03:00
& timestamp_src , NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
smb_fname_dst ,
2019-08-09 23:49:46 +03:00
& timestamp_dst , NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp_src ! = 0 ) {
errno = EXDEV ;
return - 1 ;
}
if ( timestamp_dst ! = 0 ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_RENAMEAT ( handle ,
srcfsp ,
smb_fname_src ,
dstfsp ,
smb_fname_dst ) ;
}
2019-03-26 18:35:18 +03:00
/* block links from writeable shares to snapshots for now, like other modules */
2019-08-30 23:16:01 +03:00
static int ceph_snap_gmt_symlinkat ( vfs_handle_struct * handle ,
2020-04-30 20:30:50 +03:00
const struct smb_filename * link_contents ,
2019-08-30 23:16:01 +03:00
struct files_struct * dirfsp ,
const struct smb_filename * new_smb_fname )
{
int ret ;
time_t timestamp_old = 0 ;
time_t timestamp_new = 0 ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
link_contents ,
2019-08-30 23:16:01 +03:00
& timestamp_old ,
NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
new_smb_fname ,
2019-08-30 23:16:01 +03:00
& timestamp_new ,
NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( ( timestamp_old ! = 0 ) | | ( timestamp_new ! = 0 ) ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_SYMLINKAT ( handle ,
link_contents ,
dirfsp ,
new_smb_fname ) ;
}
2019-08-14 21:38:23 +03:00
static int ceph_snap_gmt_linkat ( vfs_handle_struct * handle ,
files_struct * srcfsp ,
const struct smb_filename * old_smb_fname ,
files_struct * dstfsp ,
const struct smb_filename * new_smb_fname ,
int flags )
{
int ret ;
time_t timestamp_old = 0 ;
time_t timestamp_new = 0 ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
old_smb_fname ,
2019-08-14 21:38:23 +03:00
& timestamp_old ,
NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
new_smb_fname ,
2019-08-14 21:38:23 +03:00
& timestamp_new ,
NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( ( timestamp_old ! = 0 ) | | ( timestamp_new ! = 0 ) ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_LINKAT ( handle ,
srcfsp ,
old_smb_fname ,
dstfsp ,
new_smb_fname ,
flags ) ;
}
2019-03-26 18:35:18 +03:00
static int ceph_snap_gmt_stat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
char * tmp ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
smb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
tmp = smb_fname - > base_name ;
smb_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
smb_fname - > base_name = tmp ;
return ret ;
}
static int ceph_snap_gmt_lstat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
char * tmp ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
smb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
tmp = smb_fname - > base_name ;
smb_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
smb_fname - > base_name = tmp ;
return ret ;
}
static int ceph_snap_gmt_open ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname , files_struct * fsp ,
int flags , mode_t mode )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
char * tmp ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
smb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
tmp = smb_fname - > base_name ;
smb_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
smb_fname - > base_name = tmp ;
return ret ;
}
2019-09-12 20:05:00 +03:00
static int ceph_snap_gmt_unlinkat ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * csmb_fname ,
int flags )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-09-12 20:05:00 +03:00
& timestamp , NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp ! = 0 ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
csmb_fname ,
flags ) ;
}
2019-03-26 18:35:18 +03:00
static int ceph_snap_gmt_chmod ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
mode_t mode )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-09 01:47:44 +03:00
& timestamp , NULL , 0 ) ;
2019-03-26 18:35:18 +03:00
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
2019-08-09 01:47:44 +03:00
if ( timestamp ! = 0 ) {
errno = EROFS ;
2019-03-26 18:35:18 +03:00
return - 1 ;
}
2019-08-09 01:47:44 +03:00
return SMB_VFS_NEXT_CHMOD ( handle , csmb_fname , mode ) ;
2019-03-26 18:35:18 +03:00
}
static int ceph_snap_gmt_chdir ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_CHDIR ( handle , csmb_fname ) ;
}
ret = ceph_snap_gmt_convert_dir ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
new_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_CHDIR ( handle , new_fname ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return ret ;
}
static int ceph_snap_gmt_ntimes ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
struct smb_file_time * ft )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-09 01:52:14 +03:00
& timestamp , NULL , 0 ) ;
2019-03-26 18:35:18 +03:00
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
2019-08-09 01:52:14 +03:00
if ( timestamp ! = 0 ) {
errno = EROFS ;
2019-03-26 18:35:18 +03:00
return - 1 ;
}
2019-08-09 01:52:14 +03:00
return SMB_VFS_NEXT_NTIMES ( handle , csmb_fname , ft ) ;
2019-03-26 18:35:18 +03:00
}
2019-08-23 00:10:31 +03:00
static int ceph_snap_gmt_readlinkat ( vfs_handle_struct * handle ,
files_struct * dirfsp ,
const struct smb_filename * csmb_fname ,
char * buf ,
size_t bufsiz )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-23 00:10:31 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_READLINKAT ( handle ,
dirfsp ,
csmb_fname ,
buf ,
bufsiz ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
new_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_READLINKAT ( handle ,
dirfsp ,
new_fname ,
buf ,
bufsiz ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return ret ;
}
2019-08-21 02:52:36 +03:00
static int ceph_snap_gmt_mknodat ( vfs_handle_struct * handle ,
files_struct * dirfsp ,
const struct smb_filename * csmb_fname ,
mode_t mode ,
SMB_DEV_T dev )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-21 02:52:36 +03:00
& timestamp , NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp ! = 0 ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_MKNODAT ( handle ,
dirfsp ,
csmb_fname ,
mode ,
dev ) ;
}
2019-03-26 18:35:18 +03:00
static struct smb_filename * ceph_snap_gmt_realpath ( vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
const struct smb_filename * csmb_fname )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
struct smb_filename * result_fname ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return NULL ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_REALPATH ( handle , ctx , csmb_fname ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return NULL ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return NULL ;
}
new_fname - > base_name = conv ;
result_fname = SMB_VFS_NEXT_REALPATH ( handle , ctx , new_fname ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return result_fname ;
}
static NTSTATUS ceph_snap_gmt_get_nt_acl ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
uint32_t security_info ,
TALLOC_CTX * mem_ctx ,
struct security_descriptor * * ppdesc )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
NTSTATUS status ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
return map_nt_error_from_unix ( - ret ) ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GET_NT_ACL ( handle , csmb_fname , security_info ,
mem_ctx , ppdesc ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
return map_nt_error_from_unix ( - ret ) ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
new_fname - > base_name = conv ;
status = SMB_VFS_NEXT_GET_NT_ACL ( handle , new_fname , security_info ,
mem_ctx , ppdesc ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return status ;
}
2019-09-05 01:43:44 +03:00
static int ceph_snap_gmt_mkdirat ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * csmb_fname ,
mode_t mode )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-09-05 01:43:44 +03:00
& timestamp , NULL , 0 ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp ! = 0 ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_MKDIRAT ( handle ,
dirfsp ,
csmb_fname ,
mode ) ;
}
2019-03-26 18:35:18 +03:00
static int ceph_snap_gmt_chflags ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
unsigned int flags )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-09 01:56:59 +03:00
& timestamp , NULL , 0 ) ;
2019-03-26 18:35:18 +03:00
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
2019-08-09 01:56:59 +03:00
if ( timestamp ! = 0 ) {
errno = EROFS ;
2019-03-26 18:35:18 +03:00
return - 1 ;
}
2019-08-09 01:56:59 +03:00
return SMB_VFS_NEXT_CHFLAGS ( handle , csmb_fname , flags ) ;
2019-03-26 18:35:18 +03:00
}
static ssize_t ceph_snap_gmt_getxattr ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
const char * aname ,
void * value ,
size_t size )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GETXATTR ( handle , csmb_fname , aname , value ,
size ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
new_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_GETXATTR ( handle , new_fname , aname , value , size ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return ret ;
}
static ssize_t ceph_snap_gmt_listxattr ( struct vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
char * list , size_t size )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_LISTXATTR ( handle , csmb_fname , list , size ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
new_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_LISTXATTR ( handle , new_fname , list , size ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return ret ;
}
static int ceph_snap_gmt_removexattr ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
const char * aname )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-09 01:58:10 +03:00
& timestamp , NULL , 0 ) ;
2019-03-26 18:35:18 +03:00
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
2019-08-09 01:58:10 +03:00
if ( timestamp ! = 0 ) {
errno = EROFS ;
2019-03-26 18:35:18 +03:00
return - 1 ;
}
2019-08-09 01:58:10 +03:00
return SMB_VFS_NEXT_REMOVEXATTR ( handle , csmb_fname , aname ) ;
2019-03-26 18:35:18 +03:00
}
static int ceph_snap_gmt_setxattr ( struct vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
const char * aname , const void * value ,
size_t size , int flags )
{
time_t timestamp = 0 ;
int ret ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-08-09 01:59:15 +03:00
& timestamp , NULL , 0 ) ;
2019-03-26 18:35:18 +03:00
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
2019-08-09 01:59:15 +03:00
if ( timestamp ! = 0 ) {
errno = EROFS ;
2019-03-26 18:35:18 +03:00
return - 1 ;
}
2019-08-09 01:59:15 +03:00
return SMB_VFS_NEXT_SETXATTR ( handle , csmb_fname ,
2019-03-26 18:35:18 +03:00
aname , value , size , flags ) ;
}
static int ceph_snap_gmt_get_real_filename ( struct vfs_handle_struct * handle ,
2020-04-30 17:40:28 +03:00
const struct smb_filename * path ,
2019-03-26 18:35:18 +03:00
const char * name ,
TALLOC_CTX * mem_ctx ,
char * * found_name )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
2020-04-30 17:40:28 +03:00
struct smb_filename conv_fname ;
2019-03-26 18:35:18 +03:00
int ret ;
2020-05-02 12:39:58 +03:00
ret = ceph_snap_gmt_strip_snapshot ( handle , path ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GET_REAL_FILENAME ( handle , path , name ,
mem_ctx , found_name ) ;
}
ret = ceph_snap_gmt_convert_dir ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
2020-04-30 17:40:28 +03:00
conv_fname = ( struct smb_filename ) {
. base_name = conv ,
} ;
ret = SMB_VFS_NEXT_GET_REAL_FILENAME ( handle , & conv_fname , name ,
2019-03-26 18:35:18 +03:00
mem_ctx , found_name ) ;
return ret ;
}
static uint64_t ceph_snap_gmt_disk_free ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
uint64_t * bsize ,
uint64_t * dfree ,
uint64_t * dsize )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_DISK_FREE ( handle , csmb_fname ,
bsize , dfree , dsize ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
new_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_DISK_FREE ( handle , new_fname ,
bsize , dfree , dsize ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return ret ;
}
static int ceph_snap_gmt_get_quota ( vfs_handle_struct * handle ,
const struct smb_filename * csmb_fname ,
enum SMB_QUOTA_TYPE qtype ,
unid_t id ,
SMB_DISK_QUOTA * dq )
{
time_t timestamp = 0 ;
char stripped [ PATH_MAX + 1 ] ;
char conv [ PATH_MAX + 1 ] ;
int ret ;
struct smb_filename * new_fname ;
int saved_errno ;
ret = ceph_snap_gmt_strip_snapshot ( handle ,
2020-05-02 12:39:58 +03:00
csmb_fname ,
2019-03-26 18:35:18 +03:00
& timestamp , stripped , sizeof ( stripped ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GET_QUOTA ( handle , csmb_fname , qtype , id , dq ) ;
}
ret = ceph_snap_gmt_convert ( handle , stripped ,
timestamp , conv , sizeof ( conv ) ) ;
if ( ret < 0 ) {
errno = - ret ;
return - 1 ;
}
new_fname = cp_smb_filename ( talloc_tos ( ) , csmb_fname ) ;
if ( new_fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
new_fname - > base_name = conv ;
ret = SMB_VFS_NEXT_GET_QUOTA ( handle , new_fname , qtype , id , dq ) ;
saved_errno = errno ;
TALLOC_FREE ( new_fname ) ;
errno = saved_errno ;
return ret ;
}
static struct vfs_fn_pointers ceph_snap_fns = {
. get_shadow_copy_data_fn = ceph_snap_get_shadow_copy_data ,
. disk_free_fn = ceph_snap_gmt_disk_free ,
. get_quota_fn = ceph_snap_gmt_get_quota ,
2019-08-09 23:49:46 +03:00
. renameat_fn = ceph_snap_gmt_renameat ,
2019-08-14 21:38:23 +03:00
. linkat_fn = ceph_snap_gmt_linkat ,
2019-08-30 23:16:01 +03:00
. symlinkat_fn = ceph_snap_gmt_symlinkat ,
2019-03-26 18:35:18 +03:00
. stat_fn = ceph_snap_gmt_stat ,
. lstat_fn = ceph_snap_gmt_lstat ,
. open_fn = ceph_snap_gmt_open ,
2019-09-12 20:05:00 +03:00
. unlinkat_fn = ceph_snap_gmt_unlinkat ,
2019-03-26 18:35:18 +03:00
. chmod_fn = ceph_snap_gmt_chmod ,
. chdir_fn = ceph_snap_gmt_chdir ,
. ntimes_fn = ceph_snap_gmt_ntimes ,
2019-08-23 00:10:31 +03:00
. readlinkat_fn = ceph_snap_gmt_readlinkat ,
2019-08-21 02:52:36 +03:00
. mknodat_fn = ceph_snap_gmt_mknodat ,
2019-03-26 18:35:18 +03:00
. realpath_fn = ceph_snap_gmt_realpath ,
. get_nt_acl_fn = ceph_snap_gmt_get_nt_acl ,
2019-09-05 01:43:44 +03:00
. mkdirat_fn = ceph_snap_gmt_mkdirat ,
2019-03-26 18:35:18 +03:00
. getxattr_fn = ceph_snap_gmt_getxattr ,
. getxattrat_send_fn = vfs_not_implemented_getxattrat_send ,
. getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv ,
. listxattr_fn = ceph_snap_gmt_listxattr ,
. removexattr_fn = ceph_snap_gmt_removexattr ,
. setxattr_fn = ceph_snap_gmt_setxattr ,
. chflags_fn = ceph_snap_gmt_chflags ,
. get_real_filename_fn = ceph_snap_gmt_get_real_filename ,
} ;
static_decl_vfs ;
NTSTATUS vfs_ceph_snapshots_init ( TALLOC_CTX * ctx )
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION ,
" ceph_snapshots " , & ceph_snap_fns ) ;
}