2004-09-20 11:28:43 +04:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - open and close
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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "include/includes.h"
# include "vfs_posix.h"
/*
find open file handle given fnum
*/
2004-09-29 17:17:09 +04:00
struct pvfs_file * pvfs_find_fd ( struct pvfs_state * pvfs ,
struct smbsrv_request * req , uint16_t fnum )
2004-09-20 11:28:43 +04:00
{
struct pvfs_file * f ;
for ( f = pvfs - > open_files ; f ; f = f - > next ) {
if ( f - > fnum = = fnum ) {
2004-09-26 15:30:20 +04:00
if ( req - > session ! = f - > session ) {
DEBUG ( 2 , ( " pvfs_find_fd: attempt to use wrong session for fnum %d \n " , fnum ) ) ;
return NULL ;
}
2004-09-20 11:28:43 +04:00
return f ;
}
}
return NULL ;
}
2004-09-25 08:45:52 +04:00
/*
by using a destructor we make sure that abnormal cleanup will not
leak file descriptors ( assuming at least the top level pointer is freed , which
will cascade down to here )
*/
static int pvfs_fd_destructor ( void * p )
{
struct pvfs_file * f = p ;
if ( f - > fd ! = - 1 ) {
close ( f - > fd ) ;
f - > fd = - 1 ;
}
return 0 ;
}
2004-09-20 11:28:43 +04:00
/*
open a file
TODO : this is a temporary implementation derived from the simple backend
its purpose is to allow other tests to run
*/
2004-09-29 17:17:09 +04:00
NTSTATUS pvfs_open ( struct ntvfs_module_context * ntvfs ,
struct smbsrv_request * req , union smb_open * io )
2004-09-20 11:28:43 +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
int fd , flags ;
struct pvfs_filename * name ;
struct pvfs_file * f ;
NTSTATUS status ;
if ( io - > generic . level ! = RAW_OPEN_GENERIC ) {
2004-09-29 17:17:09 +04:00
return ntvfs_map_open ( req , io , ntvfs ) ;
2004-09-20 11:28:43 +04:00
}
/* resolve the cifs name to a posix name */
status = pvfs_resolve_name ( pvfs , req , io - > ntcreatex . in . fname ,
PVFS_RESOLVE_NO_WILDCARD , & name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
switch ( io - > generic . in . open_disposition ) {
case NTCREATEX_DISP_SUPERSEDE :
case NTCREATEX_DISP_OVERWRITE_IF :
flags = O_CREAT | O_TRUNC ;
break ;
case NTCREATEX_DISP_OPEN :
case NTCREATEX_DISP_OVERWRITE :
flags = 0 ;
break ;
case NTCREATEX_DISP_CREATE :
flags = O_CREAT | O_EXCL ;
break ;
case NTCREATEX_DISP_OPEN_IF :
flags = O_CREAT ;
break ;
default :
flags = 0 ;
break ;
}
flags | = O_RDWR ;
2004-09-20 12:53:45 +04:00
/* we need to do this differently to support systems without O_DIRECTORY */
# ifndef O_DIRECTORY
# define O_DIRECTORY 0
# endif
2004-10-12 09:07:33 +04:00
if ( name - > exists & &
( io - > generic . in . create_options & NTCREATEX_OPTIONS_DIRECTORY ) & &
2004-10-11 18:35:54 +04:00
! ( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ) {
return NT_STATUS_NOT_A_DIRECTORY ;
}
2004-10-12 09:07:33 +04:00
if ( ( name - > exists & & name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) | |
( io - > generic . in . create_options & NTCREATEX_OPTIONS_DIRECTORY ) ) {
2004-09-20 11:28:43 +04:00
flags = O_RDONLY | O_DIRECTORY ;
if ( pvfs - > flags & PVFS_FLAG_READONLY ) {
goto do_open ;
}
switch ( io - > generic . in . open_disposition ) {
case NTCREATEX_DISP_CREATE :
if ( mkdir ( name - > full_name , 0755 ) = = - 1 ) {
return pvfs_map_errno ( pvfs , errno ) ;
}
break ;
case NTCREATEX_DISP_OPEN_IF :
if ( mkdir ( name - > full_name , 0755 ) = = - 1 & & errno ! = EEXIST ) {
return pvfs_map_errno ( pvfs , errno ) ;
}
break ;
}
}
do_open :
fd = open ( name - > full_name , flags , 0644 ) ;
if ( fd = = - 1 ) {
if ( errno = = 0 )
errno = ENOENT ;
return pvfs_map_errno ( pvfs , errno ) ;
}
f = talloc_p ( pvfs , struct pvfs_file ) ;
if ( f = = NULL ) {
close ( fd ) ;
return NT_STATUS_NO_MEMORY ;
}
/* re-resolve the open fd */
status = pvfs_resolve_name_fd ( pvfs , fd , name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
f - > fnum = fd ;
f - > fd = fd ;
f - > name = talloc_steal ( f , name ) ;
2004-09-26 15:30:20 +04:00
f - > session = req - > session ;
f - > smbpid = req - > smbpid ;
2004-09-20 11:28:43 +04:00
2004-09-25 08:45:52 +04:00
/* setup a destructor to avoid file descriptor leaks on
abnormal termination */
talloc_set_destructor ( f , pvfs_fd_destructor ) ;
2004-09-20 11:28:43 +04:00
DLIST_ADD ( pvfs - > open_files , f ) ;
ZERO_STRUCT ( io - > generic . out ) ;
io - > generic . out . create_time = name - > dos . create_time ;
io - > generic . out . access_time = name - > dos . access_time ;
io - > generic . out . write_time = name - > dos . write_time ;
io - > generic . out . change_time = name - > dos . change_time ;
io - > generic . out . fnum = f - > fnum ;
io - > generic . out . alloc_size = name - > dos . alloc_size ;
io - > generic . out . size = name - > st . st_size ;
io - > generic . out . attrib = name - > dos . attrib ;
io - > generic . out . is_directory = ( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ? 1 : 0 ;
return NT_STATUS_OK ;
}
/*
close a file
*/
2004-09-29 17:17:09 +04:00
NTSTATUS pvfs_close ( struct ntvfs_module_context * ntvfs ,
struct smbsrv_request * req , union smb_close * io )
2004-09-20 11:28:43 +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_file * f ;
2004-09-25 08:45:52 +04:00
NTSTATUS status ;
2004-09-20 11:28:43 +04:00
if ( io - > generic . level ! = RAW_CLOSE_CLOSE ) {
/* we need a mapping function */
return NT_STATUS_INVALID_LEVEL ;
}
2004-09-29 17:17:09 +04:00
f = pvfs_find_fd ( pvfs , req , io - > close . in . fnum ) ;
2004-09-20 11:28:43 +04:00
if ( ! f ) {
return NT_STATUS_INVALID_HANDLE ;
}
if ( close ( f - > fd ) ! = 0 ) {
2004-09-25 08:45:52 +04:00
status = pvfs_map_errno ( pvfs , errno ) ;
} else {
status = NT_STATUS_OK ;
2004-09-20 11:28:43 +04:00
}
2004-09-25 08:45:52 +04:00
talloc_set_destructor ( f , NULL ) ;
2004-09-20 11:28:43 +04:00
DLIST_REMOVE ( pvfs - > open_files , f ) ;
talloc_free ( f ) ;
2004-09-25 08:45:52 +04:00
return status ;
2004-09-20 11:28:43 +04:00
}
2004-09-26 15:30:20 +04:00
/*
logoff - close all file descriptors open by a vuid
*/
2004-09-29 17:17:09 +04:00
NTSTATUS pvfs_logoff ( struct ntvfs_module_context * ntvfs ,
struct smbsrv_request * req )
2004-09-26 15:30:20 +04:00
{
2004-09-29 17:17:09 +04:00
struct pvfs_state * pvfs = ntvfs - > private_data ;
2004-09-26 15:30:20 +04:00
struct pvfs_file * f , * next ;
for ( f = pvfs - > open_files ; f ; f = next ) {
next = f - > next ;
if ( f - > session = = req - > session ) {
talloc_set_destructor ( f , NULL ) ;
DLIST_REMOVE ( pvfs - > open_files , f ) ;
talloc_free ( f ) ;
}
}
return NT_STATUS_OK ;
}
/*
exit - close files for the current pid
*/
2004-09-29 17:17:09 +04:00
NTSTATUS pvfs_exit ( struct ntvfs_module_context * ntvfs ,
struct smbsrv_request * req )
2004-09-26 15:30:20 +04:00
{
2004-09-29 17:17:09 +04:00
struct pvfs_state * pvfs = ntvfs - > private_data ;
2004-09-26 15:30:20 +04:00
struct pvfs_file * f , * next ;
for ( f = pvfs - > open_files ; f ; f = next ) {
next = f - > next ;
if ( f - > smbpid = = req - > smbpid ) {
talloc_set_destructor ( f , NULL ) ;
DLIST_REMOVE ( pvfs - > open_files , f ) ;
talloc_free ( f ) ;
}
}
return NT_STATUS_OK ;
}