2007-03-13 04:47:04 +03:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 2004
2008-02-21 18:12:27 +03:00
Copyright ( C ) Stefan Metzmacher 2008
2007-03-13 04:47:04 +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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-03-13 04:47:04 +03: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/>.
2007-03-13 04:47:04 +03:00
*/
/*
this is the open files database , tdb backend . It implements shared
storage of what files are open between server instances , and
implements the rules of shared access to files .
The caller needs to provide a file_key , which specifies what file
they are talking about . This needs to be a unique key across all
filesystems , and is usually implemented in terms of a device / inode
pair .
Before any operations can be performed the caller needs to establish
a lock on the record associated with file_key . That is done by
calling odb_lock ( ) . The caller releases this lock by calling
talloc_free ( ) on the returned handle .
All other operations on a record are done by passing the odb_lock ( )
handle back to this module . The handle contains internal
information about what file_key is being operated on .
*/
# include "includes.h"
# include "system/filesys.h"
2013-04-11 11:42:15 +04:00
# include "lib/dbwrap/dbwrap.h"
2007-03-13 04:47:04 +03:00
# include "messaging/messaging.h"
# include "lib/messaging/irpc.h"
# include "librpc/gen_ndr/ndr_opendb.h"
# include "ntvfs/ntvfs.h"
# include "ntvfs/common/ntvfs_common.h"
# include "cluster/cluster.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2008-03-07 14:21:11 +03:00
# include "ntvfs/sysdep/sys_lease.h"
2007-03-13 04:47:04 +03:00
struct odb_context {
2013-04-11 11:42:15 +04:00
struct db_context * db ;
2007-03-13 04:47:04 +03:00
struct ntvfs_context * ntvfs_ctx ;
2007-10-07 02:28:14 +04:00
bool oplocks ;
2008-03-07 14:21:11 +03:00
struct sys_lease_context * lease_ctx ;
2007-03-13 04:47:04 +03:00
} ;
/*
an odb lock handle . You must obtain one of these using odb_lock ( ) before doing
any other operations .
*/
struct odb_lock {
struct odb_context * odb ;
2013-04-11 11:42:15 +04:00
struct db_record * locked ;
2008-03-07 20:23:34 +03:00
2008-03-08 10:55:12 +03:00
struct opendb_file file ;
2008-03-07 20:23:34 +03:00
struct {
struct opendb_entry * e ;
bool attrs_only ;
} can_open ;
2007-03-13 04:47:04 +03:00
} ;
2011-05-03 04:40:33 +04:00
static NTSTATUS odb_oplock_break_send ( struct imessaging_context * msg_ctx ,
2008-03-07 14:21:11 +03:00
struct opendb_entry * e ,
uint8_t level ) ;
2007-03-13 04:47:04 +03:00
/*
Open up the openfiles . tdb database . Close it down using
2011-05-03 04:40:33 +04:00
talloc_free ( ) . We need the imessaging_ctx to allow for pending open
2007-03-13 04:47:04 +03:00
notifications .
*/
static struct odb_context * odb_tdb_init ( TALLOC_CTX * mem_ctx ,
struct ntvfs_context * ntvfs_ctx )
{
struct odb_context * odb ;
odb = talloc ( mem_ctx , struct odb_context ) ;
if ( odb = = NULL ) {
return NULL ;
}
2013-04-11 11:42:15 +04:00
odb - > db = cluster_db_tmp_open ( odb , ntvfs_ctx - > lp_ctx ,
" openfiles " , TDB_DEFAULT ) ;
if ( odb - > db = = NULL ) {
2007-03-13 04:47:04 +03:00
talloc_free ( odb ) ;
return NULL ;
}
odb - > ntvfs_ctx = ntvfs_ctx ;
2008-03-27 12:40:40 +03:00
odb - > oplocks = share_bool_option ( ntvfs_ctx - > config , SHARE_OPLOCKS , SHARE_OPLOCKS_DEFAULT ) ;
2007-03-13 04:47:04 +03:00
2008-03-07 14:21:11 +03:00
odb - > lease_ctx = sys_lease_context_create ( ntvfs_ctx - > config , odb ,
ntvfs_ctx - > event_ctx ,
ntvfs_ctx - > msg_ctx ,
odb_oplock_break_send ) ;
2007-03-13 04:47:04 +03:00
return odb ;
}
2008-03-08 10:55:12 +03:00
static NTSTATUS odb_pull_record ( struct odb_lock * lck , struct opendb_file * file ) ;
2007-03-13 04:47:04 +03:00
/*
get a lock on a entry in the odb . This call returns a lock handle ,
which the caller should unlock using talloc_free ( ) .
*/
static struct odb_lock * odb_tdb_lock ( TALLOC_CTX * mem_ctx ,
struct odb_context * odb , DATA_BLOB * file_key )
{
struct odb_lock * lck ;
2008-03-08 10:55:12 +03:00
NTSTATUS status ;
2013-04-11 11:42:15 +04:00
TDB_DATA key ;
2007-03-13 04:47:04 +03:00
lck = talloc ( mem_ctx , struct odb_lock ) ;
if ( lck = = NULL ) {
return NULL ;
}
lck - > odb = talloc_reference ( lck , odb ) ;
2013-04-11 11:42:15 +04:00
key . dptr = talloc_memdup ( lck , file_key - > data , file_key - > length ) ;
key . dsize = file_key - > length ;
if ( key . dptr = = NULL ) {
2007-03-13 04:47:04 +03:00
talloc_free ( lck ) ;
return NULL ;
}
2013-04-11 11:42:15 +04:00
lck - > locked = dbwrap_fetch_locked ( odb - > db , lck , key ) ;
if ( ! lck - > locked ) {
2007-03-13 04:47:04 +03:00
talloc_free ( lck ) ;
return NULL ;
}
2008-03-07 20:23:34 +03:00
ZERO_STRUCT ( lck - > can_open ) ;
2008-03-08 10:55:12 +03:00
status = odb_pull_record ( lck , & lck - > file ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
/* initialise a blank structure */
ZERO_STRUCT ( lck - > file ) ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( lck ) ;
return NULL ;
}
2007-03-13 04:47:04 +03:00
return lck ;
}
2008-02-22 12:18:13 +03:00
static DATA_BLOB odb_tdb_get_key ( TALLOC_CTX * mem_ctx , struct odb_lock * lck )
{
2013-04-11 11:42:15 +04:00
TDB_DATA key = dbwrap_record_get_key ( lck - > locked ) ;
return data_blob_talloc ( mem_ctx , key . dptr , key . dsize ) ;
2008-02-22 12:18:13 +03:00
}
2007-03-13 04:47:04 +03:00
/*
determine if two odb_entry structures conflict
return NT_STATUS_OK on no conflict
*/
2008-02-25 18:26:04 +03:00
static NTSTATUS share_conflict ( struct opendb_entry * e1 ,
uint32_t stream_id ,
uint32_t share_access ,
uint32_t access_mask )
2007-03-13 04:47:04 +03:00
{
/* if either open involves no read.write or delete access then
it can ' t conflict */
if ( ! ( e1 - > access_mask & ( SEC_FILE_WRITE_DATA |
SEC_FILE_APPEND_DATA |
SEC_FILE_READ_DATA |
SEC_FILE_EXECUTE |
SEC_STD_DELETE ) ) ) {
return NT_STATUS_OK ;
}
2008-02-25 18:26:04 +03:00
if ( ! ( access_mask & ( SEC_FILE_WRITE_DATA |
SEC_FILE_APPEND_DATA |
SEC_FILE_READ_DATA |
SEC_FILE_EXECUTE |
SEC_STD_DELETE ) ) ) {
2007-03-13 04:47:04 +03:00
return NT_STATUS_OK ;
}
/* data IO access masks. This is skipped if the two open handles
are on different streams ( as in that case the masks don ' t
interact ) */
2008-02-25 18:26:04 +03:00
if ( e1 - > stream_id ! = stream_id ) {
2007-03-13 04:47:04 +03:00
return NT_STATUS_OK ;
}
# define CHECK_MASK(am, right, sa, share) \
if ( ( ( am ) & ( right ) ) & & ! ( ( sa ) & ( share ) ) ) return NT_STATUS_SHARING_VIOLATION
CHECK_MASK ( e1 - > access_mask , SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA ,
2008-02-25 18:26:04 +03:00
share_access , NTCREATEX_SHARE_ACCESS_WRITE ) ;
CHECK_MASK ( access_mask , SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA ,
2007-03-13 04:47:04 +03:00
e1 - > share_access , NTCREATEX_SHARE_ACCESS_WRITE ) ;
CHECK_MASK ( e1 - > access_mask , SEC_FILE_READ_DATA | SEC_FILE_EXECUTE ,
2008-02-25 18:26:04 +03:00
share_access , NTCREATEX_SHARE_ACCESS_READ ) ;
CHECK_MASK ( access_mask , SEC_FILE_READ_DATA | SEC_FILE_EXECUTE ,
2007-03-13 04:47:04 +03:00
e1 - > share_access , NTCREATEX_SHARE_ACCESS_READ ) ;
CHECK_MASK ( e1 - > access_mask , SEC_STD_DELETE ,
2008-02-25 18:26:04 +03:00
share_access , NTCREATEX_SHARE_ACCESS_DELETE ) ;
CHECK_MASK ( access_mask , SEC_STD_DELETE ,
2007-03-13 04:47:04 +03:00
e1 - > share_access , NTCREATEX_SHARE_ACCESS_DELETE ) ;
2008-02-22 19:26:40 +03:00
# undef CHECK_MASK
2007-03-13 04:47:04 +03:00
return NT_STATUS_OK ;
}
/*
pull a record , translating from the db format to the opendb_file structure defined
in opendb . idl
*/
static NTSTATUS odb_pull_record ( struct odb_lock * lck , struct opendb_file * file )
{
TDB_DATA dbuf ;
DATA_BLOB blob ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2013-04-11 11:42:15 +04:00
dbuf = dbwrap_record_get_value ( lck - > locked ) ;
if ( ! dbuf . dptr ) {
2007-03-13 04:47:04 +03:00
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
blob . data = dbuf . dptr ;
blob . length = dbuf . dsize ;
2010-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob ( & blob , lck , file , ( ndr_pull_flags_fn_t ) ndr_pull_opendb_file ) ;
2007-11-09 21:24:51 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2007-03-13 04:47:04 +03:00
2007-11-09 21:24:51 +03:00
return NT_STATUS_OK ;
2007-03-13 04:47:04 +03:00
}
/*
push a record , translating from the opendb_file structure defined in opendb . idl
*/
static NTSTATUS odb_push_record ( struct odb_lock * lck , struct opendb_file * file )
{
TDB_DATA dbuf ;
DATA_BLOB blob ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2013-04-11 11:42:15 +04:00
NTSTATUS status ;
2007-03-13 04:47:04 +03:00
if ( file - > num_entries = = 0 ) {
2013-04-11 11:42:15 +04:00
return dbwrap_record_delete ( lck - > locked ) ;
2007-03-13 04:47:04 +03:00
}
2010-05-09 19:20:01 +04:00
ndr_err = ndr_push_struct_blob ( & blob , lck , file , ( ndr_push_flags_fn_t ) ndr_push_opendb_file ) ;
2007-11-09 21:24:51 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2007-03-13 04:47:04 +03:00
dbuf . dptr = blob . data ;
dbuf . dsize = blob . length ;
2013-04-11 11:42:15 +04:00
status = dbwrap_record_store ( lck - > locked , dbuf , TDB_REPLACE ) ;
2007-03-13 04:47:04 +03:00
data_blob_free ( & blob ) ;
2013-04-11 11:42:15 +04:00
return status ;
2007-03-13 04:47:04 +03:00
}
/*
send an oplock break to a client
*/
2011-05-03 04:40:33 +04:00
static NTSTATUS odb_oplock_break_send ( struct imessaging_context * msg_ctx ,
2008-02-21 14:20:31 +03:00
struct opendb_entry * e ,
uint8_t level )
2007-03-13 04:47:04 +03:00
{
2008-02-21 14:20:31 +03:00
NTSTATUS status ;
struct opendb_oplock_break op_break ;
DATA_BLOB blob ;
ZERO_STRUCT ( op_break ) ;
2007-03-13 04:47:04 +03:00
/* tell the server handling this open file about the need to send the client
a break */
2008-02-21 14:20:31 +03:00
op_break . file_handle = e - > file_handle ;
op_break . level = level ;
blob = data_blob_const ( & op_break , sizeof ( op_break ) ) ;
2011-05-03 04:40:33 +04:00
status = imessaging_send ( msg_ctx , e - > server ,
2008-02-21 14:20:31 +03:00
MSG_NTVFS_OPLOCK_BREAK , & blob ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
return NT_STATUS_OK ;
2007-03-13 04:47:04 +03:00
}
2008-02-22 19:26:40 +03:00
static bool access_attributes_only ( uint32_t access_mask ,
2008-02-26 14:52:46 +03:00
uint32_t open_disposition ,
bool break_to_none )
2008-02-22 19:26:40 +03:00
{
switch ( open_disposition ) {
case NTCREATEX_DISP_SUPERSEDE :
case NTCREATEX_DISP_OVERWRITE_IF :
case NTCREATEX_DISP_OVERWRITE :
return false ;
default :
break ;
}
2008-02-26 14:52:46 +03:00
if ( break_to_none ) {
return false ;
}
2008-02-22 19:26:40 +03:00
# define CHECK_MASK(m,g) ((m) && (((m) & ~(g))==0) && (((m) & (g)) != 0))
return CHECK_MASK ( access_mask ,
SEC_STD_SYNCHRONIZE |
SEC_FILE_READ_ATTRIBUTE |
SEC_FILE_WRITE_ATTRIBUTE ) ;
# undef CHECK_MASK
}
2008-02-25 18:26:04 +03:00
static NTSTATUS odb_tdb_open_can_internal ( struct odb_context * odb ,
const struct opendb_file * file ,
uint32_t stream_id , uint32_t share_access ,
uint32_t access_mask , bool delete_on_close ,
uint32_t open_disposition , bool break_to_none ,
bool * _attrs_only )
2007-03-13 04:47:04 +03:00
{
NTSTATUS status ;
2008-02-25 18:26:04 +03:00
uint32_t i ;
2008-02-22 19:26:40 +03:00
bool attrs_only = false ;
2007-03-13 04:47:04 +03:00
/* see if anyone has an oplock, which we need to break */
2008-02-25 18:26:04 +03:00
for ( i = 0 ; i < file - > num_entries ; i + + ) {
if ( file - > entries [ i ] . oplock_level = = OPLOCK_BATCH ) {
2008-02-25 18:14:23 +03:00
bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II ;
2008-02-22 19:26:40 +03:00
/* if this is an attribute only access
* it doesn ' t conflict with a BACTCH oplock
* but we ' ll not grant the oplock below
*/
attrs_only = access_attributes_only ( access_mask ,
2008-02-26 14:52:46 +03:00
open_disposition ,
break_to_none ) ;
2008-02-22 19:26:40 +03:00
if ( attrs_only ) {
break ;
}
2007-03-13 04:47:04 +03:00
/* a batch oplock caches close calls, which
means the client application might have
already closed the file . We have to allow
2018-05-04 23:22:46 +03:00
this close to propagate by sending a oplock
2007-03-13 04:47:04 +03:00
break request and suspending this call
until the break is acknowledged or the file
is closed */
2008-03-06 17:47:27 +03:00
if ( break_to_none | |
! file - > entries [ i ] . allow_level_II_oplock ) {
2008-02-25 18:14:23 +03:00
oplock_return = OPLOCK_BREAK_TO_NONE ;
}
2008-03-07 12:33:57 +03:00
odb_oplock_break_send ( odb - > ntvfs_ctx - > msg_ctx ,
& file - > entries [ i ] ,
2008-02-25 18:14:23 +03:00
oplock_return ) ;
2007-03-13 04:47:04 +03:00
return NT_STATUS_OPLOCK_NOT_GRANTED ;
}
}
2008-02-25 22:20:35 +03:00
if ( file - > delete_on_close ) {
2007-03-13 04:47:04 +03:00
/* while delete on close is set, no new opens are allowed */
return NT_STATUS_DELETE_PENDING ;
}
2008-02-25 22:20:35 +03:00
if ( file - > num_entries ! = 0 & & delete_on_close ) {
return NT_STATUS_SHARING_VIOLATION ;
}
2007-03-13 04:47:04 +03:00
/* check for sharing violations */
2008-02-25 18:26:04 +03:00
for ( i = 0 ; i < file - > num_entries ; i + + ) {
status = share_conflict ( & file - > entries [ i ] , stream_id ,
share_access , access_mask ) ;
2007-03-13 04:47:04 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
/* we now know the open could succeed, but we need to check
for any exclusive oplocks . We can ' t grant a second open
till these are broken . Note that we check for batch oplocks
before checking for sharing violations , and check for
exclusive oplocks afterwards . */
2008-02-25 18:26:04 +03:00
for ( i = 0 ; i < file - > num_entries ; i + + ) {
if ( file - > entries [ i ] . oplock_level = = OPLOCK_EXCLUSIVE ) {
2008-02-27 11:40:49 +03:00
bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II ;
/* if this is an attribute only access
* it doesn ' t conflict with an EXCLUSIVE oplock
* but we ' ll not grant the oplock below
*/
attrs_only = access_attributes_only ( access_mask ,
open_disposition ,
break_to_none ) ;
if ( attrs_only ) {
break ;
}
/*
* send an oplock break to the holder of the
* oplock and tell caller to retry later
*/
2008-03-06 17:47:27 +03:00
if ( break_to_none | |
! file - > entries [ i ] . allow_level_II_oplock ) {
2008-02-27 11:40:49 +03:00
oplock_return = OPLOCK_BREAK_TO_NONE ;
}
2008-03-07 12:33:57 +03:00
odb_oplock_break_send ( odb - > ntvfs_ctx - > msg_ctx ,
& file - > entries [ i ] ,
2008-02-27 11:40:49 +03:00
oplock_return ) ;
2007-03-13 04:47:04 +03:00
return NT_STATUS_OPLOCK_NOT_GRANTED ;
}
}
2008-02-25 18:26:04 +03:00
if ( _attrs_only ) {
* _attrs_only = attrs_only ;
}
return NT_STATUS_OK ;
}
/*
2008-03-07 20:23:34 +03:00
register an open file in the open files database .
The share_access rules are implemented by odb_can_open ( )
and it ' s needed to call odb_can_open ( ) before
odb_open_file ( ) otherwise NT_STATUS_INTERNAL_ERROR is returned
2008-02-25 18:26:04 +03:00
Note that the path is only used by the delete on close logic , not
for comparing with other filenames
*/
2008-02-25 18:47:48 +03:00
static NTSTATUS odb_tdb_open_file ( struct odb_lock * lck ,
void * file_handle , const char * path ,
2008-04-15 18:00:42 +04:00
int * fd , NTTIME open_write_time ,
bool allow_level_II_oplock ,
2008-02-25 18:26:04 +03:00
uint32_t oplock_level , uint32_t * oplock_granted )
{
struct odb_context * odb = lck - > odb ;
2008-03-07 20:23:34 +03:00
if ( ! lck - > can_open . e ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2008-02-25 18:26:04 +03:00
if ( odb - > oplocks = = false ) {
oplock_level = OPLOCK_NONE ;
}
2008-03-07 20:23:34 +03:00
if ( ! oplock_granted ) {
oplock_level = OPLOCK_NONE ;
}
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
lck - > file . path = talloc_strdup ( lck , path ) ;
NT_STATUS_HAVE_NO_MEMORY ( lck - > file . path ) ;
2008-02-25 18:26:04 +03:00
}
2008-04-15 18:00:42 +04:00
if ( lck - > file . open_write_time = = 0 ) {
lck - > file . open_write_time = open_write_time ;
}
2007-03-13 04:47:04 +03:00
/*
2008-02-22 19:26:40 +03:00
possibly grant an exclusive , batch or level2 oplock
2007-03-13 04:47:04 +03:00
*/
2008-03-07 20:23:34 +03:00
if ( lck - > can_open . attrs_only ) {
oplock_level = OPLOCK_NONE ;
} else if ( oplock_level = = OPLOCK_EXCLUSIVE ) {
2008-03-08 10:55:12 +03:00
if ( lck - > file . num_entries = = 0 ) {
2008-03-07 20:23:34 +03:00
oplock_level = OPLOCK_EXCLUSIVE ;
} else if ( allow_level_II_oplock ) {
oplock_level = OPLOCK_LEVEL_II ;
} else {
oplock_level = OPLOCK_NONE ;
}
} else if ( oplock_level = = OPLOCK_BATCH ) {
2008-03-08 10:55:12 +03:00
if ( lck - > file . num_entries = = 0 ) {
2008-03-07 20:23:34 +03:00
oplock_level = OPLOCK_BATCH ;
} else if ( allow_level_II_oplock ) {
oplock_level = OPLOCK_LEVEL_II ;
} else {
oplock_level = OPLOCK_NONE ;
}
} else if ( oplock_level = = OPLOCK_LEVEL_II ) {
oplock_level = OPLOCK_LEVEL_II ;
} else {
oplock_level = OPLOCK_NONE ;
}
2008-03-07 14:21:11 +03:00
lck - > can_open . e - > file_handle = file_handle ;
lck - > can_open . e - > fd = fd ;
lck - > can_open . e - > allow_level_II_oplock = allow_level_II_oplock ;
lck - > can_open . e - > oplock_level = oplock_level ;
if ( odb - > lease_ctx & & fd ) {
NTSTATUS status ;
status = sys_lease_setup ( odb - > lease_ctx , lck - > can_open . e ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2008-02-22 19:26:40 +03:00
if ( oplock_granted ) {
2008-03-07 14:21:11 +03:00
if ( lck - > can_open . e - > oplock_level = = OPLOCK_EXCLUSIVE ) {
2008-03-07 20:23:34 +03:00
* oplock_granted = EXCLUSIVE_OPLOCK_RETURN ;
2008-03-07 14:21:11 +03:00
} else if ( lck - > can_open . e - > oplock_level = = OPLOCK_BATCH ) {
2008-03-07 20:23:34 +03:00
* oplock_granted = BATCH_OPLOCK_RETURN ;
2008-03-07 14:21:11 +03:00
} else if ( lck - > can_open . e - > oplock_level = = OPLOCK_LEVEL_II ) {
2008-02-22 19:26:40 +03:00
* oplock_granted = LEVEL_II_OPLOCK_RETURN ;
2007-03-13 04:47:04 +03:00
} else {
2008-02-22 19:26:40 +03:00
* oplock_granted = NO_OPLOCK_RETURN ;
2007-03-13 04:47:04 +03:00
}
}
/* it doesn't conflict, so add it to the end */
2008-03-08 10:55:12 +03:00
lck - > file . entries = talloc_realloc ( lck , lck - > file . entries ,
struct opendb_entry ,
lck - > file . num_entries + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( lck - > file . entries ) ;
lck - > file . entries [ lck - > file . num_entries ] = * lck - > can_open . e ;
lck - > file . num_entries + + ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
talloc_free ( lck - > can_open . e ) ;
lck - > can_open . e = NULL ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
return odb_push_record ( lck , & lck - > file ) ;
2007-03-13 04:47:04 +03:00
}
/*
register a pending open file in the open files database
*/
2009-02-02 10:32:46 +03:00
static NTSTATUS odb_tdb_open_file_pending ( struct odb_lock * lck , void * private_data )
2007-03-13 04:47:04 +03:00
{
struct odb_context * odb = lck - > odb ;
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
lck - > file . pending = talloc_realloc ( lck , lck - > file . pending ,
struct opendb_pending ,
lck - > file . num_pending + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( lck - > file . pending ) ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
lck - > file . pending [ lck - > file . num_pending ] . server = odb - > ntvfs_ctx - > server_id ;
2009-02-02 10:32:46 +03:00
lck - > file . pending [ lck - > file . num_pending ] . notify_ptr = private_data ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
lck - > file . num_pending + + ;
return odb_push_record ( lck , & lck - > file ) ;
2007-03-13 04:47:04 +03:00
}
/*
remove a opendb entry
*/
2008-02-27 23:50:51 +03:00
static NTSTATUS odb_tdb_close_file ( struct odb_lock * lck , void * file_handle ,
const char * * _delete_path )
2007-03-13 04:47:04 +03:00
{
struct odb_context * odb = lck - > odb ;
2008-02-27 23:50:51 +03:00
const char * delete_path = NULL ;
2007-03-13 04:47:04 +03:00
int i ;
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-03-13 04:47:04 +03:00
/* find the entry, and delete it */
2008-03-08 10:55:12 +03:00
for ( i = 0 ; i < lck - > file . num_entries ; i + + ) {
if ( file_handle = = lck - > file . entries [ i ] . file_handle & &
cluster_id_equal ( & odb - > ntvfs_ctx - > server_id , & lck - > file . entries [ i ] . server ) ) {
if ( lck - > file . entries [ i ] . delete_on_close ) {
lck - > file . delete_on_close = true ;
2007-03-13 04:47:04 +03:00
}
2008-03-07 14:21:11 +03:00
if ( odb - > lease_ctx & & lck - > file . entries [ i ] . fd ) {
NTSTATUS status ;
status = sys_lease_remove ( odb - > lease_ctx , & lck - > file . entries [ i ] ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2008-03-08 10:55:12 +03:00
if ( i < lck - > file . num_entries - 1 ) {
memmove ( lck - > file . entries + i , lck - > file . entries + i + 1 ,
( lck - > file . num_entries - ( i + 1 ) ) *
2007-03-13 04:47:04 +03:00
sizeof ( struct opendb_entry ) ) ;
}
break ;
}
}
2008-03-08 10:55:12 +03:00
if ( i = = lck - > file . num_entries ) {
2007-03-13 04:47:04 +03:00
return NT_STATUS_UNSUCCESSFUL ;
}
/* send any pending notifications, removing them once sent */
2008-03-08 10:55:12 +03:00
for ( i = 0 ; i < lck - > file . num_pending ; i + + ) {
2011-05-03 04:40:33 +04:00
imessaging_send_ptr ( odb - > ntvfs_ctx - > msg_ctx ,
2008-03-08 10:55:12 +03:00
lck - > file . pending [ i ] . server ,
MSG_PVFS_RETRY_OPEN ,
lck - > file . pending [ i ] . notify_ptr ) ;
2007-03-13 04:47:04 +03:00
}
2008-03-08 10:55:12 +03:00
lck - > file . num_pending = 0 ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
lck - > file . num_entries - - ;
2008-02-27 23:50:51 +03:00
2008-03-08 10:55:12 +03:00
if ( lck - > file . num_entries = = 0 & & lck - > file . delete_on_close ) {
delete_path = lck - > file . path ;
2008-02-27 23:50:51 +03:00
}
if ( _delete_path ) {
* _delete_path = delete_path ;
}
2008-03-08 10:55:12 +03:00
return odb_push_record ( lck , & lck - > file ) ;
2007-03-13 04:47:04 +03:00
}
2008-02-21 18:12:27 +03:00
/*
update the oplock level of the client
*/
static NTSTATUS odb_tdb_update_oplock ( struct odb_lock * lck , void * file_handle ,
uint32_t oplock_level )
{
struct odb_context * odb = lck - > odb ;
int i ;
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2008-02-21 18:12:27 +03:00
/* find the entry, and update it */
2008-03-08 10:55:12 +03:00
for ( i = 0 ; i < lck - > file . num_entries ; i + + ) {
if ( file_handle = = lck - > file . entries [ i ] . file_handle & &
cluster_id_equal ( & odb - > ntvfs_ctx - > server_id , & lck - > file . entries [ i ] . server ) ) {
lck - > file . entries [ i ] . oplock_level = oplock_level ;
2008-03-07 14:21:11 +03:00
if ( odb - > lease_ctx & & lck - > file . entries [ i ] . fd ) {
NTSTATUS status ;
status = sys_lease_update ( odb - > lease_ctx , & lck - > file . entries [ i ] ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2008-02-21 18:12:27 +03:00
break ;
}
}
2008-03-08 10:55:12 +03:00
if ( i = = lck - > file . num_entries ) {
2008-02-21 18:12:27 +03:00
return NT_STATUS_UNSUCCESSFUL ;
}
/* send any pending notifications, removing them once sent */
2008-03-08 10:55:12 +03:00
for ( i = 0 ; i < lck - > file . num_pending ; i + + ) {
2011-05-03 04:40:33 +04:00
imessaging_send_ptr ( odb - > ntvfs_ctx - > msg_ctx ,
2008-03-08 10:55:12 +03:00
lck - > file . pending [ i ] . server ,
2008-02-21 18:12:27 +03:00
MSG_PVFS_RETRY_OPEN ,
2008-03-08 10:55:12 +03:00
lck - > file . pending [ i ] . notify_ptr ) ;
2008-02-21 18:12:27 +03:00
}
2008-03-08 10:55:12 +03:00
lck - > file . num_pending = 0 ;
2008-02-21 18:12:27 +03:00
2008-03-08 10:55:12 +03:00
return odb_push_record ( lck , & lck - > file ) ;
2008-02-21 18:12:27 +03:00
}
2008-02-22 18:30:13 +03:00
/*
send oplocks breaks to none to all level2 holders
*/
static NTSTATUS odb_tdb_break_oplocks ( struct odb_lock * lck )
{
struct odb_context * odb = lck - > odb ;
int i ;
2008-03-08 10:58:41 +03:00
bool modified = false ;
2008-02-22 18:30:13 +03:00
/* see if anyone has an oplock, which we need to break */
2008-03-08 10:55:12 +03:00
for ( i = 0 ; i < lck - > file . num_entries ; i + + ) {
if ( lck - > file . entries [ i ] . oplock_level = = OPLOCK_LEVEL_II ) {
2008-02-22 18:30:13 +03:00
/*
* there could be multiple level2 oplocks
* and we just send a break to none to all of them
* without waiting for a release
*/
2008-03-07 12:33:57 +03:00
odb_oplock_break_send ( odb - > ntvfs_ctx - > msg_ctx ,
2008-03-08 10:55:12 +03:00
& lck - > file . entries [ i ] ,
2008-02-22 18:30:13 +03:00
OPLOCK_BREAK_TO_NONE ) ;
2008-03-08 10:55:12 +03:00
lck - > file . entries [ i ] . oplock_level = OPLOCK_NONE ;
2008-02-22 18:30:13 +03:00
modified = true ;
}
}
if ( modified ) {
2008-03-08 10:55:12 +03:00
return odb_push_record ( lck , & lck - > file ) ;
2008-02-22 18:30:13 +03:00
}
return NT_STATUS_OK ;
}
2007-03-13 04:47:04 +03:00
/*
remove a pending opendb entry
*/
2009-02-02 10:32:46 +03:00
static NTSTATUS odb_tdb_remove_pending ( struct odb_lock * lck , void * private_data )
2007-03-13 04:47:04 +03:00
{
struct odb_context * odb = lck - > odb ;
int i ;
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-03-13 04:47:04 +03:00
/* find the entry, and delete it */
2008-03-08 10:55:12 +03:00
for ( i = 0 ; i < lck - > file . num_pending ; i + + ) {
2009-02-02 10:32:46 +03:00
if ( private_data = = lck - > file . pending [ i ] . notify_ptr & &
2008-03-08 10:55:12 +03:00
cluster_id_equal ( & odb - > ntvfs_ctx - > server_id , & lck - > file . pending [ i ] . server ) ) {
if ( i < lck - > file . num_pending - 1 ) {
memmove ( lck - > file . pending + i , lck - > file . pending + i + 1 ,
( lck - > file . num_pending - ( i + 1 ) ) *
2007-03-13 04:47:04 +03:00
sizeof ( struct opendb_pending ) ) ;
}
break ;
}
}
2008-03-08 10:55:12 +03:00
if ( i = = lck - > file . num_pending ) {
2007-03-13 04:47:04 +03:00
return NT_STATUS_UNSUCCESSFUL ;
}
2008-03-08 10:55:12 +03:00
lck - > file . num_pending - - ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
return odb_push_record ( lck , & lck - > file ) ;
2007-03-13 04:47:04 +03:00
}
/*
rename the path in a open file
*/
static NTSTATUS odb_tdb_rename ( struct odb_lock * lck , const char * path )
{
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
2007-03-13 04:47:04 +03:00
/* not having the record at all is OK */
return NT_STATUS_OK ;
}
2008-03-08 10:55:12 +03:00
lck - > file . path = talloc_strdup ( lck , path ) ;
NT_STATUS_HAVE_NO_MEMORY ( lck - > file . path ) ;
return odb_push_record ( lck , & lck - > file ) ;
2007-03-13 04:47:04 +03:00
}
2008-02-28 11:06:49 +03:00
/*
get the path of an open file
*/
static NTSTATUS odb_tdb_get_path ( struct odb_lock * lck , const char * * path )
{
* path = NULL ;
/* we don't ignore NT_STATUS_OBJECT_NAME_NOT_FOUND here */
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2008-02-28 11:06:49 +03:00
2008-03-08 10:55:12 +03:00
* path = lck - > file . path ;
2008-02-28 11:06:49 +03:00
return NT_STATUS_OK ;
}
2007-03-13 04:47:04 +03:00
/*
update delete on close flag on an open file
*/
2007-10-07 02:28:14 +04:00
static NTSTATUS odb_tdb_set_delete_on_close ( struct odb_lock * lck , bool del_on_close )
2007-03-13 04:47:04 +03:00
{
2008-03-08 10:55:12 +03:00
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
lck - > file . delete_on_close = del_on_close ;
2007-03-13 04:47:04 +03:00
2008-03-08 10:55:12 +03:00
return odb_push_record ( lck , & lck - > file ) ;
2007-03-13 04:47:04 +03:00
}
2008-04-15 18:00:42 +04:00
/*
update the write time on an open file
*/
static NTSTATUS odb_tdb_set_write_time ( struct odb_lock * lck ,
NTTIME write_time , bool force )
{
if ( lck - > file . path = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
if ( lck - > file . changed_write_time ! = 0 & & ! force ) {
return NT_STATUS_OK ;
}
lck - > file . changed_write_time = write_time ;
return odb_push_record ( lck , & lck - > file ) ;
}
2007-03-13 04:47:04 +03:00
/*
return the current value of the delete_on_close bit , and how many
people still have the file open
*/
2008-04-15 18:00:42 +04:00
static NTSTATUS odb_tdb_get_file_infos ( struct odb_context * odb , DATA_BLOB * key ,
bool * del_on_close , NTTIME * write_time )
2007-03-13 04:47:04 +03:00
{
struct odb_lock * lck ;
2008-04-15 18:00:42 +04:00
if ( del_on_close ) {
* del_on_close = false ;
}
if ( write_time ) {
* write_time = 0 ;
}
2008-02-28 00:16:55 +03:00
2007-03-13 04:47:04 +03:00
lck = odb_lock ( odb , odb , key ) ;
NT_STATUS_HAVE_NO_MEMORY ( lck ) ;
2008-04-15 18:00:42 +04:00
if ( del_on_close ) {
* del_on_close = lck - > file . delete_on_close ;
}
if ( write_time ) {
if ( lck - > file . changed_write_time = = 0 ) {
* write_time = lck - > file . open_write_time ;
} else {
* write_time = lck - > file . changed_write_time ;
}
}
2007-03-13 04:47:04 +03:00
talloc_free ( lck ) ;
return NT_STATUS_OK ;
}
/*
determine if a file can be opened with the given share_access ,
create_options and access_mask
*/
static NTSTATUS odb_tdb_can_open ( struct odb_lock * lck ,
2008-02-25 19:48:13 +03:00
uint32_t stream_id , uint32_t share_access ,
uint32_t access_mask , bool delete_on_close ,
uint32_t open_disposition , bool break_to_none )
2007-03-13 04:47:04 +03:00
{
struct odb_context * odb = lck - > odb ;
NTSTATUS status ;
2008-03-08 10:55:12 +03:00
status = odb_tdb_open_can_internal ( odb , & lck - > file , stream_id ,
2008-02-25 18:26:04 +03:00
share_access , access_mask ,
delete_on_close , open_disposition ,
2008-03-07 20:23:34 +03:00
break_to_none , & lck - > can_open . attrs_only ) ;
2008-02-25 18:26:04 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2007-03-13 04:47:04 +03:00
2008-03-07 20:23:34 +03:00
lck - > can_open . e = talloc ( lck , struct opendb_entry ) ;
NT_STATUS_HAVE_NO_MEMORY ( lck - > can_open . e ) ;
lck - > can_open . e - > server = odb - > ntvfs_ctx - > server_id ;
lck - > can_open . e - > file_handle = NULL ;
2008-03-08 11:12:09 +03:00
lck - > can_open . e - > fd = NULL ;
2008-03-07 20:23:34 +03:00
lck - > can_open . e - > stream_id = stream_id ;
lck - > can_open . e - > share_access = share_access ;
lck - > can_open . e - > access_mask = access_mask ;
lck - > can_open . e - > delete_on_close = delete_on_close ;
lck - > can_open . e - > allow_level_II_oplock = false ;
lck - > can_open . e - > oplock_level = OPLOCK_NONE ;
2007-03-13 04:47:04 +03:00
return NT_STATUS_OK ;
}
static const struct opendb_ops opendb_tdb_ops = {
. odb_init = odb_tdb_init ,
. odb_lock = odb_tdb_lock ,
2008-02-22 12:18:13 +03:00
. odb_get_key = odb_tdb_get_key ,
2007-03-13 04:47:04 +03:00
. odb_open_file = odb_tdb_open_file ,
. odb_open_file_pending = odb_tdb_open_file_pending ,
. odb_close_file = odb_tdb_close_file ,
. odb_remove_pending = odb_tdb_remove_pending ,
. odb_rename = odb_tdb_rename ,
2008-02-28 11:06:49 +03:00
. odb_get_path = odb_tdb_get_path ,
2007-03-13 04:47:04 +03:00
. odb_set_delete_on_close = odb_tdb_set_delete_on_close ,
2008-04-15 18:00:42 +04:00
. odb_set_write_time = odb_tdb_set_write_time ,
. odb_get_file_infos = odb_tdb_get_file_infos ,
2008-02-21 18:12:27 +03:00
. odb_can_open = odb_tdb_can_open ,
2008-02-22 18:30:13 +03:00
. odb_update_oplock = odb_tdb_update_oplock ,
. odb_break_oplocks = odb_tdb_break_oplocks
2007-03-13 04:47:04 +03:00
} ;
void odb_tdb_init_ops ( void )
{
2008-03-07 14:21:11 +03:00
sys_lease_init ( ) ;
2007-03-13 04:47:04 +03:00
odb_set_ops ( & opendb_tdb_ops ) ;
}