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
* the Free Software Foundation ; either version 2 of the License , or
* ( 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
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
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
static int recycle_connect ( vfs_handle_struct * handle , connection_struct * conn , const char * service , const char * user ) ;
static void recycle_disconnect ( vfs_handle_struct * handle , connection_struct * conn ) ;
static int recycle_unlink ( vfs_handle_struct * handle , connection_struct * conn , 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 */
2002-09-07 08:05:42 +04:00
{ VFS_OP ( recycle_connect ) , SMB_VFS_OP_CONNECT , SMB_VFS_LAYER_TRANSPARENT } ,
{ VFS_OP ( recycle_disconnect ) , SMB_VFS_OP_DISCONNECT , SMB_VFS_LAYER_TRANSPARENT } ,
2002-03-19 05:51:48 +03:00
/* File operations */
2002-09-07 08:05:42 +04:00
{ VFS_OP ( recycle_unlink ) , SMB_VFS_OP_UNLINK , SMB_VFS_LAYER_TRANSPARENT } ,
2002-08-27 13:45:26 +04:00
2002-09-07 08:05:42 +04:00
{ NULL , SMB_VFS_OP_NOOP , SMB_VFS_LAYER_NOOP }
2002-03-19 05:51:48 +03:00
} ;
2003-05-12 03:34:18 +04:00
static int recycle_connect ( vfs_handle_struct * handle , connection_struct * conn , 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
2003-05-12 03:34:18 +04:00
return VFS_NEXT_CONNECT ( handle , conn , service , user ) ;
}
2003-04-24 07:46:17 +04:00
2003-05-12 03:34:18 +04:00
static void recycle_disconnect ( vfs_handle_struct * handle , connection_struct * conn )
{
DEBUG ( 10 , ( " recycle_disconnect() connect to service[%s]. \n " ,
lp_servicename ( SNUM ( conn ) ) ) ) ;
2003-04-24 07:46:17 +04:00
2003-05-12 03:34:18 +04:00
VFS_NEXT_DISCONNECT ( handle , conn ) ;
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
2003-05-12 03:34:18 +04:00
static BOOL recycle_keep_dir_tree ( vfs_handle_struct * handle )
{
BOOL ret ;
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 ;
}
static BOOL recycle_versions ( vfs_handle_struct * handle )
{
BOOL ret ;
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 ;
}
static BOOL recycle_touch ( vfs_handle_struct * handle )
{
BOOL ret ;
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
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
2003-05-12 03:34:18 +04:00
static int recycle_maxsize ( vfs_handle_struct * handle )
{
int maxsize ;
maxsize = lp_parm_int ( SNUM ( handle - > conn ) , " recycle " , " maxsize " , - 1 ) ;
2003-04-24 07:46:17 +04:00
2003-05-12 03:34:18 +04:00
DEBUG ( 10 , ( " recycle: maxsize = %d \n " , maxsize ) ) ;
return maxsize ;
2002-03-19 05:51:48 +03:00
}
2003-05-12 03:34:18 +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
2003-05-12 03:34:18 +04:00
if ( VFS_NEXT_STAT ( handle , handle - > conn , 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
}
2003-05-12 03:34:18 +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 ;
2003-05-12 03:34:18 +04:00
if ( VFS_NEXT_STAT ( handle , handle - > conn , 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
if ( VFS_NEXT_STAT ( handle , handle - > conn , fname , & st ) ! = 0 ) {
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
* */
2003-05-12 03:34:18 +04:00
static BOOL recycle_create_dir ( vfs_handle_struct * handle , const char * dname )
2002-09-07 08:05:42 +04:00
{
int len ;
mode_t mode ;
char * new_dir = NULL ;
char * tmp_str = NULL ;
char * token ;
char * tok_str ;
BOOL ret = False ;
mode = S_IREAD | S_IWRITE | S_IEXEC ;
tmp_str = strdup ( dname ) ;
ALLOC_CHECK ( tmp_str , done ) ;
tok_str = tmp_str ;
len = strlen ( dname ) ;
new_dir = ( char * ) malloc ( len + 1 ) ;
ALLOC_CHECK ( new_dir , done ) ;
* new_dir = ' \0 ' ;
/* Create directory tree if neccessary */
for ( token = strtok ( tok_str , " / " ) ; token ; token = strtok ( NULL , " / " ) ) {
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 ) ) ;
if ( VFS_NEXT_MKDIR ( handle , handle - > conn , new_dir , mode ) ! = 0 ) {
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 ) ;
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
/**
* Check if needle is contained exactly in haystack
* @ param haystack list of parameters separated by delimimiter character
* @ param needle string to be matched exactly to haystack
* @ return True if found
* */
2003-05-12 03:34:18 +04:00
static BOOL checkparam ( 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 + + ) {
if ( strequal ( haystack_list [ i ] , needle ) ) {
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
}
/**
* 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
* */
2003-05-12 03:34:18 +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 + + ) {
if ( ! unix_wild_match ( ( char * ) haystack_list [ i ] , ( char * ) needle ) ) {
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
}
/**
* Touch access date
* */
2003-05-12 03:34:18 +04:00
static void recycle_do_touch ( vfs_handle_struct * handle , const char * fname )
2002-09-07 08:05:42 +04:00
{
SMB_STRUCT_STAT st ;
struct utimbuf tb ;
time_t currtime ;
2003-05-12 03:34:18 +04:00
if ( VFS_NEXT_STAT ( handle , handle - > conn , fname , & st ) ! = 0 ) {
DEBUG ( 0 , ( " recycle: stat for %s returned %s \n " , fname , strerror ( errno ) ) ) ;
2002-09-07 08:05:42 +04:00
return ;
}
currtime = time ( & currtime ) ;
tb . actime = currtime ;
tb . modtime = st . st_mtime ;
2003-05-12 03:34:18 +04:00
if ( VFS_NEXT_UTIME ( handle , handle - > conn , fname , & tb ) = = - 1 ) {
DEBUG ( 0 , ( " recycle: touching %s failed, reason = %s \n " , fname , strerror ( errno ) ) ) ;
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
* */
2003-05-12 03:34:18 +04:00
static int recycle_unlink ( vfs_handle_struct * handle , connection_struct * conn , const char * file_name )
2002-03-19 05:51:48 +03:00
{
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 ;
int maxsize ;
2003-04-24 07:46:17 +04:00
SMB_OFF_T file_size ; /* space_avail; */
2002-09-07 08:05:42 +04:00
BOOL exist ;
2002-09-08 07:55:37 +04:00
int rc = - 1 ;
2002-09-07 08:05:42 +04:00
2003-05-12 03:34:18 +04:00
repository = alloc_sub_conn ( conn , ( char * ) recycle_repository ( handle ) ) ;
ALLOC_CHECK ( repository , done ) ;
/* shouldn't we allow absolute path names here? --metze */
trim_string ( repository , " / " , " / " ) ;
if ( ! repository | | * ( repository ) = = ' \0 ' ) {
DEBUG ( 3 , ( " recycle: repository path not set, purging %s... \n " , file_name ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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 " ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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 ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , file_name ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
*/
/* FIXME: this is wrong, we should check the hole size of the recycle bin is
* 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 ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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
*
2003-05-12 03:34:18 +04:00
space_avail = VFS_NEXT_DISK_FREE ( handle , conn , " . " , 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 ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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 ;
2003-04-09 21:36:52 +04:00
path_name = strdup ( " / " ) ;
ALLOC_CHECK ( path_name , done ) ;
2002-09-07 08:05:42 +04:00
}
else {
2003-04-09 21:36:52 +04:00
path_name = strdup ( file_name ) ;
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 ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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
2002-09-07 08:05:42 +04:00
/* FIXME: this check will fail if we have more than one level of directories,
* we shoud check for every level 1 , 1 / 2 , 1 / 2 / 3 , 1 / 2 / 3 / 4 . . . .
* - - - simo
*/
2003-05-12 03:34:18 +04:00
if ( checkparam ( recycle_exclude_dir ( handle ) , path_name ) ) {
DEBUG ( 3 , ( " recycle: directory %s is excluded \n " , path_name ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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 ) {
asprintf ( & temp_name , " %s/%s " , repository , path_name ) ;
2003-04-09 21:36:52 +04:00
} else {
2003-05-12 03:34:18 +04:00
temp_name = 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 ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , 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
2003-04-24 07:46:17 +04:00
asprintf ( & final_name , " %s/%s " , temp_name , base ) ;
2002-09-08 07:55:37 +04:00
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 ) ) ;
if ( VFS_NEXT_UNLINK ( handle , conn , final_name ) ! = 0 ) {
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 ) ) {
snprintf ( final_name , PATH_MAX - 1 , " %s/Copy #%d of %s " , temp_name , i + + , base ) ;
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 ) ) ;
rc = VFS_NEXT_RENAME ( handle , conn , 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 ) ) ;
rc = VFS_NEXT_UNLINK ( handle , conn , file_name ) ;
2002-09-07 08:05:42 +04:00
goto done ;
}
/* touch access date of moved file */
2003-05-12 03:34:18 +04:00
if ( recycle_touch ( handle ) = = True )
recycle_do_touch ( handle , final_name ) ;
2002-09-07 08:05:42 +04:00
done :
SAFE_FREE ( path_name ) ;
SAFE_FREE ( temp_name ) ;
SAFE_FREE ( final_name ) ;
2003-05-12 03:34:18 +04:00
SAFE_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
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 ) ;
if ( NT_STATUS_IS_ERR ( ret ) )
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
}