2002-09-07 04:05:42 +00:00
/*
* Recycle bin VFS module for Samba .
2002-03-19 02:51:48 +00: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 09:59:53 +00:00
* Copyright ( C ) 2002 , Alexander Bokovoy - cascaded VFS adoption ,
2002-09-07 04:05:42 +00:00
* Copyright ( C ) 2002 , Juergen Hasch - added some options .
* Copyright ( C ) 2002 , Simo Sorce
2002-03-19 02:51:48 +00: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 04:05:42 +00:00
*
2002-03-19 02:51:48 +00: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 04:05:42 +00:00
*
2002-03-19 02:51:48 +00: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 04:05:42 +00: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
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
static const char * delimiter = " | " ; /* delimiter for options */
/* One per connection */
typedef struct recycle_bin_struct
{
2002-12-09 12:06:15 +00:00
TALLOC_CTX * mem_ctx ;
2002-09-07 04:05:42 +00:00
char * repository ; /* name of the recycle bin directory */
2002-09-08 03:55:37 +00:00
BOOL keep_dir_tree ; /* keep directory structure of deleted file in recycle bin */
2002-09-07 04:05:42 +00:00
BOOL versions ; /* create versions of deleted files with identical name */
BOOL touch ; /* touch access date of deleted file */
char * exclude ; /* which files to exclude */
char * exclude_dir ; /* which directories to exclude */
char * noversions ; /* which files to exclude from versioning */
SMB_OFF_T maxsize ; /* maximum file size to be saved */
} recycle_bin_struct ;
2002-12-09 12:06:15 +00:00
typedef struct recycle_bin_connections {
int conn ;
recycle_bin_struct * data ;
struct recycle_bin_connections * next ;
} recycle_bin_connections ;
typedef struct recycle_bin_private_data {
TALLOC_CTX * mem_ctx ;
recycle_bin_connections * conns ;
} recycle_bin_private_data ;
struct smb_vfs_handle_struct * recycle_bin_private_handle ;
2002-09-07 04:05:42 +00:00
/* VFS operations */
2002-07-30 09:59:53 +00:00
static struct vfs_ops default_vfs_ops ; /* For passthrough operation */
2002-09-07 04:05:42 +00:00
2002-03-19 02:51:48 +00:00
static int recycle_connect ( struct connection_struct * conn , const char * service , const char * user ) ;
static void recycle_disconnect ( struct connection_struct * conn ) ;
2002-09-07 04:05:42 +00:00
static int recycle_unlink ( connection_struct * , const char * ) ;
# define VFS_OP(x) ((void *) x)
2002-03-19 02:51:48 +00:00
2002-07-30 09:59:53 +00:00
static vfs_op_tuple recycle_ops [ ] = {
2002-03-19 02:51:48 +00:00
2002-07-30 09:59:53 +00:00
/* Disk operations */
2002-09-07 04:05:42 +00: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 02:51:48 +00:00
/* File operations */
2002-09-07 04:05:42 +00:00
{ VFS_OP ( recycle_unlink ) , SMB_VFS_OP_UNLINK , SMB_VFS_LAYER_TRANSPARENT } ,
2002-08-27 09:45:26 +00:00
2002-09-07 04:05:42 +00:00
{ NULL , SMB_VFS_OP_NOOP , SMB_VFS_LAYER_NOOP }
2002-03-19 02:51:48 +00:00
} ;
2002-09-07 04:05:42 +00:00
/**
* VFS initialisation function .
*
* @ retval initialised vfs_op_tuple array
* */
2002-10-21 13:41:34 +00:00
vfs_op_tuple * vfs_init ( int * vfs_version , struct vfs_ops * def_vfs_ops ,
struct smb_vfs_handle_struct * vfs_handle )
2002-03-19 02:51:48 +00:00
{
2002-12-09 12:06:15 +00:00
TALLOC_CTX * mem_ctx = NULL ;
2002-09-07 04:05:42 +00:00
DEBUG ( 10 , ( " Initializing VFS module recycle \n " ) ) ;
2002-03-19 02:51:48 +00:00
* vfs_version = SMB_VFS_INTERFACE_VERSION ;
2002-07-30 09:59:53 +00:00
memcpy ( & default_vfs_ops , def_vfs_ops , sizeof ( struct vfs_ops ) ) ;
2002-09-08 03:55:37 +00:00
vfs_recycle_debug_level = debug_add_class ( " vfs_recycle_bin " ) ;
2002-09-07 04:05:42 +00:00
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 ( 0 , ( " vfs_recycle: Debug class number of 'vfs_recycle': %d \n " , vfs_recycle_debug_level ) ) ;
}
2002-07-30 09:59:53 +00:00
2002-12-09 12:06:15 +00:00
recycle_bin_private_handle = vfs_handle ;
2002-12-22 16:02:36 +00:00
if ( ! ( mem_ctx = talloc_init ( " recycle bin data " ) ) ) {
2002-12-09 12:06:15 +00:00
DEBUG ( 0 , ( " Failed to allocate memory in VFS module recycle_bin \n " ) ) ;
return NULL ;
}
recycle_bin_private_handle - > data = talloc ( mem_ctx , sizeof ( recycle_bin_private_data ) ) ;
if ( recycle_bin_private_handle - > data = = NULL ) {
DEBUG ( 0 , ( " Failed to allocate memory in VFS module recycle_bin \n " ) ) ;
return NULL ;
}
( ( recycle_bin_private_data * ) ( recycle_bin_private_handle - > data ) ) - > mem_ctx = mem_ctx ;
( ( recycle_bin_private_data * ) ( recycle_bin_private_handle - > data ) ) - > conns = NULL ;
2002-07-30 09:59:53 +00:00
return recycle_ops ;
}
2002-09-07 04:05:42 +00:00
/**
* VFS finalization function .
*
* */
2002-12-09 12:06:15 +00:00
void vfs_done ( void )
2002-07-30 09:59:53 +00:00
{
2002-12-09 12:06:15 +00:00
recycle_bin_private_data * recdata ;
recycle_bin_connections * recconn ;
DEBUG ( 10 , ( " Unloading/Cleaning VFS module recycle bin \n " ) ) ;
if ( recycle_bin_private_handle )
recdata = ( recycle_bin_private_data * ) ( recycle_bin_private_handle - > data ) ;
else {
DEBUG ( 0 , ( " Recycle bin not initialized! \n " ) ) ;
return ;
}
if ( recdata ) {
if ( recdata - > conns ) {
recconn = recdata - > conns ;
while ( recconn ) {
talloc_destroy ( recconn - > data - > mem_ctx ) ;
recconn = recconn - > next ;
}
}
if ( recdata - > mem_ctx ) {
talloc_destroy ( recdata - > mem_ctx ) ;
}
recdata = NULL ;
}
2002-03-19 02:51:48 +00:00
}
static int recycle_connect ( struct connection_struct * conn , const char * service , const char * user )
{
2002-09-07 04:05:42 +00:00
TALLOC_CTX * ctx = NULL ;
recycle_bin_struct * recbin ;
2002-12-09 12:06:15 +00:00
recycle_bin_connections * recconn ;
recycle_bin_connections * recconnbase ;
recycle_bin_private_data * recdata ;
2002-09-07 04:05:42 +00:00
char * tmp_str ;
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
DEBUG ( 10 , ( " Called for service %s (%d) as user %s \n " , service , SNUM ( conn ) , user ) ) ;
2002-03-19 02:51:48 +00:00
2002-12-09 12:06:15 +00:00
if ( recycle_bin_private_handle )
recdata = ( recycle_bin_private_data * ) ( recycle_bin_private_handle - > data ) ;
else {
DEBUG ( 0 , ( " Recycle bin not initialized! \n " ) ) ;
return - 1 ;
}
2002-12-22 16:02:36 +00:00
if ( ! ( ctx = talloc_init ( " recycle bin connection " ) ) ) {
2002-09-07 04:05:42 +00:00
DEBUG ( 0 , ( " Failed to allocate memory in VFS module recycle_bin \n " ) ) ;
2002-12-09 12:06:15 +00:00
return - 1 ;
2002-03-19 02:51:48 +00:00
}
2002-08-27 09:45:26 +00:00
2002-12-09 12:06:15 +00:00
recbin = talloc ( ctx , sizeof ( recycle_bin_struct ) ) ;
if ( recbin = = NULL ) {
2002-09-07 04:05:42 +00:00
DEBUG ( 0 , ( " Failed to allocate memory in VFS module recycle_bin \n " ) ) ;
return - 1 ;
}
2002-12-09 12:06:15 +00:00
recbin - > mem_ctx = ctx ;
2002-09-07 04:05:42 +00:00
/* Set defaults */
2002-12-09 12:06:15 +00:00
recbin - > repository = talloc_strdup ( recbin - > mem_ctx , " .recycle " ) ;
2002-09-07 04:05:42 +00:00
ALLOC_CHECK ( recbin - > repository , error ) ;
2002-09-08 03:55:37 +00:00
recbin - > keep_dir_tree = False ;
2002-09-07 04:05:42 +00:00
recbin - > versions = False ;
recbin - > touch = False ;
recbin - > exclude = " " ;
recbin - > exclude_dir = " " ;
recbin - > noversions = " " ;
recbin - > maxsize = 0 ;
/* parse configuration options */
2002-12-09 13:02:27 +00:00
if ( ( tmp_str = lp_parm_string ( SNUM ( conn ) , " vfs_recycle_bin " , " repository " ) ) ! = NULL ) {
2002-12-09 12:06:15 +00:00
recbin - > repository = talloc_sub_conn ( recbin - > mem_ctx , conn , tmp_str ) ;
2002-09-07 04:05:42 +00:00
ALLOC_CHECK ( recbin - > repository , error ) ;
trim_string ( recbin - > repository , " / " , " / " ) ;
DEBUG ( 5 , ( " recycle.bin: repository = %s \n " , recbin - > repository ) ) ;
}
2002-12-09 13:02:27 +00:00
recbin - > keep_dir_tree = lp_parm_bool ( SNUM ( conn ) , " vfs_recycle_bin " , " keeptree " ) ;
DEBUG ( 5 , ( " recycle.bin: keeptree = %d \n " , recbin - > keep_dir_tree ) ) ;
recbin - > versions = lp_parm_bool ( SNUM ( conn ) , " vfs_recycle_bin " , " versions " ) ;
DEBUG ( 5 , ( " recycle.bin: versions = %d \n " , recbin - > versions ) ) ;
recbin - > touch = lp_parm_bool ( SNUM ( conn ) , " vfs_recycle_bin " , " touch " ) ;
DEBUG ( 5 , ( " recycle.bin: touch = %d \n " , recbin - > touch ) ) ;
recbin - > maxsize = lp_parm_ulong ( SNUM ( conn ) , " vfs_recycle_bin " , " maxsize " ) ;
if ( recbin - > maxsize = = 0 ) {
recbin - > maxsize = - 1 ;
DEBUG ( 5 , ( " recycle.bin: maxsize = -infinite- \n " ) ) ;
} else {
DEBUG ( 5 , ( " recycle.bin: maxsize = %ld \n " , ( long int ) recbin - > maxsize ) ) ;
2002-09-07 04:05:42 +00:00
}
2002-12-09 13:02:27 +00:00
if ( ( tmp_str = lp_parm_string ( SNUM ( conn ) , " vfs_recycle_bin " , " exclude " ) ) ! = NULL ) {
2002-12-09 12:06:15 +00:00
recbin - > exclude = talloc_strdup ( recbin - > mem_ctx , tmp_str ) ;
2002-09-07 04:05:42 +00:00
ALLOC_CHECK ( recbin - > exclude , error ) ;
DEBUG ( 5 , ( " recycle.bin: exclude = %s \n " , recbin - > exclude ) ) ;
}
2002-12-09 13:02:27 +00:00
if ( ( tmp_str = lp_parm_string ( SNUM ( conn ) , " vfs_recycle_bin " , " exclude_dir " ) ) ! = NULL ) {
2002-12-09 12:06:15 +00:00
recbin - > exclude_dir = talloc_strdup ( recbin - > mem_ctx , tmp_str ) ;
2002-09-07 04:05:42 +00:00
ALLOC_CHECK ( recbin - > exclude_dir , error ) ;
DEBUG ( 5 , ( " recycle.bin: exclude_dir = %s \n " , recbin - > exclude_dir ) ) ;
}
2002-12-09 13:02:27 +00:00
if ( ( tmp_str = lp_parm_string ( SNUM ( conn ) , " vfs_recycle_bin " , " noversions " ) ) ! = NULL ) {
2002-12-09 12:06:15 +00:00
recbin - > noversions = talloc_strdup ( recbin - > mem_ctx , tmp_str ) ;
2002-09-07 04:05:42 +00:00
ALLOC_CHECK ( recbin - > noversions , error ) ;
DEBUG ( 5 , ( " recycle.bin: noversions = %s \n " , recbin - > noversions ) ) ;
}
2002-03-19 02:51:48 +00:00
2002-12-09 12:06:15 +00:00
recconn = talloc ( recdata - > mem_ctx , sizeof ( recycle_bin_connections ) ) ;
if ( recconn = = NULL ) {
DEBUG ( 0 , ( " Failed to allocate memory in VFS module recycle_bin \n " ) ) ;
goto error ;
}
recconn - > conn = SNUM ( conn ) ;
recconn - > data = recbin ;
recconn - > next = NULL ;
if ( recdata - > conns ) {
recconnbase = recdata - > conns ;
while ( recconnbase - > next ! = NULL ) recconnbase = recconnbase - > next ;
recconnbase - > next = recconn ;
} else {
recdata - > conns = recconn ;
}
2002-09-07 04:05:42 +00:00
return default_vfs_ops . connect ( conn , service , user ) ;
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
error :
talloc_destroy ( ctx ) ;
return - 1 ;
2002-03-19 02:51:48 +00:00
}
static void recycle_disconnect ( struct connection_struct * conn )
{
2002-12-09 12:06:15 +00:00
recycle_bin_private_data * recdata ;
recycle_bin_connections * recconn ;
2002-09-07 04:05:42 +00:00
DEBUG ( 10 , ( " Disconnecting VFS module recycle bin \n " ) ) ;
2002-12-09 12:06:15 +00:00
if ( recycle_bin_private_handle )
recdata = ( recycle_bin_private_data * ) ( recycle_bin_private_handle - > data ) ;
else {
DEBUG ( 0 , ( " Recycle bin not initialized! \n " ) ) ;
return ;
}
if ( recdata ) {
if ( recdata - > conns ) {
if ( recdata - > conns - > conn = = SNUM ( conn ) ) {
talloc_destroy ( recdata - > conns - > data - > mem_ctx ) ;
recdata - > conns = recdata - > conns - > next ;
} else {
recconn = recdata - > conns ;
while ( recconn - > next ) {
if ( recconn - > next - > conn = = SNUM ( conn ) ) {
talloc_destroy ( recconn - > next - > data - > mem_ctx ) ;
recconn - > next = recconn - > next - > next ;
break ;
}
recconn = recconn - > next ;
}
}
}
2002-09-07 04:05:42 +00:00
}
default_vfs_ops . disconnect ( conn ) ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
static BOOL recycle_directory_exist ( connection_struct * conn , const char * dname )
2002-03-19 02:51:48 +00:00
{
2002-03-23 20:48:45 +00:00
SMB_STRUCT_STAT st ;
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
if ( default_vfs_ops . stat ( conn , dname , & st ) = = 0 ) {
if ( S_ISDIR ( st . st_mode ) ) {
return True ;
}
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
return False ;
2002-03-19 02:51:48 +00:00
}
static BOOL recycle_file_exist ( connection_struct * conn , const char * fname )
{
2002-09-07 04:05:42 +00:00
SMB_STRUCT_STAT st ;
if ( default_vfs_ops . stat ( conn , fname , & st ) = = 0 ) {
if ( S_ISREG ( st . st_mode ) ) {
return True ;
}
}
return False ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
/**
* Return file size
* @ param conn connection
* @ param fname file name
* @ return size in bytes
* */
2002-03-19 02:51:48 +00:00
static SMB_OFF_T recycle_get_file_size ( connection_struct * conn , const char * fname )
{
2002-03-23 20:48:45 +00:00
SMB_STRUCT_STAT st ;
2002-09-07 04:05:42 +00:00
if ( default_vfs_ops . stat ( conn , fname , & st ) ! = 0 ) {
DEBUG ( 0 , ( " recycle.bin: stat for %s returned %s \n " , fname , strerror ( errno ) ) ) ;
return ( SMB_OFF_T ) 0 ;
}
return ( st . st_size ) ;
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
/**
* Create directory tree
* @ param conn connection
* @ param dname Directory tree to be created
* @ return Returns True for success
* */
static BOOL recycle_create_dir ( connection_struct * conn , const char * dname )
{
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 , " / " ) ) {
safe_strcat ( new_dir , token , len ) ;
if ( recycle_directory_exist ( conn , new_dir ) )
DEBUG ( 10 , ( " recycle.bin: dir %s already exists \n " , new_dir ) ) ;
else {
DEBUG ( 5 , ( " recycle.bin: creating new dir %s \n " , new_dir ) ) ;
if ( default_vfs_ops . mkdir ( conn , new_dir , mode ) ! = 0 ) {
DEBUG ( 1 , ( " recycle.bin: mkdir failed for %s with error: %s \n " , new_dir , strerror ( errno ) ) ) ;
ret = False ;
goto done ;
}
}
safe_strcat ( new_dir , " / " , len ) ;
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
ret = True ;
done :
SAFE_FREE ( tmp_str ) ;
SAFE_FREE ( new_dir ) ;
return ret ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00: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
* */
2002-09-08 03:55:37 +00:00
static BOOL checkparam ( const char * haystack , const char * needle )
2002-09-07 04:05:42 +00:00
{
char * token ;
char * tok_str ;
char * tmp_str ;
BOOL ret = False ;
if ( haystack = = NULL | | strlen ( haystack ) = = 0 | | needle = = NULL | | strlen ( needle ) = = 0 ) {
return False ;
}
tmp_str = strdup ( haystack ) ;
ALLOC_CHECK ( tmp_str , done ) ;
token = tok_str = tmp_str ;
for ( token = strtok ( tok_str , delimiter ) ; token ; token = strtok ( NULL , delimiter ) ) {
if ( strcmp ( token , needle ) = = 0 ) {
ret = True ;
goto done ;
}
}
done :
SAFE_FREE ( tmp_str ) ;
return ret ;
}
/**
* 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
* */
2002-09-08 03:55:37 +00:00
static BOOL matchparam ( const char * haystack , const char * needle )
2002-09-07 04:05:42 +00:00
{
char * token ;
char * tok_str ;
char * tmp_str ;
BOOL ret = False ;
if ( haystack = = NULL | | strlen ( haystack ) = = 0 | | needle = = NULL | | strlen ( needle ) = = 0 ) {
return False ;
}
tmp_str = strdup ( haystack ) ;
ALLOC_CHECK ( tmp_str , done ) ;
token = tok_str = tmp_str ;
for ( token = strtok ( tok_str , delimiter ) ; token ; token = strtok ( NULL , delimiter ) ) {
if ( ! unix_wild_match ( token , needle ) ) {
ret = True ;
goto done ;
}
}
done :
SAFE_FREE ( tmp_str ) ;
return ret ;
}
/**
* Touch access date
* */
static void recycle_touch ( connection_struct * conn , const char * fname )
{
SMB_STRUCT_STAT st ;
struct utimbuf tb ;
time_t currtime ;
if ( default_vfs_ops . stat ( conn , fname , & st ) ! = 0 ) {
DEBUG ( 0 , ( " recycle.bin: stat for %s returned %s \n " , fname , strerror ( errno ) ) ) ;
return ;
}
currtime = time ( & currtime ) ;
tb . actime = currtime ;
tb . modtime = st . st_mtime ;
if ( default_vfs_ops . utime ( conn , fname , & tb ) = = - 1 )
DEBUG ( 0 , ( " recycle.bin: touching %s failed, reason = %s \n " , fname , strerror ( errno ) ) ) ;
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
/**
* Check if file should be recycled
* */
2003-02-24 09:10:41 +00:00
static int recycle_unlink ( connection_struct * conn , const char * file_name )
2002-03-19 02:51:48 +00:00
{
2002-12-09 12:06:15 +00:00
recycle_bin_private_data * recdata ;
recycle_bin_connections * recconn ;
2002-09-07 04:05:42 +00:00
recycle_bin_struct * recbin ;
char * path_name = NULL ;
char * temp_name = NULL ;
char * final_name = NULL ;
2003-02-24 09:10:41 +00:00
const char * base ;
2002-09-07 04:05:42 +00:00
int i ;
2002-12-09 12:06:15 +00:00
/* SMB_BIG_UINT dfree, dsize, bsize; */
SMB_OFF_T file_size ; /* space_avail; */
2002-09-07 04:05:42 +00:00
BOOL exist ;
2002-09-08 03:55:37 +00:00
int rc = - 1 ;
2002-09-07 04:05:42 +00:00
2002-12-09 12:06:15 +00:00
recbin = NULL ;
if ( recycle_bin_private_handle ) {
recdata = ( recycle_bin_private_data * ) ( recycle_bin_private_handle - > data ) ;
if ( recdata ) {
if ( recdata - > conns ) {
recconn = recdata - > conns ;
while ( recconn & & recconn - > conn ! = SNUM ( conn ) ) recconn = recconn - > next ;
if ( recconn ! = NULL ) {
recbin = recconn - > data ;
}
}
}
}
if ( recbin = = NULL ) {
2002-09-07 04:05:42 +00:00
DEBUG ( 0 , ( " Recycle bin not initialized! \n " ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
if ( ! recbin - > repository | | * ( recbin - > repository ) = = ' \0 ' ) {
DEBUG ( 3 , ( " Recycle path not set, purging %s... \n " , file_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
/* we don't recycle the recycle bin... */
if ( strncmp ( file_name , recbin - > repository , strlen ( recbin - > repository ) ) = = 0 ) {
DEBUG ( 3 , ( " File is within recycling bin, unlinking ... \n " ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00:00
file_size = recycle_get_file_size ( conn , file_name ) ;
/* it is wrong to purge filenames only because they are empty imho
* - - - simo
*
if ( fsize = = 0 ) {
DEBUG ( 3 , ( " File %s is empty, purging... \n " , file_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
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
*/
if ( recbin - > maxsize > 0 & & file_size > recbin - > maxsize ) {
DEBUG ( 3 , ( " File %s exceeds maximum recycle size, purging... \n " , file_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
/* FIXME: this is wrong: moving files with rename does not change the disk space
* allocation
*
space_avail = default_vfs_ops . disk_free ( conn , " . " , True , & bsize , & dfree , & dsize ) * 1024L ;
DEBUG ( 5 , ( " space_avail = %Lu, file_size = %Lu \n " , space_avail , file_size ) ) ;
if ( space_avail < file_size ) {
DEBUG ( 3 , ( " Not enough diskspace, purging file %s \n " , file_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
}
*/
/* extract filename and path */
path_name = ( char * ) malloc ( PATH_MAX ) ;
ALLOC_CHECK ( path_name , done ) ;
* path_name = ' \0 ' ;
2003-02-24 09:10:41 +00:00
safe_strcpy ( path_name , file_name , PATH_MAX - 1 ) ;
2002-09-07 04:05:42 +00:00
base = strrchr ( path_name , ' / ' ) ;
if ( base = = NULL ) {
base = file_name ;
2003-02-24 09:10:41 +00:00
safe_strcpy ( path_name , " / " , PATH_MAX - 1 ) ;
2002-09-07 04:05:42 +00:00
}
else {
base + + ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
DEBUG ( 10 , ( " recycle.bin: fname = %s \n " , file_name ) ) ; /* original filename with path */
DEBUG ( 10 , ( " recycle.bin: fpath = %s \n " , path_name ) ) ; /* original path */
DEBUG ( 10 , ( " recycle.bin: base = %s \n " , base ) ) ; /* filename without path */
2002-05-11 00:33:51 +00:00
2002-09-07 04:05:42 +00:00
if ( matchparam ( recbin - > exclude , base ) ) {
DEBUG ( 3 , ( " recycle.bin: file %s is excluded \n " , base ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
2002-05-11 00:33:51 +00:00
}
2002-03-19 02:51:48 +00:00
2002-09-07 04:05:42 +00: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
*/
if ( checkparam ( recbin - > exclude_dir , path_name ) ) {
DEBUG ( 3 , ( " recycle.bin: directory %s is excluded \n " , path_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
2002-03-19 02:51:48 +00:00
}
2003-02-24 09:10:41 +00:00
temp_name = ( char * ) strdup ( recbin - > repository ) ;
2002-09-07 04:05:42 +00:00
ALLOC_CHECK ( temp_name , done ) ;
2002-05-11 00:33:51 +00:00
2002-09-07 04:05:42 +00:00
/* see if we need to recreate the original directory structure in the recycle bin */
2002-09-08 03:55:37 +00:00
if ( recbin - > keep_dir_tree = = True ) {
2003-02-24 09:10:41 +00:00
safe_strcat ( temp_name , " / " , PATH_MAX - 1 ) ;
safe_strcat ( temp_name , path_name , PATH_MAX - 1 ) ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
exist = recycle_directory_exist ( conn , temp_name ) ;
if ( exist ) {
DEBUG ( 10 , ( " recycle.bin: Directory already exists \n " ) ) ;
} else {
DEBUG ( 10 , ( " recycle.bin: Creating directory %s \n " , temp_name ) ) ;
if ( recycle_create_dir ( conn , temp_name ) = = False ) {
DEBUG ( 3 , ( " Could not create directory, purging %s... \n " , file_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
}
2002-03-19 02:51:48 +00:00
2003-02-24 09:10:41 +00:00
final_name = NULL ;
asprintf ( & final_name , " %s/%s " , temp_name , base ) ;
2002-09-08 03:55:37 +00:00
ALLOC_CHECK ( final_name , done ) ;
2002-09-07 04:05:42 +00:00
DEBUG ( 10 , ( " recycle.bin: recycled file name%s \n " , temp_name ) ) ; /* new filename with path */
/* check if we should delete file from recycle bin */
2002-09-08 03:55:37 +00:00
if ( recycle_file_exist ( conn , final_name ) ) {
2002-09-07 04:05:42 +00:00
if ( recbin - > versions = = False | | matchparam ( recbin - > noversions , base ) = = True ) {
2002-09-08 03:55:37 +00:00
DEBUG ( 3 , ( " recycle.bin: Removing old file %s from recycle bin \n " , final_name ) ) ;
if ( default_vfs_ops . unlink ( conn , final_name ) ! = 0 ) {
2002-09-07 04:05:42 +00:00
DEBUG ( 1 , ( " recycle.bin: Error deleting old file: %s \n " , strerror ( errno ) ) ) ;
}
2002-03-23 20:48:45 +00:00
}
2002-03-19 02:51:48 +00:00
}
2002-09-07 04:05:42 +00:00
/* rename file we move to recycle bin */
i = 1 ;
while ( recycle_file_exist ( conn , final_name ) ) {
2002-09-08 03:55:37 +00:00
snprintf ( final_name , PATH_MAX , " %s/Copy #%d of %s " , temp_name , i + + , base ) ;
2002-09-07 04:05:42 +00:00
}
DEBUG ( 10 , ( " recycle.bin: Moving %s to %s \n " , file_name , final_name ) ) ;
rc = default_vfs_ops . rename ( conn , file_name , final_name ) ;
if ( rc ! = 0 ) {
DEBUG ( 3 , ( " recycle.bin: Move error %d (%s), purging file %s (%s) \n " , errno , strerror ( errno ) , file_name , final_name ) ) ;
rc = default_vfs_ops . unlink ( conn , file_name ) ;
goto done ;
}
/* touch access date of moved file */
if ( recbin - > touch = = True )
recycle_touch ( conn , final_name ) ;
done :
SAFE_FREE ( path_name ) ;
SAFE_FREE ( temp_name ) ;
SAFE_FREE ( final_name ) ;
return rc ;
2002-03-19 02:51:48 +00:00
}