1998-08-15 11:27:34 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Files [ ] structure handling
Copyright ( C ) Andrew Tridgell 1998
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 "includes.h"
extern int DEBUGLEVEL ;
1998-08-16 08:08:47 +04:00
/* the only restriction is that this must be less than PIPE_HANDLE_OFFSET */
# define MAX_FNUMS 4096
1998-08-15 11:27:34 +04:00
# define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < MAX_FNUMS))
1998-08-17 07:06:20 +04:00
# define FILE_HANDLE_OFFSET 0x1000
1998-08-16 08:08:47 +04:00
static struct bitmap * file_bmap ;
static struct bitmap * fd_bmap ;
static files_struct * Files ;
1998-08-15 11:27:34 +04:00
/*
* Indirection for file fd ' s . Needed as POSIX locking
* is based on file / process , not fd / process .
*/
1998-08-16 08:08:47 +04:00
static file_fd_struct * FileFd ;
1998-08-15 11:27:34 +04:00
1998-08-16 08:08:47 +04:00
static int files_used , fd_ptr_used ;
1998-08-15 11:27:34 +04:00
/****************************************************************************
find first available file slot
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-16 06:32:55 +04:00
files_struct * file_new ( void )
1998-08-15 11:27:34 +04:00
{
int i ;
static int first_file ;
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
1998-08-15 11:27:34 +04:00
/* we want to give out file handles differently on each new
connection because of a common bug in MS clients where they try to
reuse a file descriptor from an earlier smb connection . This code
increases the chance that the errant client will get an error rather
than causing corruption */
if ( first_file = = 0 ) {
first_file = ( getpid ( ) ^ ( int ) time ( NULL ) ) % MAX_FNUMS ;
1998-08-16 08:08:47 +04:00
}
1998-08-15 11:27:34 +04:00
1998-08-16 08:08:47 +04:00
i = bitmap_find ( file_bmap , first_file ) ;
if ( i = = - 1 ) {
/*
* Before we give up , go through the open files
* and see if there are any files opened with a
* batch oplock . If so break the oplock and then
* re - use that entry ( if it becomes closed ) .
* This may help as NT / 95 clients tend to keep
* files batch oplocked for quite a long time
* after they have finished with them .
*/
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
if ( attempt_close_oplocked_file ( fsp ) ) {
return file_new ( ) ;
}
1998-08-15 11:27:34 +04:00
}
1998-08-16 08:08:47 +04:00
DEBUG ( 0 , ( " ERROR! Out of file structures \n " ) ) ;
return NULL ;
}
1998-08-15 11:27:34 +04:00
1998-08-16 08:08:47 +04:00
fsp = ( files_struct * ) malloc ( sizeof ( * fsp ) ) ;
if ( ! fsp ) return NULL ;
memset ( fsp , 0 , sizeof ( * fsp ) ) ;
1998-08-17 07:06:20 +04:00
first_file = ( i + 1 ) % MAX_FNUMS ;
1998-08-16 08:08:47 +04:00
bitmap_set ( file_bmap , i ) ;
files_used + + ;
1998-08-17 07:06:20 +04:00
fsp - > fnum = i + FILE_HANDLE_OFFSET ;
string_init ( & fsp - > fsp_name , " " ) ;
1998-08-16 08:08:47 +04:00
/* hook into the front of the list */
if ( ! Files ) {
Files = fsp ;
} else {
Files - > prev = fsp ;
fsp - > next = Files ;
Files = fsp ;
}
DEBUG ( 5 , ( " allocated file structure %d (%d used) \n " ,
i , files_used ) ) ;
return fsp ;
1998-08-15 11:27:34 +04:00
}
/****************************************************************************
fd support routines - attempt to find an already open file by dev
and inode - increments the ref_count of the returned file_fd_struct * .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
file_fd_struct * fd_get_already_open ( struct stat * sbuf )
{
1998-08-16 08:08:47 +04:00
file_fd_struct * fd_ptr ;
if ( ! sbuf ) return NULL ;
for ( fd_ptr = FileFd ; fd_ptr ; fd_ptr = fd_ptr - > next ) {
if ( ( fd_ptr - > ref_count > 0 ) & &
( ( ( uint32 ) sbuf - > st_dev ) = = fd_ptr - > dev ) & &
( ( ( uint32 ) sbuf - > st_ino ) = = fd_ptr - > inode ) ) {
fd_ptr - > ref_count + + ;
DEBUG ( 3 , ( " Re-used file_fd_struct dev = %x, inode = %x, ref_count = %d \n " ,
fd_ptr - > dev , fd_ptr - > inode ,
fd_ptr - > ref_count ) ) ;
return fd_ptr ;
}
}
return NULL ;
1998-08-15 11:27:34 +04:00
}
1998-08-16 08:08:47 +04:00
1998-08-15 11:27:34 +04:00
/****************************************************************************
fd support routines - attempt to find a empty slot in the FileFd array .
Increments the ref_count of the returned entry .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
file_fd_struct * fd_get_new ( void )
{
1998-08-16 08:08:47 +04:00
extern struct current_user current_user ;
int i ;
file_fd_struct * fd_ptr ;
i = bitmap_find ( fd_bmap , 1 ) ;
if ( i = = - 1 ) {
DEBUG ( 0 , ( " ERROR! Out of file_fd structures \n " ) ) ;
return NULL ;
}
fd_ptr = ( file_fd_struct * ) malloc ( sizeof ( * fd_ptr ) ) ;
if ( ! fd_ptr ) return NULL ;
memset ( fd_ptr , 0 , sizeof ( * fd_ptr ) ) ;
fd_ptr - > fdnum = i ;
fd_ptr - > dev = ( uint32 ) - 1 ;
fd_ptr - > inode = ( uint32 ) - 1 ;
fd_ptr - > fd = - 1 ;
fd_ptr - > fd_readonly = - 1 ;
fd_ptr - > fd_writeonly = - 1 ;
fd_ptr - > real_open_flags = - 1 ;
fd_add_to_uid_cache ( fd_ptr , ( uid_t ) current_user . uid ) ;
fd_ptr - > ref_count + + ;
bitmap_set ( fd_bmap , i ) ;
fd_ptr_used + + ;
/* hook into the front of the list */
if ( ! FileFd ) {
FileFd = fd_ptr ;
} else {
FileFd - > prev = fd_ptr ;
fd_ptr - > next = FileFd ;
FileFd = fd_ptr ;
}
DEBUG ( 5 , ( " allocated fd_ptr structure %d (%d used) \n " ,
i , fd_ptr_used ) ) ;
return fd_ptr ;
1998-08-15 11:27:34 +04:00
}
/****************************************************************************
close all open files for a connection
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void file_close_conn ( connection_struct * conn )
{
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
if ( fsp - > conn = = conn & & fsp - > open ) {
if ( fsp - > is_directory )
close_directory ( fsp ) ;
else
close_file ( fsp , False ) ;
}
}
1998-08-15 11:27:34 +04:00
}
/****************************************************************************
initialise file structures
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void file_init ( void )
{
1998-08-16 08:08:47 +04:00
file_bmap = bitmap_allocate ( MAX_FNUMS ) ;
fd_bmap = bitmap_allocate ( MAX_FNUMS ) ;
if ( ! file_bmap | | ! fd_bmap ) {
exit_server ( " out of memory in file_init " ) ;
}
1998-08-15 11:27:34 +04:00
1998-08-16 08:08:47 +04:00
# if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
1998-08-15 11:27:34 +04:00
{
struct rlimit rlp ;
getrlimit ( RLIMIT_NOFILE , & rlp ) ;
1998-08-16 10:20:18 +04:00
/* Set the fd limit to be MAX_FNUMS + 10 to
* account for the extra fd we need
* as well as the log files and standard
1998-08-15 11:27:34 +04:00
* handles etc . */
rlp . rlim_cur = ( MAX_FNUMS + 10 > rlp . rlim_max ) ?
rlp . rlim_max : MAX_FNUMS + 10 ;
setrlimit ( RLIMIT_NOFILE , & rlp ) ;
getrlimit ( RLIMIT_NOFILE , & rlp ) ;
DEBUG ( 3 , ( " Maximum number of open files per session is %d \n " ,
( int ) rlp . rlim_cur ) ) ;
}
# endif
}
1998-08-16 08:08:47 +04:00
1998-08-15 11:27:34 +04:00
/****************************************************************************
find a fsp given a fnum
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
files_struct * file_fsp ( int fnum )
{
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
if ( fsp - > fnum = = fnum ) return fsp ;
}
return NULL ;
1998-08-15 11:27:34 +04:00
}
/****************************************************************************
close files open by a specified vuid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void file_close_user ( int vuid )
{
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
1998-08-15 11:27:34 +04:00
if ( ( fsp - > vuid = = vuid ) & & fsp - > open ) {
if ( ! fsp - > is_directory )
close_file ( fsp , False ) ;
else
close_directory ( fsp ) ;
}
}
}
/****************************************************************************
find a fsp given a device , inode and timevalue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
files_struct * file_find_dit ( int dev , int inode , struct timeval * tval )
{
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
1998-08-15 11:27:34 +04:00
if ( fsp - > open & &
fsp - > fd_ptr - > dev = = dev & &
fsp - > fd_ptr - > inode = = inode & &
fsp - > open_time . tv_sec = = tval - > tv_sec & &
fsp - > open_time . tv_usec = = tval - > tv_usec ) {
return fsp ;
}
1998-08-16 08:08:47 +04:00
}
1998-08-15 11:27:34 +04:00
return NULL ;
}
1998-08-16 08:08:47 +04:00
1998-08-15 11:27:34 +04:00
/****************************************************************************
find a fsp that is open for printing
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
files_struct * file_find_print ( void )
{
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
1998-08-15 11:27:34 +04:00
1998-08-16 08:08:47 +04:00
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
if ( fsp - > open & & fsp - > print_file ) return fsp ;
1998-08-15 11:27:34 +04:00
}
return NULL ;
}
/****************************************************************************
sync open files on a connection
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void file_sync_all ( connection_struct * conn )
{
1998-08-16 08:08:47 +04:00
files_struct * fsp ;
for ( fsp = Files ; fsp ; fsp = fsp - > next ) {
1998-08-15 11:27:34 +04:00
if ( fsp - > open & & conn = = fsp - > conn ) {
sync_file ( conn , fsp ) ;
}
}
}
1998-08-16 08:08:47 +04:00
/****************************************************************************
free up a fd_ptr
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fd_ptr_free ( file_fd_struct * fd_ptr )
{
if ( fd_ptr = = FileFd ) {
FileFd = fd_ptr - > next ;
if ( FileFd ) FileFd - > prev = NULL ;
} else {
fd_ptr - > prev - > next = fd_ptr - > next ;
if ( fd_ptr - > next ) fd_ptr - > next - > prev = fd_ptr - > prev ;
}
bitmap_clear ( fd_bmap , fd_ptr - > fdnum ) ;
fd_ptr_used - - ;
DEBUG ( 5 , ( " freed fd_ptr structure %d (%d used) \n " ,
fd_ptr - > fdnum , fd_ptr_used ) ) ;
/* paranoia */
memset ( fd_ptr , 0 , sizeof ( * fd_ptr ) ) ;
free ( fd_ptr ) ;
}
/****************************************************************************
free up a fsp
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-15 11:27:34 +04:00
void file_free ( files_struct * fsp )
{
1998-08-16 08:08:47 +04:00
if ( fsp = = Files ) {
Files = fsp - > next ;
if ( Files ) Files - > prev = NULL ;
} else {
fsp - > prev - > next = fsp - > next ;
if ( fsp - > next ) fsp - > next - > prev = fsp - > prev ;
}
string_free ( & fsp - > fsp_name ) ;
if ( fsp - > fd_ptr & & fsp - > fd_ptr - > ref_count = = 0 ) {
fd_ptr_free ( fsp - > fd_ptr ) ;
}
1998-08-17 07:06:20 +04:00
bitmap_clear ( file_bmap , fsp - > fnum - FILE_HANDLE_OFFSET ) ;
1998-08-16 08:08:47 +04:00
files_used - - ;
DEBUG ( 5 , ( " freed files structure %d (%d used) \n " ,
fsp - > fnum , files_used ) ) ;
/* this is paranoia, just in case someone tries to reuse the
information */
1998-08-15 11:27:34 +04:00
memset ( fsp , 0 , sizeof ( * fsp ) ) ;
1998-08-16 08:08:47 +04:00
free ( fsp ) ;
1998-08-15 11:27:34 +04:00
}