2004-09-18 12:16:14 +04:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - unlink
Copyright ( C ) Andrew Tridgell 2004
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
2004-09-18 12:16:14 +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/>.
2004-09-18 12:16:14 +04:00
*/
2004-11-05 10:24:25 +03:00
# include "includes.h"
2004-09-18 12:16:14 +04:00
# include "vfs_posix.h"
2006-04-24 04:16:51 +04:00
# include "system/dir.h"
2004-09-18 12:16:14 +04:00
2008-02-22 13:52:17 +03:00
/*
retry an open after a sharing violation
*/
static void pvfs_retry_unlink ( struct pvfs_odb_retry * r ,
struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req ,
void * _io ,
void * private_data ,
enum pvfs_wait_notice reason )
{
union smb_unlink * io = talloc_get_type ( _io , union smb_unlink ) ;
NTSTATUS status = NT_STATUS_INTERNAL_ERROR ;
talloc_free ( r ) ;
switch ( reason ) {
case PVFS_WAIT_CANCEL :
/*TODO*/
status = NT_STATUS_CANCELLED ;
break ;
case PVFS_WAIT_TIMEOUT :
/* if it timed out, then give the failure
immediately */
/*TODO*/
status = NT_STATUS_SHARING_VIOLATION ;
break ;
case PVFS_WAIT_EVENT :
/* try the open again, which could trigger another retry setup
if it wants to , so we have to unmark the async flag so we
will know if it does a second async reply */
req - > async_states - > state & = ~ NTVFS_ASYNC_STATE_ASYNC ;
status = pvfs_unlink ( ntvfs , req , io ) ;
if ( req - > async_states - > state & NTVFS_ASYNC_STATE_ASYNC ) {
/* the 2nd try also replied async, so we don't send
the reply yet */
return ;
}
/* re-mark it async, just in case someone up the chain does
paranoid checking */
req - > async_states - > state | = NTVFS_ASYNC_STATE_ASYNC ;
break ;
}
/* send the reply up the chain */
req - > async_states - > status = status ;
req - > async_states - > send_fn ( req ) ;
}
/*
setup for a unlink retry after a sharing violation
or a non granted oplock
*/
static NTSTATUS pvfs_unlink_setup_retry ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req ,
union smb_unlink * io ,
struct odb_lock * lck ,
NTSTATUS status )
{
struct pvfs_state * pvfs = ntvfs - > private_data ;
struct timeval end_time ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_SHARING_VIOLATION ) ) {
end_time = timeval_add ( & req - > statistics . request_time ,
0 , pvfs - > sharing_violation_delay ) ;
} else if ( NT_STATUS_EQUAL ( status , NT_STATUS_OPLOCK_NOT_GRANTED ) ) {
end_time = timeval_add ( & req - > statistics . request_time ,
pvfs - > oplock_break_timeout , 0 ) ;
} else {
return NT_STATUS_INTERNAL_ERROR ;
}
return pvfs_odb_retry_setup ( ntvfs , req , lck , end_time , io , NULL ,
pvfs_retry_unlink ) ;
}
2004-09-18 12:16:14 +04:00
/*
2008-02-22 11:37:22 +03:00
unlink a file
2004-09-18 12:16:14 +04:00
*/
2008-02-22 11:37:22 +03:00
static NTSTATUS pvfs_unlink_file ( struct pvfs_state * pvfs ,
struct pvfs_filename * name )
2004-09-18 12:16:14 +04:00
{
NTSTATUS status ;
2004-10-26 09:39:54 +04:00
if ( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) {
return NT_STATUS_FILE_IS_A_DIRECTORY ;
}
2004-12-30 06:19:27 +03:00
if ( name - > st . st_nlink = = 1 ) {
status = pvfs_xattr_unlink_hook ( pvfs , name - > full_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-12-17 06:39:29 +03:00
}
2004-09-18 12:16:14 +04:00
/* finally try the actual unlink */
if ( unlink ( name - > full_name ) = = - 1 ) {
status = pvfs_map_errno ( pvfs , errno ) ;
}
2006-03-21 14:47:24 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
2006-03-30 07:51:49 +04:00
notify_trigger ( pvfs - > notify_context ,
NOTIFY_ACTION_REMOVED ,
FILE_NOTIFY_CHANGE_FILE_NAME ,
2006-03-21 14:47:24 +03:00
name - > full_name ) ;
}
2004-09-18 12:16:14 +04:00
return status ;
}
2008-02-22 11:37:22 +03:00
/*
unlink one file
*/
static NTSTATUS pvfs_unlink_one ( struct pvfs_state * pvfs ,
struct ntvfs_request * req ,
union smb_unlink * unl ,
struct pvfs_filename * name )
{
NTSTATUS status ;
2008-02-22 13:52:17 +03:00
struct odb_lock * lck = NULL ;
2008-02-22 11:37:22 +03:00
/* make sure its matches the given attributes */
status = pvfs_match_attrib ( pvfs , name ,
unl - > unlink . in . attrib , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2008-02-22 13:52:17 +03:00
status = pvfs_can_delete ( pvfs , req , name , & lck ) ;
/*
* on a sharing violation we need to retry when the file is closed by
* the other user , or after 1 second
* on a non granted oplock we need to retry when the file is closed by
* the other user , or after 30 seconds
*/
if ( ( NT_STATUS_EQUAL ( status , NT_STATUS_SHARING_VIOLATION ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_OPLOCK_NOT_GRANTED ) ) & &
( req - > async_states - > state & NTVFS_ASYNC_STATE_MAY_ASYNC ) ) {
return pvfs_unlink_setup_retry ( pvfs - > ntvfs , req , unl , lck , status ) ;
}
2008-02-22 11:37:22 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2008-02-22 11:41:41 +03:00
if ( name - > stream_name ) {
if ( ! name - > stream_exists ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
return pvfs_stream_delete ( pvfs , name , - 1 ) ;
}
2008-02-22 11:37:22 +03:00
return pvfs_unlink_file ( pvfs , name ) ;
}
2004-09-18 12:16:14 +04:00
/*
delete a file - the dirtype specifies the file types to include in the search .
The name can contain CIFS wildcards , but rarely does ( except with OS / 2 clients )
*/
2004-09-29 17:17:09 +04:00
NTSTATUS pvfs_unlink ( struct ntvfs_module_context * ntvfs ,
2006-03-10 23:49:20 +03:00
struct ntvfs_request * req ,
union smb_unlink * unl )
2004-09-18 12:16:14 +04:00
{
2004-09-29 17:17:09 +04:00
struct pvfs_state * pvfs = ntvfs - > private_data ;
2004-09-20 11:28:43 +04:00
struct pvfs_dir * dir ;
2004-09-18 12:16:14 +04:00
NTSTATUS status ;
2004-10-26 17:18:34 +04:00
uint32_t total_deleted = 0 ;
2004-09-18 12:16:14 +04:00
struct pvfs_filename * name ;
2004-10-26 15:11:16 +04:00
const char * fname ;
2006-09-10 11:24:41 +04:00
off_t ofs ;
2004-09-18 12:16:14 +04:00
/* resolve the cifs name to a posix name */
2006-03-10 23:49:20 +03:00
status = pvfs_resolve_name ( pvfs , req , unl - > unlink . in . pattern ,
2008-05-05 14:18:47 +04:00
PVFS_RESOLVE_WILDCARD |
PVFS_RESOLVE_STREAMS |
PVFS_RESOLVE_NO_OPENDB ,
& name ) ;
2004-09-18 12:16:14 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! name - > exists & & ! name - > has_wildcard ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2004-10-26 09:39:54 +04:00
if ( name - > exists & &
( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ) {
return NT_STATUS_FILE_IS_A_DIRECTORY ;
}
2008-02-22 11:30:51 +03:00
if ( ! name - > has_wildcard ) {
return pvfs_unlink_one ( pvfs , req , unl , name ) ;
}
2008-03-15 14:22:36 +03:00
/*
* disable async requests in the wildcard case
* untill we have proper tests for this
*/
req - > async_states - > state & = ~ NTVFS_ASYNC_STATE_MAY_ASYNC ;
2004-09-18 12:16:14 +04:00
/* get list of matching files */
2004-10-26 17:18:34 +04:00
status = pvfs_list_start ( pvfs , name , req , & dir ) ;
2004-09-18 12:16:14 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-10-26 15:11:16 +04:00
status = NT_STATUS_NO_SUCH_FILE ;
2008-02-21 22:12:46 +03:00
talloc_free ( name ) ;
2004-10-26 09:39:54 +04:00
2004-10-26 17:18:34 +04:00
ofs = 0 ;
while ( ( fname = pvfs_list_next ( dir , & ofs ) ) ) {
2004-10-26 09:39:54 +04:00
/* this seems to be a special case */
2006-03-10 23:49:20 +03:00
if ( ( unl - > unlink . in . attrib & FILE_ATTRIBUTE_DIRECTORY ) & &
2006-04-24 04:16:51 +04:00
( ISDOT ( fname ) | | ISDOTDOT ( fname ) ) ) {
2004-10-26 09:39:54 +04:00
return NT_STATUS_OBJECT_NAME_INVALID ;
}
2008-02-21 22:12:46 +03:00
/* get a pvfs_filename object */
status = pvfs_resolve_partial ( pvfs , req ,
pvfs_list_unix_path ( dir ) ,
2008-05-05 14:18:47 +04:00
fname ,
PVFS_RESOLVE_NO_OPENDB ,
& name ) ;
2008-02-21 22:12:46 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2008-02-22 11:23:53 +03:00
status = pvfs_unlink_one ( pvfs , req , unl , name ) ;
2004-09-18 12:16:14 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
total_deleted + + ;
}
2008-02-21 22:12:46 +03:00
talloc_free ( name ) ;
2004-09-18 12:16:14 +04:00
}
2004-10-26 15:11:16 +04:00
if ( total_deleted > 0 ) {
status = NT_STATUS_OK ;
2004-09-18 12:16:14 +04:00
}
2004-10-26 15:11:16 +04:00
return status ;
2004-09-18 12:16:14 +04:00
}