2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
useful function for deleting a whole directory tree
Copyright ( C ) Andrew Tridgell 2003
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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2006-01-03 18:40:05 +03:00
# include "libcli/raw/libcliraw.h"
# include "libcli/libcli.h"
2006-04-24 04:16:51 +04:00
# include "system/dir.h"
2003-08-13 05:53:07 +04:00
struct delete_state {
2004-08-04 17:23:35 +04:00
struct smbcli_tree * tree ;
2003-08-13 05:53:07 +04:00
int total_deleted ;
2007-10-07 02:28:14 +04:00
bool failed ;
2003-08-13 05:53:07 +04:00
} ;
/*
callback function for torture_deltree ( )
*/
2004-11-30 08:37:57 +03:00
static void delete_fn ( struct clilist_file_info * finfo , const char * name , void * state )
2003-08-13 05:53:07 +04:00
{
2007-09-07 17:31:15 +04:00
struct delete_state * dstate = ( struct delete_state * ) state ;
2003-08-13 05:53:07 +04:00
char * s , * n ;
2006-04-24 04:16:51 +04:00
if ( ISDOT ( finfo - > name ) | | ISDOTDOT ( finfo - > name ) ) {
return ;
}
2003-08-13 05:53:07 +04:00
n = strdup ( name ) ;
n [ strlen ( n ) - 1 ] = 0 ;
asprintf ( & s , " %s%s " , n , finfo - > name ) ;
2004-11-30 08:37:57 +03:00
if ( finfo - > attrib & FILE_ATTRIBUTE_READONLY ) {
2004-08-04 17:23:35 +04:00
if ( NT_STATUS_IS_ERR ( smbcli_setatr ( dstate - > tree , s , 0 , 0 ) ) ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 2 , ( " Failed to remove READONLY on %s - %s \n " ,
2004-08-04 17:23:35 +04:00
s , smbcli_errstr ( dstate - > tree ) ) ) ;
2003-08-13 05:53:07 +04:00
}
}
2004-11-30 08:37:57 +03:00
if ( finfo - > attrib & FILE_ATTRIBUTE_DIRECTORY ) {
2003-08-13 05:53:07 +04:00
char * s2 ;
asprintf ( & s2 , " %s \\ * " , s ) ;
2004-08-04 17:23:35 +04:00
smbcli_unlink ( dstate - > tree , s2 ) ;
smbcli_list ( dstate - > tree , s2 ,
2003-08-13 05:53:07 +04:00
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM ,
delete_fn , state ) ;
free ( s2 ) ;
2004-08-04 17:23:35 +04:00
if ( NT_STATUS_IS_ERR ( smbcli_rmdir ( dstate - > tree , s ) ) ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 2 , ( " Failed to delete %s - %s \n " ,
2004-08-04 17:23:35 +04:00
s , smbcli_errstr ( dstate - > tree ) ) ) ;
2007-10-07 02:28:14 +04:00
dstate - > failed = true ;
2003-08-13 05:53:07 +04:00
}
dstate - > total_deleted + + ;
} else {
2004-08-04 17:23:35 +04:00
if ( NT_STATUS_IS_ERR ( smbcli_unlink ( dstate - > tree , s ) ) ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 2 , ( " Failed to delete %s - %s \n " ,
2004-08-04 17:23:35 +04:00
s , smbcli_errstr ( dstate - > tree ) ) ) ;
2007-10-07 02:28:14 +04:00
dstate - > failed = true ;
2003-08-13 05:53:07 +04:00
}
dstate - > total_deleted + + ;
}
free ( s ) ;
free ( n ) ;
}
/*
recursively descend a tree deleting all files
returns the number of files deleted , or - 1 on error
*/
2004-08-04 17:23:35 +04:00
int smbcli_deltree ( struct smbcli_tree * tree , const char * dname )
2003-08-13 05:53:07 +04:00
{
char * mask ;
struct delete_state dstate ;
2008-09-23 09:16:46 +04:00
NTSTATUS status ;
2003-08-13 05:53:07 +04:00
2004-02-08 03:51:07 +03:00
dstate . tree = tree ;
2003-08-13 05:53:07 +04:00
dstate . total_deleted = 0 ;
2007-10-07 02:28:14 +04:00
dstate . failed = false ;
2003-08-13 05:53:07 +04:00
/* it might be a file */
2008-09-25 02:40:55 +04:00
status = smbcli_unlink ( tree , dname ) ;
2004-08-04 17:23:35 +04:00
if ( NT_STATUS_IS_OK ( smbcli_unlink ( tree , dname ) ) ) {
2003-08-13 05:53:07 +04:00
return 1 ;
}
2004-08-04 17:23:35 +04:00
if ( NT_STATUS_EQUAL ( smbcli_nt_error ( tree ) , NT_STATUS_OBJECT_NAME_NOT_FOUND ) | |
NT_STATUS_EQUAL ( smbcli_nt_error ( tree ) , NT_STATUS_OBJECT_PATH_NOT_FOUND ) | |
2008-12-02 01:42:07 +03:00
NT_STATUS_EQUAL ( smbcli_nt_error ( tree ) , NT_STATUS_NO_SUCH_FILE ) | |
NT_STATUS_EQUAL ( smbcli_nt_error ( tree ) , NT_STATUS_DOS ( ERRDOS , ERRbadfile ) ) ) {
2003-08-13 05:53:07 +04:00
return 0 ;
}
2008-09-23 09:16:46 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_CANNOT_DELETE ) ) {
/* it could be read-only */
status = smbcli_setatr ( tree , dname , FILE_ATTRIBUTE_NORMAL , 0 ) ;
if ( NT_STATUS_IS_OK ( smbcli_unlink ( tree , dname ) ) ) {
return 1 ;
}
}
2003-08-13 05:53:07 +04:00
asprintf ( & mask , " %s \\ * " , dname ) ;
2004-08-04 17:23:35 +04:00
smbcli_unlink ( dstate . tree , mask ) ;
smbcli_list ( dstate . tree , mask ,
2003-08-13 05:53:07 +04:00
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM ,
delete_fn , & dstate ) ;
free ( mask ) ;
2008-09-23 09:16:46 +04:00
status = smbcli_rmdir ( dstate . tree , dname ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_CANNOT_DELETE ) ) {
/* it could be read-only */
status = smbcli_setatr ( dstate . tree , dname , FILE_ATTRIBUTE_NORMAL , 0 ) ;
status = smbcli_rmdir ( dstate . tree , dname ) ;
}
if ( NT_STATUS_IS_ERR ( status ) ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 2 , ( " Failed to delete %s - %s \n " ,
2004-08-04 17:23:35 +04:00
dname , smbcli_errstr ( dstate . tree ) ) ) ;
2003-08-13 05:53:07 +04:00
return - 1 ;
}
dstate . total_deleted + + ;
if ( dstate . failed ) {
return - 1 ;
}
return dstate . total_deleted ;
}