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"
# 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
2006-07-11 22:01:26 +04:00
static int recycle_connect ( vfs_handle_struct * handle , const char * service , const char * user ) ;
static void recycle_disconnect ( vfs_handle_struct * handle ) ;
static int recycle_unlink ( vfs_handle_struct * handle , const char * name ) ;
2002-03-19 05:51:48 +03:00
2002-07-30 13:59:53 +04:00
static vfs_op_tuple recycle_ops [ ] = {
2002-03-19 05:51:48 +03:00
2002-07-30 13:59:53 +04:00
/* Disk operations */
2003-05-14 14:59:01 +04:00
{ SMB_VFS_OP ( recycle_connect ) , SMB_VFS_OP_CONNECT , SMB_VFS_LAYER_TRANSPARENT } ,
{ SMB_VFS_OP ( recycle_disconnect ) , SMB_VFS_OP_DISCONNECT , SMB_VFS_LAYER_TRANSPARENT } ,
2002-03-19 05:51:48 +03:00
/* File operations */
2003-05-14 14:59:01 +04:00
{ SMB_VFS_OP ( recycle_unlink ) , SMB_VFS_OP_UNLINK , SMB_VFS_LAYER_TRANSPARENT } ,
2002-08-27 13:45:26 +04:00
2003-05-14 14:59:01 +04:00
{ SMB_VFS_OP ( NULL ) , SMB_VFS_OP_NOOP , SMB_VFS_LAYER_NOOP }
2002-03-19 05:51:48 +03:00
} ;
2006-07-11 22:01:26 +04:00
static int recycle_connect ( vfs_handle_struct * handle , const char * service , const char * user )
2002-03-19 05:51:48 +03:00
{
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle_connect() connect to service[%s] as user[%s]. \n " ,
service , user ) ) ;
2003-04-24 07:46:17 +04:00
2006-07-11 22:01:26 +04:00
return SMB_VFS_NEXT_CONNECT ( handle , service , user ) ;
2003-05-12 03:34:18 +04:00
}
2003-04-24 07:46:17 +04:00
2006-07-11 22:01:26 +04:00
static void recycle_disconnect ( vfs_handle_struct * handle )
2003-05-12 03:34:18 +04:00
{
DEBUG ( 10 , ( " recycle_disconnect() connect to service[%s]. \n " ,
2006-07-11 22:01:26 +04:00
lp_servicename ( SNUM ( handle - > conn ) ) ) ) ;
2003-04-24 07:46:17 +04:00
2006-07-11 22:01:26 +04:00
SMB_VFS_NEXT_DISCONNECT ( handle ) ;
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 ) ) ;
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 ;
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 " ) ) ;
2003-04-24 07:46:17 +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 " ) ) ;
2003-04-24 07:46:17 +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 " ) ) ;
2003-04-24 07:46:17 +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 " ) ) ;
return ret ;
}
2003-05-12 03:34:18 +04:00
static const char * * recycle_exclude ( vfs_handle_struct * handle )
{
const char * * tmp_lp ;
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 : " " ) ) ;
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 ;
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 : " " ) ) ;
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 ;
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 : " " ) ) ;
return tmp_lp ;
}
2003-04-24 07:46:17 +04:00
2007-03-02 02:57:37 +03:00
static SMB_OFF_T recycle_maxsize ( vfs_handle_struct * handle )
2003-05-12 03:34:18 +04:00
{
2007-03-02 02:57:37 +03:00
SMB_OFF_T maxsize ;
2003-05-12 03:34:18 +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 ) ) ;
2003-05-12 03:34:18 +04:00
return maxsize ;
2002-03-19 05:51:48 +03:00
}
2007-03-02 02:57:37 +03:00
static SMB_OFF_T recycle_minsize ( vfs_handle_struct * handle )
{
SMB_OFF_T minsize ;
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 ) ) ;
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
{
2002-03-23 23:48:45 +03:00
SMB_STRUCT_STAT st ;
2002-03-19 05:51:48 +03:00
2006-07-11 22:01:26 +04:00
if ( SMB_VFS_NEXT_STAT ( handle , dname , & st ) = = 0 ) {
2002-09-07 08:05:42 +04:00
if ( S_ISDIR ( st . st_mode ) ) {
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
}
2007-10-19 04:40:25 +04:00
static bool recycle_file_exist ( vfs_handle_struct * handle , const char * fname )
2002-03-19 05:51:48 +03:00
{
2002-09-07 08:05:42 +04:00
SMB_STRUCT_STAT st ;
2006-07-11 22:01:26 +04:00
if ( SMB_VFS_NEXT_STAT ( handle , fname , & st ) = = 0 ) {
2002-09-07 08:05:42 +04:00
if ( S_ISREG ( st . st_mode ) ) {
return True ;
}
}
return False ;
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
* */
2003-05-12 03:34:18 +04:00
static SMB_OFF_T recycle_get_file_size ( vfs_handle_struct * handle , const char * fname )
2002-03-19 05:51:48 +03:00
{
2002-03-23 23:48:45 +03:00
SMB_STRUCT_STAT st ;
2003-05-12 03:34:18 +04:00
2006-07-11 22:01:26 +04:00
if ( SMB_VFS_NEXT_STAT ( handle , fname , & st ) ! = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 0 , ( " recycle: stat for %s returned %s \n " , fname , strerror ( errno ) ) ) ;
2002-09-07 08:05:42 +04:00
return ( SMB_OFF_T ) 0 ;
}
2003-05-12 03:34:18 +04:00
2002-09-07 08:05:42 +04:00
return ( st . st_size ) ;
}
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. */
safe_strcat ( new_dir , " / " , len ) ;
}
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 ) ) {
2003-04-07 22:13:03 +04:00
safe_strcat ( new_dir , token , len ) ;
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 {
2003-05-12 03:34:18 +04:00
DEBUG ( 5 , ( " recycle: creating new dir %s \n " , new_dir ) ) ;
2006-07-11 22:01:26 +04:00
if ( SMB_VFS_NEXT_MKDIR ( handle , new_dir , 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 ) ) ) ;
2002-09-07 08:05:42 +04:00
ret = False ;
goto done ;
}
}
2003-04-07 22:13:03 +04:00
safe_strcat ( new_dir , " / " , len ) ;
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
* */
2007-07-04 03:34:01 +04:00
static void recycle_do_touch ( vfs_handle_struct * handle , const char * fname ,
2007-10-19 04:40:25 +04:00
bool touch_mtime )
2002-09-07 08:05:42 +04:00
{
SMB_STRUCT_STAT st ;
2007-03-06 02:40:03 +03:00
struct timespec ts [ 2 ] ;
2007-07-04 03:48:02 +04:00
int ret , err ;
2007-07-04 03:34:01 +04:00
2006-07-11 22:01:26 +04:00
if ( SMB_VFS_NEXT_STAT ( handle , fname , & st ) ! = 0 ) {
2007-07-04 03:34:01 +04:00
DEBUG ( 0 , ( " recycle: stat for %s returned %s \n " ,
fname , strerror ( errno ) ) ) ;
2002-09-07 08:05:42 +04:00
return ;
}
2007-03-06 02:40:03 +03:00
ts [ 0 ] = timespec_current ( ) ; /* atime */
ts [ 1 ] = touch_mtime ? ts [ 0 ] : get_mtimespec ( & st ) ; /* mtime */
2002-09-07 08:05:42 +04:00
2007-07-04 03:34:01 +04:00
become_root ( ) ;
2007-07-04 03:48:02 +04:00
ret = SMB_VFS_NEXT_NTIMES ( handle , fname , ts ) ;
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 " ,
fname , strerror ( err ) ) ) ;
2002-09-07 08:05:42 +04:00
}
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
* */
2006-07-11 22:01:26 +04:00
static int recycle_unlink ( vfs_handle_struct * handle , const char * file_name )
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 ;
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 ;
2007-03-02 02:57:37 +03:00
SMB_OFF_T maxsize , minsize ;
2003-04-24 07:46:17 +04:00
SMB_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
2006-07-15 02:06:38 +04:00
repository = talloc_sub_advanced ( NULL , lp_servicename ( SNUM ( conn ) ) ,
2008-05-08 18:06:42 +04:00
conn - > server_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2008-06-19 18:54:12 +04:00
conn - > server_info - > utok . gid ,
2008-05-11 13:26:33 +04:00
conn - > server_info - > sanitized_username ,
2008-06-19 17:48:05 +04:00
pdb_get_domain ( conn - > server_info - > sam_account ) ,
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 ' , ' / ' ) ;
2003-05-12 03:34:18 +04:00
if ( ! repository | | * ( repository ) = = ' \0 ' ) {
DEBUG ( 3 , ( " recycle: repository path not set, purging %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 ;
}
2002-03-19 05:51:48 +03:00
2002-09-07 08:05:42 +04:00
/* we don't recycle the recycle bin... */
2003-05-12 03:34:18 +04:00
if ( strncmp ( file_name , repository , strlen ( repository ) ) = = 0 ) {
DEBUG ( 3 , ( " recycle: File is within recycling bin, unlinking ... \n " ) ) ;
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 ;
}
2002-03-19 05:51:48 +03:00
2003-05-12 03:34:18 +04:00
file_size = recycle_get_file_size ( handle , file_name ) ;
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 ) {
DEBUG ( 3 , ( " recycle: File %s exceeds maximum recycle size, purging... \n " , file_name ) ) ;
2007-03-02 02:57:37 +03:00
rc = SMB_VFS_NEXT_UNLINK ( handle , file_name ) ;
goto done ;
}
minsize = recycle_minsize ( handle ) ;
if ( minsize > 0 & & file_size < minsize ) {
DEBUG ( 3 , ( " recycle: File %s lowers minimum recycle size, 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 ;
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 */
2003-04-09 21:36:52 +04:00
base = strrchr ( file_name , ' / ' ) ;
2002-09-07 08:05:42 +04:00
if ( base = = NULL ) {
base = file_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 {
2004-12-07 21:25:53 +03:00
path_name = SMB_STRDUP ( file_name ) ;
2003-04-09 21:36:52 +04:00
ALLOC_CHECK ( path_name , done ) ;
path_name [ base - file_name ] = ' \0 ' ;
2002-09-07 08:05:42 +04:00
base + + ;
2002-03-19 05:51:48 +03:00
}
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: fname = %s \n " , file_name ) ) ; /* original filename with path */
DEBUG ( 10 , ( " recycle: fpath = %s \n " , path_name ) ) ; /* original path */
DEBUG ( 10 , ( " recycle: base = %s \n " , base ) ) ; /* filename without path */
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 ) ) ;
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 ;
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 ) ) ;
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 ;
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 ) {
DEBUG ( 3 , ( " recycle: Could not create directory, purging %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 ;
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 ) ;
}
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: recycled file name: %s \n " , final_name ) ) ; /* new filename with path */
2002-09-07 08:05:42 +04:00
/* check if we should delete file from recycle bin */
2003-05-12 03:34:18 +04:00
if ( recycle_file_exist ( handle , final_name ) ) {
if ( recycle_versions ( handle ) = = False | | matchparam ( recycle_noversions ( handle ) , base ) = = True ) {
DEBUG ( 3 , ( " recycle: Removing old file %s from recycle bin \n " , final_name ) ) ;
2006-07-11 22:01:26 +04:00
if ( SMB_VFS_NEXT_UNLINK ( handle , final_name ) ! = 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 ;
2003-05-12 03:34:18 +04:00
while ( recycle_file_exist ( handle , final_name ) ) {
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 ) ;
}
2002-09-07 08:05:42 +04:00
}
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: Moving %s to %s \n " , file_name , final_name ) ) ;
2006-07-11 22:01:26 +04:00
rc = SMB_VFS_NEXT_RENAME ( handle , file_name , final_name ) ;
2002-09-07 08:05:42 +04:00
if ( rc ! = 0 ) {
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " recycle: Move error %d (%s), purging file %s (%s) \n " , errno , strerror ( errno ) , file_name , final_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 ;
}
/* touch access date of moved file */
2005-06-21 15:27:17 +04:00
if ( recycle_touch ( handle ) = = True | | recycle_touch_mtime ( handle ) )
recycle_do_touch ( handle , final_name , 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 ) ;
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
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
{
NTSTATUS ret = smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " recycle " , recycle_ops ) ;
2003-06-22 14:09:52 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) )
2003-05-12 03:34:18 +04:00
return ret ;
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 ) ) ;
}
return ret ;
2003-04-16 18:45:11 +04:00
}