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"
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
2003-05-12 03:34:18 +04:00
2009-07-02 20:27:44 +04:00
static int recycle_unlink ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ) ;
2002-03-19 05:51:48 +03:00
2003-05-12 03:34:18 +04:00
static const char * recycle_repository ( vfs_handle_struct * handle )
2002-03-19 05:51:48 +03:00
{
2003-05-12 03:34:18 +04:00
const char * tmp_str = NULL ;
2002-03-19 05:51:48 +03:00
2003-05-12 03:34:18 +04:00
tmp_str = lp_parm_const_string ( SNUM ( handle - > conn ) , " recycle " , " repository " , " .recycle " ) ;
2002-03-19 05:51:48 +03:00
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: repository = %s \n " , tmp_str ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return tmp_str ;
}
2002-08-27 13:45:26 +04:00
2007-10-19 04:40:25 +04:00
static bool recycle_keep_dir_tree ( vfs_handle_struct * handle )
2003-05-12 03:34:18 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
ret = lp_parm_bool ( SNUM ( handle - > conn ) , " recycle " , " keeptree " , False ) ;
2002-09-07 08:05:42 +04:00
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle_bin: keeptree = %s \n " , ret ? " True " : " False " ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return ret ;
}
2007-10-19 04:40:25 +04:00
static bool recycle_versions ( vfs_handle_struct * handle )
2003-05-12 03:34:18 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2003-05-12 03:34:18 +04:00
ret = lp_parm_bool ( SNUM ( handle - > conn ) , " recycle " , " versions " , False ) ;
DEBUG ( 10 , ( " recycle: versions = %s \n " , ret ? " True " : " False " ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return ret ;
}
2007-10-19 04:40:25 +04:00
static bool recycle_touch ( vfs_handle_struct * handle )
2003-05-12 03:34:18 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2003-05-12 03:34:18 +04:00
ret = lp_parm_bool ( SNUM ( handle - > conn ) , " recycle " , " touch " , False ) ;
DEBUG ( 10 , ( " recycle: touch = %s \n " , ret ? " True " : " False " ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return ret ;
}
2003-04-24 07:46:17 +04:00
2007-10-19 04:40:25 +04:00
static bool recycle_touch_mtime ( vfs_handle_struct * handle )
2005-06-21 15:27:17 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret ;
2005-06-21 15:27:17 +04:00
ret = lp_parm_bool ( SNUM ( handle - > conn ) , " recycle " , " touch_mtime " , False ) ;
DEBUG ( 10 , ( " recycle: touch_mtime = %s \n " , ret ? " True " : " False " ) ) ;
2010-03-28 15:13:03 +04:00
2005-06-21 15:27:17 +04:00
return ret ;
}
2003-05-12 03:34:18 +04:00
static const char * * recycle_exclude ( vfs_handle_struct * handle )
{
const char * * tmp_lp ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
tmp_lp = lp_parm_string_list ( SNUM ( handle - > conn ) , " recycle " , " exclude " , NULL ) ;
2003-04-24 07:46:17 +04:00
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: exclude = %s ... \n " , tmp_lp ? * tmp_lp : " " ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return tmp_lp ;
}
2002-03-19 05:51:48 +03:00
2003-05-12 03:34:18 +04:00
static const char * * recycle_exclude_dir ( vfs_handle_struct * handle )
{
const char * * tmp_lp ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
tmp_lp = lp_parm_string_list ( SNUM ( handle - > conn ) , " recycle " , " exclude_dir " , NULL ) ;
2002-03-19 05:51:48 +03:00
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: exclude_dir = %s ... \n " , tmp_lp ? * tmp_lp : " " ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return tmp_lp ;
2002-03-19 05:51:48 +03:00
}
2003-05-12 03:34:18 +04:00
static const char * * recycle_noversions ( vfs_handle_struct * handle )
2002-03-19 05:51:48 +03:00
{
2003-05-12 03:34:18 +04:00
const char * * tmp_lp ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
tmp_lp = lp_parm_string_list ( SNUM ( handle - > conn ) , " recycle " , " noversions " , NULL ) ;
2003-04-24 07:46:17 +04:00
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: noversions = %s \n " , tmp_lp ? * tmp_lp : " " ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return tmp_lp ;
}
2003-04-24 07:46:17 +04:00
2012-04-05 08:53:08 +04:00
static off_t recycle_maxsize ( vfs_handle_struct * handle )
2003-05-12 03:34:18 +04:00
{
2012-04-05 08:53:08 +04:00
off_t maxsize ;
2010-03-28 15:13:03 +04:00
2007-03-02 06:51:22 +03:00
maxsize = conv_str_size ( lp_parm_const_string ( SNUM ( handle - > conn ) ,
" recycle " , " maxsize " , NULL ) ) ;
2003-04-24 07:46:17 +04:00
2007-03-08 21:43:39 +03:00
DEBUG ( 10 , ( " recycle: maxsize = %lu \n " , ( long unsigned int ) maxsize ) ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
return maxsize ;
2002-03-19 05:51:48 +03:00
}
2012-04-05 08:53:08 +04:00
static off_t recycle_minsize ( vfs_handle_struct * handle )
2007-03-02 02:57:37 +03:00
{
2012-04-05 08:53:08 +04:00
off_t minsize ;
2010-03-28 15:13:03 +04:00
2007-03-02 06:51:22 +03:00
minsize = conv_str_size ( lp_parm_const_string ( SNUM ( handle - > conn ) ,
" recycle " , " minsize " , NULL ) ) ;
2007-03-02 02:57:37 +03:00
2007-03-08 21:43:39 +03:00
DEBUG ( 10 , ( " recycle: minsize = %lu \n " , ( long unsigned int ) minsize ) ) ;
2010-03-28 15:13:03 +04:00
2007-03-02 02:57:37 +03:00
return minsize ;
}
2005-06-13 21:41:52 +04:00
static mode_t recycle_directory_mode ( vfs_handle_struct * handle )
{
2006-01-29 21:22:39 +03:00
int dirmode ;
2005-06-13 21:41:52 +04:00
const char * buff ;
buff = lp_parm_const_string ( SNUM ( handle - > conn ) , " recycle " , " directory_mode " , NULL ) ;
if ( buff ! = NULL ) {
2006-01-29 21:22:39 +03:00
sscanf ( buff , " %o " , & dirmode ) ;
2005-06-13 21:41:52 +04:00
} else {
dirmode = S_IRUSR | S_IWUSR | S_IXUSR ;
}
DEBUG ( 10 , ( " recycle: directory_mode = %o \n " , dirmode ) ) ;
2006-01-29 21:43:52 +03:00
return ( mode_t ) dirmode ;
2005-06-13 21:41:52 +04:00
}
2006-05-27 20:55:30 +04:00
static mode_t recycle_subdir_mode ( vfs_handle_struct * handle )
{
int dirmode ;
const char * buff ;
buff = lp_parm_const_string ( SNUM ( handle - > conn ) , " recycle " , " subdir_mode " , NULL ) ;
if ( buff ! = NULL ) {
sscanf ( buff , " %o " , & dirmode ) ;
} else {
dirmode = recycle_directory_mode ( handle ) ;
}
DEBUG ( 10 , ( " recycle: subdir_mode = %o \n " , dirmode ) ) ;
return ( mode_t ) dirmode ;
}
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 ) {
DEBUG ( 0 , ( " recycle: 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
* @ return Returns True for success
* */
2007-10-19 04:40:25 +04:00
static bool recycle_create_dir ( vfs_handle_struct * handle , const char * dname )
2002-09-07 08:05:42 +04:00
{
2005-06-13 22:45:17 +04:00
size_t len ;
2002-09-07 08:05:42 +04:00
mode_t mode ;
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
2005-06-13 21:41:52 +04:00
mode = recycle_directory_mode ( handle ) ;
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
/* Create directory tree if neccessary */
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 ;
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 ,
0 ) ;
2016-02-24 00:14:03 +03:00
if ( smb_fname = = NULL ) {
goto done ;
}
if ( SMB_VFS_NEXT_MKDIR ( handle , smb_fname , mode ) ! = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 1 , ( " recycle: mkdir 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 ;
}
2006-05-27 20:55:30 +04:00
mode = recycle_subdir_mode ( handle ) ;
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 ;
2007-07-04 03:34:01 +04:00
2009-01-24 01:40:19 +03:00
ZERO_STRUCT ( ft ) ;
2013-04-11 17:40:10 +04:00
smb_fname_tmp = cp_smb_filename ( talloc_tos ( ) , smb_fname ) ;
if ( smb_fname_tmp = = NULL ) {
2002-09-07 08:05:42 +04:00
return ;
}
2009-07-02 20:27:44 +04:00
if ( SMB_VFS_STAT ( handle - > conn , smb_fname_tmp ) ! = 0 ) {
DEBUG ( 0 , ( " recycle: stat for %s returned %s \n " ,
smb_fname_str_dbg ( smb_fname_tmp ) , strerror ( errno ) ) ) ;
goto out ;
}
/* atime */
ft . atime = timespec_current ( ) ;
/* mtime */
ft . mtime = touch_mtime ? ft . atime : smb_fname_tmp - > st . st_ex_mtime ;
2007-07-04 03:34:01 +04:00
become_root ( ) ;
2009-07-03 00:39:20 +04:00
ret = SMB_VFS_NEXT_NTIMES ( handle , smb_fname_tmp , & ft ) ;
2007-07-04 03:34:01 +04:00
err = errno ;
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
}
2009-07-02 20:27:44 +04:00
out :
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
* */
2009-07-02 20:27:44 +04:00
static int recycle_unlink ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
2002-03-19 05:51:48 +03:00
{
2006-07-11 22:01:26 +04:00
connection_struct * conn = handle - > conn ;
2002-09-07 08:05:42 +04:00
char * path_name = NULL ;
char * temp_name = NULL ;
char * final_name = NULL ;
2009-07-01 04:04:38 +04:00
struct smb_filename * smb_fname_final = NULL ;
2003-04-24 07:46:17 +04:00
const char * base ;
2003-05-12 03:34:18 +04:00
char * repository = NULL ;
int i = 1 ;
2012-04-05 08:53:08 +04:00
off_t maxsize , minsize ;
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 ;
2002-09-07 08:05:42 +04:00
2012-07-18 09:37:23 +04:00
repository = talloc_sub_advanced ( NULL , lp_servicename ( talloc_tos ( ) , SNUM ( conn ) ) ,
2011-07-15 09:55:31 +04:00
conn - > session_info - > unix_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2011-07-15 08:59:14 +04:00
conn - > session_info - > unix_token - > gid ,
2011-07-15 09:55:31 +04:00
conn - > session_info - > unix_info - > sanitized_username ,
2011-07-18 06:58:25 +04:00
conn - > session_info - > info - > domain_name ,
2006-07-11 22:01:26 +04:00
recycle_repository ( handle ) ) ;
2003-05-12 03:34:18 +04:00
ALLOC_CHECK ( repository , done ) ;
/* shouldn't we allow absolute path names here? --metze */
2005-06-13 22:45:17 +04:00
/* Yes :-). JRA. */
trim_char ( repository , ' \0 ' , ' / ' ) ;
2010-03-28 15:13:03 +04:00
2003-05-12 03:34:18 +04:00
if ( ! repository | | * ( repository ) = = ' \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 ) ) ) ;
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
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
/* we don't recycle the recycle bin... */
2009-07-02 20:27:44 +04:00
if ( strncmp ( smb_fname - > base_name , repository ,
strlen ( repository ) ) = = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: File is within recycling bin, unlinking ... \n " ) ) ;
2009-07-02 20:27:44 +04:00
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
2002-03-19 05:51:48 +03:00
2009-07-02 20:27:44 +04:00
file_size = recycle_get_file_size ( handle , smb_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 ) ) ;
2006-07-11 22:01:26 +04:00
rc = SMB_VFS_NEXT_UNLINK ( handle , file_name ) ;
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
*/
2003-05-12 03:34:18 +04:00
maxsize = recycle_maxsize ( handle ) ;
if ( maxsize > 0 & & file_size > maxsize ) {
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: File %s exceeds maximum recycle size, "
" purging... \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2007-03-02 02:57:37 +03:00
goto done ;
}
minsize = recycle_minsize ( handle ) ;
if ( minsize > 0 & & file_size < minsize ) {
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: File %s lowers minimum recycle size, "
" purging... \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
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 ) ) ;
2006-07-11 22:01:26 +04:00
rc = SMB_VFS_NEXT_UNLINK ( handle , file_name ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
*/
/* extract filename and path */
2009-07-02 20:27:44 +04:00
base = strrchr ( smb_fname - > base_name , ' / ' ) ;
2002-09-07 08:05:42 +04:00
if ( base = = NULL ) {
2009-07-02 20:27:44 +04:00
base = smb_fname - > base_name ;
2004-12-07 21:25:53 +03:00
path_name = SMB_STRDUP ( " / " ) ;
2003-04-09 21:36:52 +04:00
ALLOC_CHECK ( path_name , done ) ;
2002-09-07 08:05:42 +04:00
}
else {
2009-07-02 20:27:44 +04:00
path_name = SMB_STRDUP ( smb_fname - > base_name ) ;
2003-04-09 21:36:52 +04:00
ALLOC_CHECK ( path_name , done ) ;
2009-07-02 20:27:44 +04:00
path_name [ base - smb_fname - > base_name ] = ' \0 ' ;
2002-09-07 08:05:42 +04:00
base + + ;
2002-03-19 05:51:48 +03:00
}
2009-07-02 20:27:44 +04:00
/* original filename with path */
DEBUG ( 10 , ( " recycle: fname = %s \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
/* 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
2003-05-12 03:34:18 +04:00
if ( matchparam ( recycle_exclude ( handle ) , base ) ) {
DEBUG ( 3 , ( " recycle: file %s is excluded \n " , base ) ) ;
2009-07-02 20:27:44 +04:00
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
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
2007-04-05 03:33:07 +04:00
if ( matchdirparam ( recycle_exclude_dir ( handle ) , path_name ) ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: directory %s is excluded \n " , path_name ) ) ;
2009-07-02 20:27:44 +04:00
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2002-09-07 08:05:42 +04:00
goto done ;
2002-03-19 05:51:48 +03:00
}
2003-05-12 03:34:18 +04:00
if ( recycle_keep_dir_tree ( handle ) = = True ) {
2009-01-01 05:06:57 +03:00
if ( asprintf ( & temp_name , " %s/%s " , repository , path_name ) = = - 1 ) {
ALLOC_CHECK ( temp_name , done ) ;
}
2003-04-09 21:36:52 +04:00
} else {
2004-12-07 21:25:53 +03:00
temp_name = SMB_STRDUP ( repository ) ;
2002-03-19 05:51:48 +03:00
}
2003-04-09 21:36:52 +04:00
ALLOC_CHECK ( temp_name , done ) ;
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 ) ) ;
if ( recycle_create_dir ( handle , temp_name ) = = False ) {
2009-07-02 20:27:44 +04:00
DEBUG ( 3 , ( " recycle: Could not create directory, "
" purging %s... \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
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
2009-01-01 05:06:57 +03:00
if ( asprintf ( & final_name , " %s/%s " , temp_name , base ) = = - 1 ) {
ALLOC_CHECK ( final_name , done ) ;
}
2009-07-02 20:27:44 +04:00
/* Create smb_fname with final base name and orig stream name. */
2016-03-19 07:19:38 +03:00
smb_fname_final = synthetic_smb_fname ( talloc_tos ( ) ,
final_name ,
smb_fname - > stream_name ,
NULL ,
smb_fname - > flags ) ;
2013-04-12 13:17:00 +04:00
if ( smb_fname_final = = NULL ) {
2009-07-02 20:27:44 +04:00
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
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 ) ) {
2003-05-12 03:34:18 +04:00
if ( recycle_versions ( handle ) = = False | | matchparam ( recycle_noversions ( handle ) , 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 ) ) ) ;
if ( SMB_VFS_NEXT_UNLINK ( handle ,
smb_fname_final ) ! = 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 ) ) {
2003-08-14 23:57:23 +04:00
SAFE_FREE ( final_name ) ;
2009-01-01 05:06:57 +03:00
if ( asprintf ( & final_name , " %s/Copy #%d of %s " , temp_name , i + + , base ) = = - 1 ) {
ALLOC_CHECK ( final_name , done ) ;
}
2009-07-02 20:27:44 +04:00
TALLOC_FREE ( smb_fname_final - > base_name ) ;
smb_fname_final - > base_name = talloc_strdup ( smb_fname_final ,
final_name ) ;
if ( smb_fname_final - > base_name = = NULL ) {
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
goto done ;
}
2002-09-07 08:05:42 +04:00
}
2009-07-02 20:27:44 +04:00
DEBUG ( 10 , ( " recycle: Moving %s to %s \n " , smb_fname_str_dbg ( smb_fname ) ,
smb_fname_str_dbg ( smb_fname_final ) ) ) ;
rc = SMB_VFS_NEXT_RENAME ( handle , smb_fname , smb_fname_final ) ;
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 ) ,
smb_fname_str_dbg ( smb_fname ) ,
smb_fname_str_dbg ( smb_fname_final ) ) ) ;
rc = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
/* touch access date of moved file */
2005-06-21 15:27:17 +04:00
if ( recycle_touch ( handle ) = = True | | recycle_touch_mtime ( handle ) )
2009-07-02 20:27:44 +04:00
recycle_do_touch ( handle , smb_fname_final ,
recycle_touch_mtime ( handle ) ) ;
2002-09-07 08:05:42 +04:00
done :
SAFE_FREE ( path_name ) ;
SAFE_FREE ( temp_name ) ;
SAFE_FREE ( final_name ) ;
2009-07-01 04:04:38 +04:00
TALLOC_FREE ( smb_fname_final ) ;
2006-07-15 02:06:38 +04:00
TALLOC_FREE ( repository ) ;
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
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers vfs_recycle_fns = {
2011-12-04 08:45:04 +04:00
. unlink_fn = recycle_unlink
2009-07-24 04:28:58 +04:00
} ;
2006-12-19 23:16:52 +03:00
NTSTATUS vfs_recycle_init ( void ) ;
2003-04-28 21:48:48 +04:00
NTSTATUS vfs_recycle_init ( void )
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
}