2002-09-07 08:05:42 +04:00
/*
* Recycle bin VFS module for Samba .
2002-03-19 05:51:48 +03:00
*
* Copyright ( C ) 2001 , Brandon Stone , Amherst College , < bbstone @ amherst . edu > .
* Copyright ( C ) 2002 , Jeremy Allison - modified to make a VFS module .
2002-07-30 13:59:53 +04:00
* Copyright ( C ) 2002 , Alexander Bokovoy - cascaded VFS adoption ,
2002-09-07 08:05:42 +04:00
* Copyright ( C ) 2002 , Juergen Hasch - added some options .
* Copyright ( C ) 2002 , Simo Sorce
2003-05-12 03:34:18 +04:00
* Copyright ( C ) 2002 , Stefan ( metze ) Metzmacher
2002-03-19 05:51:48 +03:00
*
* 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
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2002-03-19 05:51:48 +03:00
* ( at your option ) any later version .
2002-09-07 08:05:42 +04:00
*
2002-03-19 05:51:48 +03:00
* 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 .
2002-09-07 08:05:42 +04:00
*
2002-03-19 05:51:48 +03:00
* You should have received a copy of the GNU General Public License
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2002-03-19 05:51:48 +03:00
*/
2002-09-07 08:05:42 +04:00
# 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"
2010-08-05 17:14:04 +04:00
# include "../librpc/gen_ndr/ndr_netlogon.h"
2011-03-24 16:15:54 +03:00
# include "auth.h"
2021-11-10 22:18:07 +03:00
# include "source3/lib/substitute.h"
2002-09-07 08:05:42 +04:00
# define ALLOC_CHECK(ptr, label) do { if ((ptr) == NULL) { DEBUG(0, ("recycle.bin: out of memory!\n")); errno = ENOMEM; goto label; } } while(0)
static int vfs_recycle_debug_level = DBGC_VFS ;
# undef DBGC_CLASS
# define DBGC_CLASS vfs_recycle_debug_level
2010-03-28 15:13:03 +04:00
2024-01-06 19:35:55 +03:00
struct recycle_config_data {
const char * repository ;
bool keeptree ;
bool versions ;
bool touch ;
bool touch_mtime ;
const char * * exclude ;
const char * * exclude_dir ;
const char * * noversions ;
mode_t directory_mode ;
mode_t subdir_mode ;
2012-04-05 08:53:08 +04:00
off_t minsize ;
2024-01-06 19:35:55 +03:00
off_t maxsize ;
} ;
2010-03-28 15:13:03 +04:00
2024-01-06 19:35:55 +03:00
static int vfs_recycle_connect ( struct vfs_handle_struct * handle ,
const char * service ,
const char * user )
2005-06-13 21:41:52 +04:00
{
2024-06-14 11:07:02 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2024-01-06 19:35:55 +03:00
struct recycle_config_data * config = NULL ;
int ret ;
int t ;
2024-06-14 11:07:02 +03:00
const char * buff = NULL ;
const char * * tmplist = NULL ;
2024-06-14 11:07:02 +03:00
char * repository = NULL ;
2005-06-13 21:41:52 +04:00
2024-01-06 19:35:55 +03:00
ret = SMB_VFS_NEXT_CONNECT ( handle , service , user ) ;
if ( ret < 0 ) {
return ret ;
}
2005-06-13 21:41:52 +04:00
2024-01-06 19:35:55 +03:00
if ( IS_IPC ( handle - > conn ) | | IS_PRINT ( handle - > conn ) ) {
return 0 ;
}
config = talloc_zero ( handle - > conn , struct recycle_config_data ) ;
if ( config = = NULL ) {
DBG_ERR ( " talloc_zero() failed \n " ) ;
errno = ENOMEM ;
return - 1 ;
}
2024-06-14 11:07:02 +03:00
buff = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" recycle " ,
" repository " ,
" .recycle " ) ;
2024-06-14 11:07:02 +03:00
repository = talloc_sub_full (
config ,
lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( handle - > conn ) ) ,
handle - > conn - > session_info - > unix_info - > unix_name ,
handle - > conn - > connectpath ,
handle - > conn - > session_info - > unix_token - > gid ,
handle - > conn - > session_info - > unix_info - > sanitized_username ,
handle - > conn - > session_info - > info - > domain_name ,
buff ) ;
if ( repository = = NULL ) {
DBG_ERR ( " talloc_sub_full() failed \n " ) ;
2024-06-14 11:07:02 +03:00
TALLOC_FREE ( config ) ;
errno = ENOMEM ;
return - 1 ;
}
2024-06-14 11:07:02 +03:00
/* shouldn't we allow absolute path names here? --metze */
/* Yes :-). JRA. */
trim_char ( repository , ' \0 ' , ' / ' ) ;
config - > repository = repository ;
2024-01-06 19:35:55 +03:00
config - > keeptree = lp_parm_bool ( SNUM ( handle - > conn ) ,
" recycle " ,
" keeptree " ,
False ) ;
config - > versions = lp_parm_bool ( SNUM ( handle - > conn ) ,
" recycle " ,
" versions " ,
False ) ;
config - > touch = lp_parm_bool ( SNUM ( handle - > conn ) ,
" recycle " ,
" touch " ,
False ) ;
config - > touch_mtime = lp_parm_bool ( SNUM ( handle - > conn ) ,
" recycle " ,
" touch_mtime " ,
False ) ;
2024-06-14 11:07:02 +03:00
tmplist = lp_parm_string_list ( SNUM ( handle - > conn ) ,
" recycle " ,
" exclude " ,
NULL ) ;
if ( tmplist ! = NULL ) {
char * * tmpcpy = str_list_copy ( config , tmplist ) ;
if ( tmpcpy = = NULL ) {
DBG_ERR ( " str_list_copy() failed \n " ) ;
TALLOC_FREE ( config ) ;
errno = ENOMEM ;
return - 1 ;
}
config - > exclude = discard_const_p ( const char * , tmpcpy ) ;
}
tmplist = lp_parm_string_list ( SNUM ( handle - > conn ) ,
" recycle " ,
" exclude_dir " ,
NULL ) ;
if ( tmplist ! = NULL ) {
char * * tmpcpy = str_list_copy ( config , tmplist ) ;
if ( tmpcpy = = NULL ) {
DBG_ERR ( " str_list_copy() failed \n " ) ;
TALLOC_FREE ( config ) ;
errno = ENOMEM ;
return - 1 ;
}
config - > exclude_dir = discard_const_p ( const char * , tmpcpy ) ;
}
tmplist = lp_parm_string_list ( SNUM ( handle - > conn ) ,
" recycle " ,
" noversions " ,
NULL ) ;
if ( tmplist ! = NULL ) {
char * * tmpcpy = str_list_copy ( config , tmplist ) ;
if ( tmpcpy = = NULL ) {
DBG_ERR ( " str_list_copy() failed \n " ) ;
TALLOC_FREE ( config ) ;
errno = ENOMEM ;
return - 1 ;
}
config - > noversions = discard_const_p ( const char * , tmpcpy ) ;
}
2024-01-06 19:35:55 +03:00
config - > minsize = conv_str_size ( lp_parm_const_string (
SNUM ( handle - > conn ) , " recycle " , " minsize " , NULL ) ) ;
config - > maxsize = conv_str_size ( lp_parm_const_string (
SNUM ( handle - > conn ) , " recycle " , " maxsize " , NULL ) ) ;
buff = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" recycle " ,
" directory_mode " ,
NULL ) ;
2005-06-13 21:41:52 +04:00
if ( buff ! = NULL ) {
2024-01-06 19:35:55 +03:00
sscanf ( buff , " %o " , & t ) ;
2005-06-13 21:41:52 +04:00
} else {
2024-01-06 19:35:55 +03:00
t = S_IRUSR | S_IWUSR | S_IXUSR ;
2005-06-13 21:41:52 +04:00
}
2024-01-06 19:35:55 +03:00
config - > directory_mode = ( mode_t ) t ;
2005-06-13 21:41:52 +04:00
2024-01-06 19:35:55 +03:00
buff = lp_parm_const_string ( SNUM ( handle - > conn ) ,
" recycle " ,
" subdir_mode " ,
NULL ) ;
2006-05-27 20:55:30 +04:00
if ( buff ! = NULL ) {
2024-01-06 19:35:55 +03:00
sscanf ( buff , " %o " , & t ) ;
2006-05-27 20:55:30 +04:00
} else {
2024-01-06 19:35:55 +03:00
t = config - > directory_mode ;
2006-05-27 20:55:30 +04:00
}
2024-01-06 19:35:55 +03:00
config - > subdir_mode = ( mode_t ) t ;
2006-05-27 20:55:30 +04:00
2024-01-06 19:35:55 +03:00
SMB_VFS_HANDLE_SET_DATA (
handle , config , NULL , struct recycle_config_data , return - 1 ) ;
return 0 ;
2006-05-27 20:55:30 +04:00
}
2007-10-19 04:40:25 +04:00
static bool recycle_directory_exist ( vfs_handle_struct * handle , const char * dname )
2002-03-19 05:51:48 +03:00
{
2016-03-19 08:10:34 +03:00
struct smb_filename smb_fname = {
. base_name = discard_const_p ( char , dname )
} ;
2002-03-19 05:51:48 +03:00
2016-03-19 08:10:34 +03:00
if ( SMB_VFS_STAT ( handle - > conn , & smb_fname ) = = 0 ) {
if ( S_ISDIR ( smb_fname . st . st_ex_mode ) ) {
2002-09-07 08:05:42 +04:00
return True ;
}
}
2002-03-19 05:51:48 +03:00
2002-09-07 08:05:42 +04:00
return False ;
2002-03-19 05:51:48 +03:00
}
2009-07-02 20:27:44 +04:00
static bool recycle_file_exist ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
2002-03-19 05:51:48 +03:00
{
2009-07-02 20:27:44 +04:00
struct smb_filename * smb_fname_tmp = NULL ;
bool ret = false ;
2002-09-07 08:05:42 +04:00
2013-04-11 17:37:38 +04:00
smb_fname_tmp = cp_smb_filename ( talloc_tos ( ) , smb_fname ) ;
if ( smb_fname_tmp = = NULL ) {
2009-07-02 20:27:44 +04:00
return false ;
}
if ( SMB_VFS_STAT ( handle - > conn , smb_fname_tmp ) = = 0 ) {
if ( S_ISREG ( smb_fname_tmp - > st . st_ex_mode ) ) {
ret = true ;
2002-09-07 08:05:42 +04:00
}
}
2009-07-02 20:27:44 +04:00
TALLOC_FREE ( smb_fname_tmp ) ;
return ret ;
2002-03-19 05:51:48 +03:00
}
2002-09-07 08:05:42 +04:00
/**
* Return file size
* @ param conn connection
* @ param fname file name
* @ return size in bytes
* */
2012-04-05 08:53:08 +04:00
static off_t recycle_get_file_size ( vfs_handle_struct * handle ,
2009-07-02 20:27:44 +04:00
const struct smb_filename * smb_fname )
2002-03-19 05:51:48 +03:00
{
2009-07-02 20:27:44 +04:00
struct smb_filename * smb_fname_tmp = NULL ;
2012-04-05 08:53:08 +04:00
off_t size ;
2009-07-02 20:27:44 +04:00
2013-04-11 17:38:41 +04:00
smb_fname_tmp = cp_smb_filename ( talloc_tos ( ) , smb_fname ) ;
if ( smb_fname_tmp = = NULL ) {
2012-04-05 08:53:08 +04:00
size = ( off_t ) 0 ;
2009-07-02 20:27:44 +04:00
goto out ;
}
2003-05-12 03:34:18 +04:00
2009-07-02 20:27:44 +04:00
if ( SMB_VFS_STAT ( handle - > conn , smb_fname_tmp ) ! = 0 ) {
2020-03-06 14:22:25 +03:00
DBG_DEBUG ( " stat for %s returned %s \n " ,
smb_fname_str_dbg ( smb_fname_tmp ) , strerror ( errno ) ) ;
2012-04-05 08:53:08 +04:00
size = ( off_t ) 0 ;
2009-07-02 20:27:44 +04:00
goto out ;
2002-09-07 08:05:42 +04:00
}
2003-05-12 03:34:18 +04:00
2009-07-02 20:27:44 +04:00
size = smb_fname_tmp - > st . st_ex_size ;
out :
TALLOC_FREE ( smb_fname_tmp ) ;
return size ;
2002-09-07 08:05:42 +04:00
}
2002-03-19 05:51:48 +03:00
2002-09-07 08:05:42 +04:00
/**
* Create directory tree
* @ param conn connection
* @ param dname Directory tree to be created
2024-01-06 19:35:55 +03:00
* @ param directory mode
* @ param subdirectory mode
2002-09-07 08:05:42 +04:00
* @ return Returns True for success
* */
2024-01-06 19:35:55 +03:00
static bool recycle_create_dir ( vfs_handle_struct * handle ,
const char * dname ,
mode_t dir_mode ,
mode_t subdir_mode )
2002-09-07 08:05:42 +04:00
{
2005-06-13 22:45:17 +04:00
size_t len ;
2024-01-06 19:35:55 +03:00
mode_t mode = dir_mode ;
2002-09-07 08:05:42 +04:00
char * new_dir = NULL ;
char * tmp_str = NULL ;
char * token ;
char * tok_str ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2008-01-23 13:04:10 +03:00
char * saveptr ;
2002-09-07 08:05:42 +04:00
2004-12-07 21:25:53 +03:00
tmp_str = SMB_STRDUP ( dname ) ;
2002-09-07 08:05:42 +04:00
ALLOC_CHECK ( tmp_str , done ) ;
tok_str = tmp_str ;
2004-03-12 14:21:50 +03:00
len = strlen ( dname ) + 1 ;
2004-12-07 21:25:53 +03:00
new_dir = ( char * ) SMB_MALLOC ( len + 1 ) ;
2002-09-07 08:05:42 +04:00
ALLOC_CHECK ( new_dir , done ) ;
* new_dir = ' \0 ' ;
2005-06-13 22:45:17 +04:00
if ( dname [ 0 ] = = ' / ' ) {
/* Absolute path. */
2012-03-30 04:13:07 +04:00
if ( strlcat ( new_dir , " / " , len + 1 ) > = len + 1 ) {
goto done ;
}
2005-06-13 22:45:17 +04:00
}
2002-09-07 08:05:42 +04:00
2019-10-26 03:41:09 +03:00
/* Create directory tree if necessary */
2008-01-23 13:04:10 +03:00
for ( token = strtok_r ( tok_str , " / " , & saveptr ) ; token ;
token = strtok_r ( NULL , " / " , & saveptr ) ) {
2012-03-30 04:13:07 +04:00
if ( strlcat ( new_dir , token , len + 1 ) > = len + 1 ) {
goto done ;
}
2003-05-12 03:34:18 +04:00
if ( recycle_directory_exist ( handle , new_dir ) )
DEBUG ( 10 , ( " recycle: dir %s already exists \n " , new_dir ) ) ;
2002-09-07 08:05:42 +04:00
else {
2016-02-24 00:14:03 +03:00
struct smb_filename * smb_fname = NULL ;
2019-09-06 19:51:47 +03:00
int retval ;
2016-02-24 00:14:03 +03:00
2003-05-12 03:34:18 +04:00
DEBUG ( 5 , ( " recycle: creating new dir %s \n " , new_dir ) ) ;
2016-02-24 00:14:03 +03:00
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
new_dir ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2016-03-19 07:19:38 +03:00
0 ) ;
2016-02-24 00:14:03 +03:00
if ( smb_fname = = NULL ) {
goto done ;
}
2019-09-06 19:51:47 +03:00
retval = SMB_VFS_NEXT_MKDIRAT ( handle ,
handle - > conn - > cwd_fsp ,
smb_fname ,
mode ) ;
if ( retval ! = 0 ) {
DBG_WARNING ( " recycle: mkdirat failed "
" for %s with error: %s \n " ,
new_dir ,
strerror ( errno ) ) ;
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( smb_fname ) ;
2002-09-07 08:05:42 +04:00
ret = False ;
goto done ;
}
2016-02-24 00:14:03 +03:00
TALLOC_FREE ( smb_fname ) ;
2002-09-07 08:05:42 +04:00
}
2012-03-30 04:13:07 +04:00
if ( strlcat ( new_dir , " / " , len + 1 ) > = len + 1 ) {
goto done ;
}
2024-01-06 19:35:55 +03:00
mode = subdir_mode ;
2003-05-12 03:34:18 +04:00
}
2002-03-19 05:51:48 +03:00
2002-09-07 08:05:42 +04:00
ret = True ;
done :
SAFE_FREE ( tmp_str ) ;
SAFE_FREE ( new_dir ) ;
return ret ;
2002-03-19 05:51:48 +03:00
}
2002-09-07 08:05:42 +04:00
/**
2007-04-05 03:33:07 +04:00
* Check if any of the components of " exclude_list " are contained in path .
* Return True if found
2002-09-07 08:05:42 +04:00
* */
2007-04-05 03:33:07 +04:00
2007-10-19 04:40:25 +04:00
static bool matchdirparam ( const char * * dir_exclude_list , char * path )
2002-09-07 08:05:42 +04:00
{
2007-04-05 03:33:07 +04:00
char * startp = NULL , * endp = NULL ;
2002-09-07 08:05:42 +04:00
2007-04-05 03:33:07 +04:00
if ( dir_exclude_list = = NULL | | dir_exclude_list [ 0 ] = = NULL | |
* dir_exclude_list [ 0 ] = = ' \0 ' | | path = = NULL | | * path = = ' \0 ' ) {
2002-09-07 08:05:42 +04:00
return False ;
}
2007-04-05 03:33:07 +04:00
/*
* Walk the components of path , looking for matches with the
* exclude list on each component .
*/
for ( startp = path ; startp ; startp = endp ) {
int i ;
while ( * startp = = ' / ' ) {
startp + + ;
}
endp = strchr ( startp , ' / ' ) ;
if ( endp ) {
* endp = ' \0 ' ;
}
for ( i = 0 ; dir_exclude_list [ i ] ; i + + ) {
if ( unix_wild_match ( dir_exclude_list [ i ] , startp ) ) {
/* Repair path. */
if ( endp ) {
* endp = ' / ' ;
}
return True ;
}
}
/* Repair path. */
if ( endp ) {
* endp = ' / ' ;
2002-09-07 08:05:42 +04:00
}
}
2003-05-12 03:34:18 +04:00
return False ;
2002-09-07 08:05:42 +04:00
}
/**
* Check if needle is contained in haystack , * and ? patterns are resolved
* @ param haystack list of parameters separated by delimimiter character
* @ param needle string to be matched exectly to haystack including pattern matching
* @ return True if found
* */
2007-10-19 04:40:25 +04:00
static bool matchparam ( const char * * haystack_list , const char * needle )
2002-09-07 08:05:42 +04:00
{
2003-05-12 03:34:18 +04:00
int i ;
2002-09-07 08:05:42 +04:00
2003-05-12 03:34:18 +04:00
if ( haystack_list = = NULL | | haystack_list [ 0 ] = = NULL | |
* haystack_list [ 0 ] = = ' \0 ' | | needle = = NULL | | * needle = = ' \0 ' ) {
2002-09-07 08:05:42 +04:00
return False ;
}
2003-05-12 03:34:18 +04:00
for ( i = 0 ; haystack_list [ i ] ; i + + ) {
2005-12-16 04:41:12 +03:00
if ( unix_wild_match ( haystack_list [ i ] , needle ) ) {
2003-05-12 03:34:18 +04:00
return True ;
2002-09-07 08:05:42 +04:00
}
}
2003-05-12 03:34:18 +04:00
return False ;
2002-09-07 08:05:42 +04:00
}
/**
2005-06-21 15:27:17 +04:00
* Touch access or modify date
2002-09-07 08:05:42 +04:00
* */
2009-07-02 20:27:44 +04:00
static void recycle_do_touch ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
2007-10-19 04:40:25 +04:00
bool touch_mtime )
2002-09-07 08:05:42 +04:00
{
2009-07-02 20:27:44 +04:00
struct smb_filename * smb_fname_tmp = NULL ;
2009-01-24 01:40:19 +03:00
struct smb_file_time ft ;
2007-07-04 03:48:02 +04:00
int ret , err ;
2021-04-14 12:26:38 +03:00
NTSTATUS status ;
2007-07-04 03:34:01 +04:00
2019-12-02 18:30:50 +03:00
init_smb_file_time ( & ft ) ;
2009-01-24 01:40:19 +03:00
2021-04-14 12:26:38 +03:00
status = synthetic_pathref ( talloc_tos ( ) ,
handle - > conn - > cwd_fsp ,
smb_fname - > base_name ,
smb_fname - > stream_name ,
NULL ,
smb_fname - > twrp ,
smb_fname - > flags ,
& smb_fname_tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " synthetic_pathref for '%s' failed: %s \n " ,
smb_fname_str_dbg ( smb_fname ) , nt_errstr ( status ) ) ;
2002-09-07 08:05:42 +04:00
return ;
}
2009-07-02 20:27:44 +04:00
/* atime */
ft . atime = timespec_current ( ) ;
/* mtime */
ft . mtime = touch_mtime ? ft . atime : smb_fname_tmp - > st . st_ex_mtime ;
2024-03-25 19:03:44 +03:00
become_root ( ) ;
2021-04-14 12:26:38 +03:00
ret = SMB_VFS_NEXT_FNTIMES ( handle , smb_fname_tmp - > fsp , & ft ) ;
2007-07-04 03:34:01 +04:00
err = errno ;
2024-03-25 19:03:44 +03:00
unbecome_root ( ) ;
2007-07-04 03:48:02 +04:00
if ( ret = = - 1 ) {
2007-07-04 03:34:01 +04:00
DEBUG ( 0 , ( " recycle: touching %s failed, reason = %s \n " ,
2009-07-02 20:27:44 +04:00
smb_fname_str_dbg ( smb_fname_tmp ) , strerror ( err ) ) ) ;
2002-09-07 08:05:42 +04:00
}
2021-04-14 12:26:38 +03:00
2009-07-03 00:39:20 +04:00
TALLOC_FREE ( smb_fname_tmp ) ;
2003-05-12 03:34:18 +04:00
}
2002-03-19 05:51:48 +03:00
2002-09-07 08:05:42 +04:00
/**
* Check if file should be recycled
* */
2019-09-17 03:22:58 +03:00
static int recycle_unlink_internal ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
2002-03-19 05:51:48 +03:00
{
2024-06-14 11:07:02 +03:00
TALLOC_CTX * frame = NULL ;
2021-01-20 17:16:07 +03:00
struct smb_filename * full_fname = NULL ;
2002-09-07 08:05:42 +04:00
char * path_name = NULL ;
2024-06-14 11:07:02 +03:00
const char * temp_name = NULL ;
const char * final_name = NULL ;
2009-07-01 04:04:38 +04:00
struct smb_filename * smb_fname_final = NULL ;
2024-06-14 11:07:02 +03:00
const char * base = NULL ;
2003-05-12 03:34:18 +04:00
int i = 1 ;
2012-04-05 08:53:08 +04:00
off_t file_size ; /* space_avail; */
2007-10-19 04:40:25 +04:00
bool exist ;
2002-09-08 07:55:37 +04:00
int rc = - 1 ;
2024-06-14 11:07:02 +03:00
struct recycle_config_data * config = NULL ;
2024-08-06 14:21:34 +03:00
struct vfs_rename_how rhow = { . flags = 0 , } ;
2024-01-06 19:35:55 +03:00
SMB_VFS_HANDLE_GET_DATA ( handle ,
config ,
struct recycle_config_data ,
2024-06-14 11:07:02 +03:00
return - 1 ) ;
2024-01-06 19:35:55 +03:00
2024-06-14 11:07:02 +03:00
frame = talloc_stackframe ( ) ;
2024-06-14 11:07:02 +03:00
if ( config - > repository [ 0 ] = = ' \0 ' ) {
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: repository path not set, purging %s... \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
2002-03-19 05:51:48 +03:00
2024-06-14 11:07:02 +03:00
full_fname = full_path_from_dirfsp_atname ( frame ,
2021-01-20 17:16:07 +03:00
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
2024-06-14 11:07:02 +03:00
rc = - 1 ;
errno = ENOMEM ;
goto done ;
2021-01-20 17:16:07 +03:00
}
2002-09-07 08:05:42 +04:00
/* we don't recycle the recycle bin... */
2024-06-14 11:07:02 +03:00
if ( strncmp ( full_fname - > base_name , config - > repository ,
strlen ( config - > repository ) ) = = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: File is within recycling bin, unlinking ... \n " ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
2002-03-19 05:51:48 +03:00
2021-01-20 17:16:07 +03:00
file_size = recycle_get_file_size ( handle , full_fname ) ;
2002-09-07 08:05:42 +04:00
/* it is wrong to purge filenames only because they are empty imho
* - - - simo
*
if ( fsize = = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: File %s is empty, purging... \n " , file_name ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
file_name ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
*/
2005-06-13 22:45:17 +04:00
/* FIXME: this is wrong, we should check the whole size of the recycle bin is
2002-09-07 08:05:42 +04:00
* not greater then maxsize , not the size of the single file , also it is better
* to remove older files
*/
2024-01-06 19:35:55 +03:00
if ( config - > maxsize > 0 & & file_size > config - > maxsize ) {
DBG_NOTICE ( " File %s exceeds maximum recycle size, "
" purging... \n " ,
smb_fname_str_dbg ( full_fname ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2007-03-02 02:57:37 +03:00
goto done ;
}
2024-01-06 19:35:55 +03:00
if ( config - > minsize > 0 & & file_size < config - > minsize ) {
DBG_NOTICE ( " File %s lowers minimum recycle size, "
" purging... \n " ,
smb_fname_str_dbg ( full_fname ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
2002-03-19 05:51:48 +03:00
}
2002-09-07 08:05:42 +04:00
/* FIXME: this is wrong: moving files with rename does not change the disk space
* allocation
*
2006-07-11 22:01:26 +04:00
space_avail = SMB_VFS_NEXT_DISK_FREE ( handle , " . " , True , & bsize , & dfree , & dsize ) * 1024L ;
2002-09-07 08:05:42 +04:00
DEBUG ( 5 , ( " space_avail = %Lu, file_size = %Lu \n " , space_avail , file_size ) ) ;
if ( space_avail < file_size ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: Not enough diskspace, purging file %s \n " , file_name ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
file_name ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
*/
/* extract filename and path */
2024-06-14 11:07:02 +03:00
if ( ! parent_dirname ( frame , full_fname - > base_name , & path_name , & base ) ) {
2021-10-28 23:01:42 +03:00
rc = - 1 ;
errno = ENOMEM ;
goto done ;
2002-03-19 05:51:48 +03:00
}
2009-07-02 20:27:44 +04:00
/* original filename with path */
2021-01-20 17:16:07 +03:00
DEBUG ( 10 , ( " recycle: fname = %s \n " , smb_fname_str_dbg ( full_fname ) ) ) ;
2009-07-02 20:27:44 +04:00
/* original path */
DEBUG ( 10 , ( " recycle: fpath = %s \n " , path_name ) ) ;
/* filename without path */
DEBUG ( 10 , ( " recycle: base = %s \n " , base ) ) ;
2002-05-11 04:33:51 +04:00
2024-01-06 19:35:55 +03:00
if ( matchparam ( config - > exclude , base ) ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: file %s is excluded \n " , base ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
2002-05-11 04:33:51 +04:00
}
2002-03-19 05:51:48 +03:00
2024-01-06 19:35:55 +03:00
if ( matchdirparam ( config - > exclude_dir , path_name ) ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: directory %s is excluded \n " , path_name ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
2002-03-19 05:51:48 +03:00
}
2024-01-06 19:35:55 +03:00
if ( config - > keeptree ) {
2024-06-14 11:07:02 +03:00
temp_name = talloc_asprintf ( frame , " %s/%s " ,
config - > repository ,
path_name ) ;
if ( temp_name = = NULL ) {
rc = - 1 ;
goto done ;
2009-01-01 05:06:57 +03:00
}
2003-04-09 21:36:52 +04:00
} else {
2024-06-14 11:07:02 +03:00
temp_name = config - > repository ;
2002-03-19 05:51:48 +03:00
}
2003-05-12 03:34:18 +04:00
exist = recycle_directory_exist ( handle , temp_name ) ;
2002-09-07 08:05:42 +04:00
if ( exist ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: Directory already exists \n " ) ) ;
2002-09-07 08:05:42 +04:00
} else {
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: Creating directory %s \n " , temp_name ) ) ;
2024-01-06 19:35:55 +03:00
if ( recycle_create_dir ( handle ,
temp_name ,
config - > directory_mode ,
config - > subdir_mode ) = = False )
{
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: Could not create directory, "
" purging %s... \n " ,
2021-01-20 17:16:07 +03:00
smb_fname_str_dbg ( full_fname ) ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
2002-03-19 05:51:48 +03:00
}
2002-09-07 08:05:42 +04:00
}
2002-03-19 05:51:48 +03:00
2024-06-14 11:07:02 +03:00
final_name = talloc_asprintf ( frame , " %s/%s " ,
temp_name , base ) ;
if ( final_name = = NULL ) {
rc = - 1 ;
goto done ;
2009-01-01 05:06:57 +03:00
}
2009-07-02 20:27:44 +04:00
/* Create smb_fname with final base name and orig stream name. */
2024-06-14 11:07:02 +03:00
smb_fname_final = synthetic_smb_fname ( frame ,
2016-03-19 07:19:38 +03:00
final_name ,
2021-01-20 17:16:07 +03:00
full_fname - > stream_name ,
2016-03-19 07:19:38 +03:00
NULL ,
2021-01-20 17:16:07 +03:00
full_fname - > twrp ,
full_fname - > flags ) ;
2013-04-12 13:17:00 +04:00
if ( smb_fname_final = = NULL ) {
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2009-07-02 20:27:44 +04:00
goto done ;
}
/* new filename with path */
DEBUG ( 10 , ( " recycle: recycled file name: %s \n " ,
smb_fname_str_dbg ( smb_fname_final ) ) ) ;
2002-09-07 08:05:42 +04:00
/* check if we should delete file from recycle bin */
2009-07-02 20:27:44 +04:00
if ( recycle_file_exist ( handle , smb_fname_final ) ) {
2024-01-06 19:35:55 +03:00
if ( config - > versions = = False | |
matchparam ( config - > noversions , base ) = = True ) {
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: Removing old file %s from recycle "
" bin \n " , smb_fname_str_dbg ( smb_fname_final ) ) ) ;
2019-09-17 03:30:49 +03:00
if ( SMB_VFS_NEXT_UNLINKAT ( handle ,
2021-01-20 17:16:07 +03:00
dirfsp - > conn - > cwd_fsp ,
2019-09-17 03:30:49 +03:00
smb_fname_final ,
flags ) ! = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 1 , ( " recycle: Error deleting old file: %s \n " , strerror ( errno ) ) ) ;
2002-09-07 08:05:42 +04:00
}
2002-03-23 23:48:45 +03:00
}
2002-03-19 05:51:48 +03:00
}
2002-09-07 08:05:42 +04:00
/* rename file we move to recycle bin */
i = 1 ;
2009-07-02 20:27:44 +04:00
while ( recycle_file_exist ( handle , smb_fname_final ) ) {
2024-06-14 11:07:02 +03:00
char * copy = NULL ;
2009-07-02 20:27:44 +04:00
TALLOC_FREE ( smb_fname_final - > base_name ) ;
2024-06-14 11:07:02 +03:00
copy = talloc_asprintf ( smb_fname_final , " %s/Copy #%d of %s " ,
temp_name , i + + , base ) ;
if ( copy = = NULL ) {
rc = - 1 ;
goto done ;
}
smb_fname_final - > base_name = copy ;
2002-09-07 08:05:42 +04:00
}
2021-01-20 17:16:07 +03:00
DEBUG ( 10 , ( " recycle: Moving %s to %s \n " , smb_fname_str_dbg ( full_fname ) ,
2009-07-02 20:27:44 +04:00
smb_fname_str_dbg ( smb_fname_final ) ) ) ;
2019-08-10 02:27:49 +03:00
rc = SMB_VFS_NEXT_RENAMEAT ( handle ,
2021-01-20 17:16:07 +03:00
dirfsp ,
2019-08-10 02:27:49 +03:00
smb_fname ,
handle - > conn - > cwd_fsp ,
2024-08-06 14:21:34 +03:00
smb_fname_final ,
& rhow ) ;
2002-09-07 08:05:42 +04:00
if ( rc ! = 0 ) {
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: Move error %d (%s), purging file %s "
" (%s) \n " , errno , strerror ( errno ) ,
2021-01-20 17:16:07 +03:00
smb_fname_str_dbg ( full_fname ) ,
2009-07-02 20:27:44 +04:00
smb_fname_str_dbg ( smb_fname_final ) ) ) ;
2019-09-17 03:30:49 +03:00
rc = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
/* touch access date of moved file */
2024-01-06 19:35:55 +03:00
if ( config - > touch | | config - > touch_mtime )
recycle_do_touch ( handle , smb_fname_final , config - > touch_mtime ) ;
2002-09-07 08:05:42 +04:00
done :
2024-06-14 11:07:02 +03:00
TALLOC_FREE ( frame ) ;
2002-09-07 08:05:42 +04:00
return rc ;
2002-03-19 05:51:48 +03:00
}
2003-04-16 18:45:11 +04:00
2019-09-12 22:55:49 +03:00
static int recycle_unlinkat ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
{
int ret ;
if ( flags & AT_REMOVEDIR ) {
ret = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
} else {
2019-09-17 03:22:58 +03:00
ret = recycle_unlink_internal ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
2019-09-12 22:55:49 +03:00
}
return ret ;
}
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers vfs_recycle_fns = {
2024-01-06 19:35:55 +03:00
. connect_fn = vfs_recycle_connect ,
. unlinkat_fn = recycle_unlinkat ,
2009-07-24 04:28:58 +04:00
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_recycle_init ( TALLOC_CTX * ctx )
2003-05-12 03:34:18 +04:00
{
2009-07-24 04:28:58 +04:00
NTSTATUS ret = smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " recycle " ,
& vfs_recycle_fns ) ;
2003-05-12 03:34:18 +04:00
2003-06-22 14:09:52 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) )
2003-05-12 03:34:18 +04:00
return ret ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
vfs_recycle_debug_level = debug_add_class ( " recycle " ) ;
if ( vfs_recycle_debug_level = = - 1 ) {
vfs_recycle_debug_level = DBGC_VFS ;
DEBUG ( 0 , ( " vfs_recycle: Couldn't register custom debugging class! \n " ) ) ;
} else {
DEBUG ( 10 , ( " vfs_recycle: Debug class number of 'recycle': %d \n " , vfs_recycle_debug_level ) ) ;
}
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return ret ;
2003-04-16 18:45:11 +04:00
}