2004-09-22 17:01:55 +04:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - rename
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-22 17:01:55 +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-22 17:01:55 +04:00
*/
2004-11-05 10:24:25 +03:00
# include "includes.h"
2004-09-22 17:01:55 +04:00
# include "vfs_posix.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/security.h"
2007-12-14 00:46:09 +03:00
# include "param/param.h"
2004-11-13 08:47:27 +03:00
2006-04-05 12:52:03 +04:00
/*
do a file rename , and send any notify triggers
*/
2008-03-01 12:05:25 +03:00
NTSTATUS pvfs_do_rename ( struct pvfs_state * pvfs ,
struct odb_lock * lck ,
const struct pvfs_filename * name1 ,
2006-04-06 05:56:04 +04:00
const char * name2 )
2006-04-05 12:52:03 +04:00
{
const char * r1 , * r2 ;
2006-04-06 05:56:04 +04:00
uint32_t mask ;
2008-03-01 12:05:25 +03:00
NTSTATUS status ;
2006-04-05 12:52:03 +04:00
2011-12-01 06:40:49 +04:00
if ( pvfs_sys_rename ( pvfs , name1 - > full_name , name2 ,
name1 - > allow_override ) = = - 1 ) {
2006-04-05 12:52:03 +04:00
return pvfs_map_errno ( pvfs , errno ) ;
}
2008-03-01 12:05:25 +03:00
status = odb_rename ( lck , name2 ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-04-06 05:56:04 +04:00
if ( name1 - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) {
mask = FILE_NOTIFY_CHANGE_DIR_NAME ;
} else {
2006-04-06 14:05:19 +04:00
mask = FILE_NOTIFY_CHANGE_FILE_NAME ;
2006-04-06 05:56:04 +04:00
}
2006-04-05 12:52:03 +04:00
/*
renames to the same directory cause a OLD_NAME - > NEW_NAME notify .
renames to a different directory are considered a remove / add
*/
2006-04-06 05:56:04 +04:00
r1 = strrchr_m ( name1 - > full_name , ' / ' ) ;
2006-04-05 12:52:03 +04:00
r2 = strrchr_m ( name2 , ' / ' ) ;
2006-04-06 05:56:04 +04:00
if ( ( r1 - name1 - > full_name ) ! = ( r2 - name2 ) | |
strncmp ( name1 - > full_name , name2 , r1 - name1 - > full_name ) ! = 0 ) {
2006-04-05 12:52:03 +04:00
notify_trigger ( pvfs - > notify_context ,
NOTIFY_ACTION_REMOVED ,
2006-04-06 05:56:04 +04:00
mask ,
name1 - > full_name ) ;
2006-04-05 12:52:03 +04:00
notify_trigger ( pvfs - > notify_context ,
NOTIFY_ACTION_ADDED ,
2006-04-06 05:56:04 +04:00
mask ,
2006-04-05 12:52:03 +04:00
name2 ) ;
} else {
notify_trigger ( pvfs - > notify_context ,
NOTIFY_ACTION_OLD_NAME ,
2006-04-06 05:56:04 +04:00
mask ,
name1 - > full_name ) ;
2006-04-05 12:52:03 +04:00
notify_trigger ( pvfs - > notify_context ,
NOTIFY_ACTION_NEW_NAME ,
2006-04-06 05:56:04 +04:00
mask ,
2006-04-05 12:52:03 +04:00
name2 ) ;
}
2006-04-06 14:05:19 +04:00
/* this is a strange one. w2k3 gives an additional event for CHANGE_ATTRIBUTES
2007-01-28 21:25:46 +03:00
and CHANGE_CREATION on the new file when renaming files , but not
2006-04-06 14:05:19 +04:00
directories */
if ( ( name1 - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) = = 0 ) {
notify_trigger ( pvfs - > notify_context ,
NOTIFY_ACTION_MODIFIED ,
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION ,
name2 ) ;
}
2006-04-05 12:52:03 +04:00
return NT_STATUS_OK ;
}
2004-11-13 08:47:27 +03:00
/*
resolve a wildcard rename pattern . This works on one component of the name
*/
static const char * pvfs_resolve_wildcard_component ( TALLOC_CTX * mem_ctx ,
const char * fname ,
const char * pattern )
{
const char * p1 , * p2 ;
char * dest , * d ;
/* the length is bounded by the length of the two strings combined */
2009-02-04 10:50:46 +03:00
dest = talloc_array ( mem_ctx , char , strlen ( fname ) + strlen ( pattern ) + 1 ) ;
2004-11-13 08:47:27 +03:00
if ( dest = = NULL ) {
return NULL ;
}
p1 = fname ;
p2 = pattern ;
d = dest ;
while ( * p2 ) {
codepoint_t c1 , c2 ;
size_t c_size1 , c_size2 ;
2010-05-09 19:20:01 +04:00
c1 = next_codepoint ( p1 , & c_size1 ) ;
c2 = next_codepoint ( p2 , & c_size2 ) ;
2004-11-13 08:47:27 +03:00
if ( c2 = = ' ? ' ) {
2010-05-09 19:20:01 +04:00
d + = push_codepoint ( d , c1 ) ;
2004-11-13 08:47:27 +03:00
} else if ( c2 = = ' * ' ) {
memcpy ( d , p1 , strlen ( p1 ) ) ;
d + = strlen ( p1 ) ;
break ;
} else {
2010-05-09 19:20:01 +04:00
d + = push_codepoint ( d , c2 ) ;
2004-11-13 08:47:27 +03:00
}
p1 + = c_size1 ;
p2 + = c_size2 ;
}
* d = 0 ;
2009-02-04 10:50:46 +03:00
talloc_set_name_const ( dest , dest ) ;
2004-11-13 08:47:27 +03:00
return dest ;
}
/*
resolve a wildcard rename pattern .
*/
static const char * pvfs_resolve_wildcard ( TALLOC_CTX * mem_ctx ,
const char * fname ,
const char * pattern )
{
const char * base1 , * base2 ;
const char * ext1 , * ext2 ;
char * p ;
/* break into base part plus extension */
p = strrchr_m ( fname , ' . ' ) ;
if ( p = = NULL ) {
ext1 = " " ;
base1 = fname ;
} else {
ext1 = talloc_strdup ( mem_ctx , p + 1 ) ;
base1 = talloc_strndup ( mem_ctx , fname , p - fname ) ;
}
if ( ext1 = = NULL | | base1 = = NULL ) {
return NULL ;
}
p = strrchr_m ( pattern , ' . ' ) ;
if ( p = = NULL ) {
ext2 = " " ;
base2 = fname ;
} else {
ext2 = talloc_strdup ( mem_ctx , p + 1 ) ;
base2 = talloc_strndup ( mem_ctx , pattern , p - pattern ) ;
}
if ( ext2 = = NULL | | base2 = = NULL ) {
return NULL ;
}
2010-05-09 19:20:01 +04:00
base1 = pvfs_resolve_wildcard_component ( mem_ctx , base1 , base2 ) ;
ext1 = pvfs_resolve_wildcard_component ( mem_ctx , ext1 , ext2 ) ;
2004-11-13 08:47:27 +03:00
if ( base1 = = NULL | | ext1 = = NULL ) {
return NULL ;
}
if ( * ext1 = = 0 ) {
return base1 ;
}
return talloc_asprintf ( mem_ctx , " %s.%s " , base1 , ext1 ) ;
}
2008-02-27 13:24:37 +03:00
/*
retry an rename after a sharing violation
*/
static void pvfs_retry_rename ( 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_rename * io = talloc_get_type ( _io , union smb_rename ) ;
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_rename ( 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 rename retry after a sharing violation
or a non granted oplock
*/
static NTSTATUS pvfs_rename_setup_retry ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req ,
union smb_rename * io ,
struct odb_lock * lck ,
NTSTATUS status )
{
2009-02-04 10:52:41 +03:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2008-02-27 13:24:37 +03:00
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_rename ) ;
}
2004-11-13 08:47:27 +03:00
/*
rename one file from a wildcard set
*/
static NTSTATUS pvfs_rename_one ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-11-13 08:47:27 +03:00
const char * dir_path ,
const char * fname1 ,
const char * fname2 ,
uint16_t attrib )
{
struct pvfs_filename * name1 , * name2 ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( req ) ;
2008-02-21 21:59:13 +03:00
struct odb_lock * lck = NULL ;
2004-11-13 08:47:27 +03:00
NTSTATUS status ;
/* resolve the wildcard pattern for this name */
2010-05-09 19:20:01 +04:00
fname2 = pvfs_resolve_wildcard ( mem_ctx , fname1 , fname2 ) ;
2004-11-13 08:47:27 +03:00
if ( fname2 = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/* get a pvfs_filename source object */
status = pvfs_resolve_partial ( pvfs , mem_ctx ,
2008-05-05 14:18:47 +04:00
dir_path , fname1 ,
PVFS_RESOLVE_NO_OPENDB ,
& name1 ) ;
2004-11-13 08:47:27 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-12-30 09:37:37 +03:00
goto failed ;
2004-11-13 08:47:27 +03:00
}
/* make sure its matches the given attributes */
status = pvfs_match_attrib ( pvfs , name1 , attrib , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-12-30 09:37:37 +03:00
goto failed ;
2004-11-13 08:47:27 +03:00
}
2006-02-28 06:47:02 +03:00
status = pvfs_can_rename ( pvfs , req , name1 , & lck ) ;
2004-11-13 08:47:27 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-21 21:59:13 +03:00
talloc_free ( lck ) ;
2004-12-30 09:37:37 +03:00
goto failed ;
2004-11-13 08:47:27 +03:00
}
/* get a pvfs_filename dest object */
status = pvfs_resolve_partial ( pvfs , mem_ctx ,
2008-05-05 14:18:47 +04:00
dir_path , fname2 ,
PVFS_RESOLVE_NO_OPENDB ,
& name2 ) ;
2004-11-13 08:47:27 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
2008-02-21 21:59:13 +03:00
status = pvfs_can_delete ( pvfs , req , name2 , NULL ) ;
2004-11-13 08:47:27 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-12-30 09:37:37 +03:00
goto failed ;
2004-11-13 08:47:27 +03:00
}
}
2004-12-30 09:37:37 +03:00
status = NT_STATUS_OK ;
2004-12-30 08:50:23 +03:00
2004-11-13 08:47:27 +03:00
fname2 = talloc_asprintf ( mem_ctx , " %s/%s " , dir_path , fname2 ) ;
if ( fname2 = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2008-03-01 12:05:25 +03:00
status = pvfs_do_rename ( pvfs , lck , name1 , fname2 ) ;
2006-03-30 13:24:31 +04:00
2004-12-30 09:37:37 +03:00
failed :
2004-11-13 08:47:27 +03:00
talloc_free ( mem_ctx ) ;
2004-12-30 09:37:37 +03:00
return status ;
2004-11-13 08:47:27 +03:00
}
/*
rename a set of files with wildcards
*/
static NTSTATUS pvfs_rename_wildcard ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-11-13 08:47:27 +03:00
union smb_rename * ren ,
struct pvfs_filename * name1 ,
struct pvfs_filename * name2 )
{
struct pvfs_dir * dir ;
NTSTATUS status ;
2006-09-10 11:24:41 +04:00
off_t ofs = 0 ;
2004-11-13 08:47:27 +03:00
const char * fname , * fname2 , * dir_path ;
uint16_t attrib = ren - > rename . in . attrib ;
int total_renamed = 0 ;
/* get list of matching files */
status = pvfs_list_start ( pvfs , name1 , req , & dir ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = NT_STATUS_NO_SUCH_FILE ;
dir_path = pvfs_list_unix_path ( dir ) ;
/* only allow wildcard renames within a directory */
if ( strncmp ( dir_path , name2 - > full_name , strlen ( dir_path ) ) ! = 0 | |
name2 - > full_name [ strlen ( dir_path ) ] ! = ' / ' | |
strchr ( name2 - > full_name + strlen ( dir_path ) + 1 , ' / ' ) ) {
2010-03-05 06:59:08 +03:00
DEBUG ( 3 , ( __location__ " : Invalid rename for %s -> %s \n " ,
name1 - > original_name , name2 - > original_name ) ) ;
2004-11-13 08:47:27 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
fname2 = talloc_strdup ( name2 , name2 - > full_name + strlen ( dir_path ) + 1 ) ;
if ( fname2 = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
while ( ( fname = pvfs_list_next ( dir , & ofs ) ) ) {
status = pvfs_rename_one ( pvfs , req ,
dir_path ,
fname , fname2 , attrib ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
total_renamed + + ;
}
}
if ( total_renamed = = 0 ) {
return status ;
}
return NT_STATUS_OK ;
}
2004-09-22 17:01:55 +04:00
/*
2004-11-13 09:46:51 +03:00
rename a set of files - SMBmv interface
2004-09-22 17:01:55 +04:00
*/
2004-11-13 09:46:51 +03:00
static NTSTATUS pvfs_rename_mv ( struct ntvfs_module_context * ntvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req , union smb_rename * ren )
2004-09-22 17:01:55 +04:00
{
2009-02-04 10:52:41 +03:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2004-09-22 17:01:55 +04:00
NTSTATUS status ;
struct pvfs_filename * name1 , * name2 ;
2008-02-21 21:59:13 +03:00
struct odb_lock * lck = NULL ;
2004-09-22 17:01:55 +04:00
/* resolve the cifs name to a posix name */
2004-11-15 09:57:26 +03:00
status = pvfs_resolve_name ( pvfs , req , ren - > rename . in . pattern1 ,
PVFS_RESOLVE_WILDCARD , & name1 ) ;
2004-09-22 17:01:55 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-11-15 09:57:26 +03:00
status = pvfs_resolve_name ( pvfs , req , ren - > rename . in . pattern2 ,
PVFS_RESOLVE_WILDCARD , & name2 ) ;
2004-09-22 17:01:55 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( name1 - > has_wildcard | | name2 - > has_wildcard ) {
2004-11-13 08:47:27 +03:00
return pvfs_rename_wildcard ( pvfs , req , ren , name1 , name2 ) ;
2004-09-22 17:01:55 +04:00
}
if ( ! name1 - > exists ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2004-11-13 08:47:27 +03:00
if ( strcmp ( name1 - > full_name , name2 - > full_name ) = = 0 ) {
return NT_STATUS_OK ;
}
2004-09-22 17:01:55 +04:00
if ( name2 - > exists ) {
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
2004-11-13 09:46:51 +03:00
status = pvfs_match_attrib ( pvfs , name1 , ren - > rename . in . attrib , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2005-01-09 11:27:35 +03:00
status = pvfs_access_check_parent ( pvfs , req , name2 , SEC_DIR_ADD_FILE ) ;
2004-12-30 08:50:23 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2006-02-28 06:47:02 +03:00
status = pvfs_can_rename ( pvfs , req , name1 , & lck ) ;
2008-02-27 13:24:37 +03:00
/*
* 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_rename_setup_retry ( pvfs - > ntvfs , req , ren , lck , status ) ;
}
2004-10-25 09:27:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2008-03-01 12:05:25 +03:00
status = pvfs_do_rename ( pvfs , lck , name1 , name2 - > full_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-09-22 17:01:55 +04:00
}
return NT_STATUS_OK ;
}
2004-11-13 09:46:51 +03:00
2009-01-07 08:46:34 +03:00
/*
rename a stream
*/
static NTSTATUS pvfs_rename_stream ( struct ntvfs_module_context * ntvfs ,
struct ntvfs_request * req , union smb_rename * ren ,
struct pvfs_filename * name1 )
{
2009-02-04 10:52:41 +03:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2009-01-07 08:46:34 +03:00
NTSTATUS status ;
struct odb_lock * lck = NULL ;
if ( name1 - > has_wildcard ) {
2010-03-05 06:59:08 +03:00
DEBUG ( 3 , ( __location__ " : Invalid wildcard rename for %s \n " ,
name1 - > original_name ) ) ;
2009-01-07 08:46:34 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ren - > ntrename . in . new_name [ 0 ] ! = ' : ' ) {
2010-03-05 06:59:08 +03:00
DEBUG ( 3 , ( __location__ " : Invalid rename for %s \n " ,
ren - > ntrename . in . new_name ) ) ;
2009-01-07 08:46:34 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ! name1 - > exists ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
if ( ren - > ntrename . in . flags ! = RENAME_FLAG_RENAME ) {
2010-03-05 06:59:08 +03:00
DEBUG ( 3 , ( __location__ " : Invalid rename flags 0x%x for %s \n " ,
ren - > ntrename . in . flags , ren - > ntrename . in . new_name ) ) ;
2009-01-07 08:46:34 +03:00
return NT_STATUS_INVALID_PARAMETER ;
}
status = pvfs_can_rename ( pvfs , req , name1 , & 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_rename_setup_retry ( pvfs - > ntvfs , req , ren , lck , status ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = pvfs_access_check_simple ( pvfs , req , name1 , SEC_FILE_WRITE_ATTRIBUTE ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
status = pvfs_stream_rename ( pvfs , name1 , - 1 ,
2009-10-18 07:19:27 +04:00
ren - > ntrename . in . new_name + 1 ,
true ) ;
2009-01-07 08:46:34 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
return NT_STATUS_OK ;
}
2004-11-13 09:46:51 +03:00
/*
rename a set of files - ntrename interface
*/
static NTSTATUS pvfs_rename_nt ( struct ntvfs_module_context * ntvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req , union smb_rename * ren )
2004-11-13 09:46:51 +03:00
{
2009-02-04 10:52:41 +03:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2004-11-13 09:46:51 +03:00
NTSTATUS status ;
struct pvfs_filename * name1 , * name2 ;
2008-02-27 13:24:37 +03:00
struct odb_lock * lck = NULL ;
2004-11-13 09:46:51 +03:00
switch ( ren - > ntrename . in . flags ) {
case RENAME_FLAG_RENAME :
case RENAME_FLAG_HARD_LINK :
case RENAME_FLAG_COPY :
case RENAME_FLAG_MOVE_CLUSTER_INFORMATION :
break ;
default :
return NT_STATUS_ACCESS_DENIED ;
}
/* resolve the cifs name to a posix name */
2004-11-17 08:58:04 +03:00
status = pvfs_resolve_name ( pvfs , req , ren - > ntrename . in . old_name ,
2009-01-07 08:46:34 +03:00
PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS , & name1 ) ;
2004-11-13 09:46:51 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2009-01-07 08:46:34 +03:00
if ( name1 - > stream_name ) {
/* stream renames need to be handled separately */
return pvfs_rename_stream ( ntvfs , req , ren , name1 ) ;
}
2004-11-17 08:58:04 +03:00
status = pvfs_resolve_name ( pvfs , req , ren - > ntrename . in . new_name ,
PVFS_RESOLVE_WILDCARD , & name2 ) ;
2004-11-13 09:46:51 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-11-17 08:58:04 +03:00
if ( name1 - > has_wildcard | | name2 - > has_wildcard ) {
return NT_STATUS_OBJECT_PATH_SYNTAX_BAD ;
}
2004-11-13 09:46:51 +03:00
if ( ! name1 - > exists ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
if ( strcmp ( name1 - > full_name , name2 - > full_name ) = = 0 ) {
return NT_STATUS_OK ;
}
if ( name2 - > exists ) {
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
status = pvfs_match_attrib ( pvfs , name1 , ren - > ntrename . in . attrib , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2008-02-27 13:24:37 +03:00
status = pvfs_can_rename ( pvfs , req , name1 , & 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_rename_setup_retry ( pvfs - > ntvfs , req , ren , lck , status ) ;
}
2004-11-13 09:46:51 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
switch ( ren - > ntrename . in . flags ) {
case RENAME_FLAG_RENAME :
2005-01-09 11:27:35 +03:00
status = pvfs_access_check_parent ( pvfs , req , name2 , SEC_DIR_ADD_FILE ) ;
2006-04-05 12:52:03 +04:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2008-03-01 12:05:25 +03:00
status = pvfs_do_rename ( pvfs , lck , name1 , name2 - > full_name ) ;
2006-04-05 12:52:03 +04:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-11-13 09:46:51 +03:00
break ;
case RENAME_FLAG_HARD_LINK :
2005-01-09 11:27:35 +03:00
status = pvfs_access_check_parent ( pvfs , req , name2 , SEC_DIR_ADD_FILE ) ;
2006-04-05 12:52:03 +04:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-11-13 09:46:51 +03:00
if ( link ( name1 - > full_name , name2 - > full_name ) = = - 1 ) {
return pvfs_map_errno ( pvfs , errno ) ;
}
break ;
case RENAME_FLAG_COPY :
2005-01-09 11:27:35 +03:00
status = pvfs_access_check_parent ( pvfs , req , name2 , SEC_DIR_ADD_FILE ) ;
2006-04-05 12:52:03 +04:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2011-12-01 06:40:49 +04:00
return pvfs_copy_file ( pvfs , name1 , name2 , name1 - > allow_override & & name2 - > allow_override ) ;
2004-11-13 09:46:51 +03:00
case RENAME_FLAG_MOVE_CLUSTER_INFORMATION :
2010-03-05 06:59:08 +03:00
DEBUG ( 3 , ( __location__ " : Invalid rename cluster for %s \n " ,
name1 - > original_name ) ) ;
2004-11-13 09:46:51 +03:00
return NT_STATUS_INVALID_PARAMETER ;
default :
return NT_STATUS_ACCESS_DENIED ;
}
return NT_STATUS_OK ;
}
/*
rename a set of files - ntrename interface
*/
NTSTATUS pvfs_rename ( struct ntvfs_module_context * ntvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req , union smb_rename * ren )
2004-11-13 09:46:51 +03:00
{
2009-02-04 10:52:41 +03:00
struct pvfs_state * pvfs = talloc_get_type ( ntvfs - > private_data ,
struct pvfs_state ) ;
2008-03-12 17:12:26 +03:00
struct pvfs_file * f ;
2004-11-13 09:46:51 +03:00
switch ( ren - > generic . level ) {
case RAW_RENAME_RENAME :
return pvfs_rename_mv ( ntvfs , req , ren ) ;
case RAW_RENAME_NTRENAME :
return pvfs_rename_nt ( ntvfs , req , ren ) ;
2008-03-11 21:29:18 +03:00
case RAW_RENAME_NTTRANS :
2008-03-12 17:12:26 +03:00
f = pvfs_find_fd ( pvfs , req , ren - > nttrans . in . file . ntvfs ) ;
if ( ! f ) {
return NT_STATUS_INVALID_HANDLE ;
}
/* wk23 ignores the request */
return NT_STATUS_OK ;
2008-03-11 21:29:18 +03:00
2004-11-13 09:46:51 +03:00
default :
break ;
}
return NT_STATUS_INVALID_LEVEL ;
}