1998-08-17 11:15:54 +04:00
/*
2002-07-15 14:35:28 +04:00
Unix SMB / Netbios implementation .
Version 1.9 .
1998-08-17 11:15:54 +04:00
read / write to a files_struct
Copyright ( C ) Andrew Tridgell 1992 - 1998
2002-07-15 14:35:28 +04:00
Copyright ( C ) Jeremy Allison 2000 - 2002. - write cache .
1998-08-17 11:15:54 +04: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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-08-17 11:15:54 +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 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 11:15:54 +04:00
*/
# include "includes.h"
2010-05-04 12:28:48 +04:00
# include "printing.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
1998-08-17 11:15:54 +04:00
2007-10-19 04:40:25 +04:00
static bool setup_write_cache ( files_struct * , SMB_OFF_T ) ;
1998-08-17 11:15:54 +04:00
1999-12-13 16:27:58 +03:00
/****************************************************************************
Read from write cache if we can .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool read_from_write_cache ( files_struct * fsp , char * data , SMB_OFF_T pos , size_t n )
1999-12-13 16:27:58 +03:00
{
2002-07-15 14:35:28 +04:00
write_cache * wcp = fsp - > wcp ;
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( ! wcp ) {
2002-07-15 14:35:28 +04:00
return False ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( n > wcp - > data_size | | pos < wcp - > offset | | pos + n > wcp - > offset + wcp - > data_size ) {
2002-07-15 14:35:28 +04:00
return False ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
memcpy ( data , wcp - > data + ( pos - wcp - > offset ) , n ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_read_hits ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
return True ;
1999-12-13 16:27:58 +03:00
}
1998-08-17 11:15:54 +04:00
/****************************************************************************
2002-07-15 14:35:28 +04:00
Read from a file .
1998-08-17 11:15:54 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-11 05:24:30 +04:00
ssize_t read_file ( files_struct * fsp , char * data , SMB_OFF_T pos , size_t n )
1998-08-17 11:15:54 +04:00
{
2001-11-25 11:26:37 +03:00
ssize_t ret = 0 , readret ;
1998-08-17 11:15:54 +04:00
2001-11-25 11:26:37 +03:00
/* you can't read from print files */
2005-05-09 03:16:28 +04:00
if ( fsp - > print_file ) {
2009-07-11 05:23:00 +04:00
errno = EBADF ;
2001-11-25 11:26:37 +03:00
return - 1 ;
2005-05-09 03:16:28 +04:00
}
2000-04-16 10:22:31 +04:00
2001-11-25 11:26:37 +03:00
/*
* Serve from write cache if we can .
*/
1999-12-13 16:27:58 +03:00
2003-08-15 01:16:06 +04:00
if ( read_from_write_cache ( fsp , data , pos , n ) ) {
2005-07-08 08:51:27 +04:00
fsp - > fh - > pos = pos + n ;
fsp - > fh - > position_information = fsp - > fh - > pos ;
2001-11-25 11:26:37 +03:00
return n ;
2003-08-15 01:16:06 +04:00
}
1998-08-17 11:15:54 +04:00
2001-11-25 11:26:37 +03:00
flush_write_cache ( fsp , READ_FLUSH ) ;
1998-08-17 11:15:54 +04:00
2005-07-08 08:51:27 +04:00
fsp - > fh - > pos = pos ;
2004-01-06 04:22:14 +03:00
2001-11-25 11:26:37 +03:00
if ( n > 0 ) {
# ifdef DMF_FIX
int numretries = 3 ;
tryagain :
2008-01-07 02:14:19 +03:00
readret = SMB_VFS_PREAD ( fsp , data , n , pos ) ;
2004-01-06 04:22:14 +03:00
2001-11-25 11:26:37 +03:00
if ( readret = = - 1 ) {
if ( ( errno = = EAGAIN ) & & numretries ) {
DEBUG ( 3 , ( " read_file EAGAIN retry in 10 seconds \n " ) ) ;
( void ) sleep ( 10 ) ;
- - numretries ;
goto tryagain ;
}
return - 1 ;
}
# else /* NO DMF fix. */
2008-01-07 02:14:19 +03:00
readret = SMB_VFS_PREAD ( fsp , data , n , pos ) ;
2004-01-06 04:22:14 +03:00
2005-05-09 03:16:28 +04:00
if ( readret = = - 1 ) {
2001-11-25 11:26:37 +03:00
return - 1 ;
2005-05-09 03:16:28 +04:00
}
2001-11-25 11:26:37 +03:00
# endif
2005-05-09 03:16:28 +04:00
if ( readret > 0 ) {
2001-11-25 11:26:37 +03:00
ret + = readret ;
2005-05-09 03:16:28 +04:00
}
2001-11-25 11:26:37 +03:00
}
2002-07-15 14:35:28 +04:00
DEBUG ( 10 , ( " read_file (%s): pos = %.0f, size = %lu, returned %lu \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( double ) pos , ( unsigned long ) n , ( long ) ret ) ) ;
2002-07-15 14:35:28 +04:00
2005-07-08 08:51:27 +04:00
fsp - > fh - > pos + = ret ;
fsp - > fh - > position_information = fsp - > fh - > pos ;
2003-08-15 01:16:06 +04:00
2001-11-25 11:26:37 +03:00
return ( ret ) ;
1998-08-17 11:15:54 +04:00
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
2000-08-26 00:44:33 +04:00
* Really * write to a file .
1999-12-13 16:27:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-31 02:22:24 +03:00
static ssize_t real_write_file ( struct smb_request * req ,
files_struct * fsp ,
const char * data ,
SMB_OFF_T pos ,
size_t n )
1999-12-13 16:27:58 +03:00
{
2002-07-15 14:35:28 +04:00
ssize_t ret ;
2005-05-09 03:16:28 +04:00
if ( pos = = - 1 ) {
2007-10-31 02:22:24 +03:00
ret = vfs_write_data ( req , fsp , data , n ) ;
2005-05-09 03:16:28 +04:00
} else {
2005-07-08 08:51:27 +04:00
fsp - > fh - > pos = pos ;
2010-12-21 04:58:33 +03:00
if ( pos & & lp_strict_allocate ( SNUM ( fsp - > conn ) & &
! fsp - > is_sparse ) ) {
2005-05-17 05:04:51 +04:00
if ( vfs_fill_sparse ( fsp , pos ) = = - 1 ) {
return - 1 ;
}
}
2007-10-31 02:22:24 +03:00
ret = vfs_pwrite_data ( req , fsp , data , n , pos ) ;
2004-01-06 04:22:14 +03:00
}
2002-07-15 14:35:28 +04:00
DEBUG ( 10 , ( " real_write_file (%s): pos = %.0f, size = %lu, returned %ld \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( double ) pos , ( unsigned long ) n , ( long ) ret ) ) ;
1999-12-13 16:27:58 +03:00
2003-08-15 01:16:06 +04:00
if ( ret ! = - 1 ) {
2005-07-08 08:51:27 +04:00
fsp - > fh - > pos + = ret ;
2003-08-15 01:16:06 +04:00
/* Yes - this is correct - writes don't update this. JRA. */
/* Found by Samba4 tests. */
#if 0
fsp - > position_information = fsp - > pos ;
# endif
}
2002-07-15 14:35:28 +04:00
return ret ;
1999-12-13 16:27:58 +03:00
}
1998-08-17 11:15:54 +04:00
/****************************************************************************
2005-05-09 03:16:28 +04:00
File size cache change .
Updates size on disk but doesn ' t flush the cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int wcp_file_size_change ( files_struct * fsp )
{
int ret ;
write_cache * wcp = fsp - > wcp ;
wcp - > file_size = wcp - > offset + wcp - > data_size ;
2008-01-07 17:55:09 +03:00
ret = SMB_VFS_FTRUNCATE ( fsp , wcp - > file_size ) ;
2005-05-09 03:16:28 +04:00
if ( ret = = - 1 ) {
2009-07-11 01:50:37 +04:00
DEBUG ( 0 , ( " wcp_file_size_change (%s): ftruncate of size %.0f "
" error %s \n " , fsp_str_dbg ( fsp ) ,
( double ) wcp - > file_size , strerror ( errno ) ) ) ;
2005-05-09 03:16:28 +04:00
}
return ret ;
}
2009-11-06 09:58:12 +03:00
void update_write_time_handler ( struct event_context * ctx ,
2008-03-12 17:39:38 +03:00
struct timed_event * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2008-03-12 17:39:38 +03:00
void * private_data )
{
2008-09-06 06:00:48 +04:00
files_struct * fsp = ( files_struct * ) private_data ;
2008-03-12 17:39:38 +03:00
2009-07-11 01:50:37 +04:00
DEBUG ( 5 , ( " Update write time on %s \n " , fsp_str_dbg ( fsp ) ) ) ;
2008-03-12 17:39:38 +03:00
2009-11-06 03:20:11 +03:00
/* change the write time in the open file db. */
( void ) set_write_time ( fsp - > file_id , timespec_current ( ) ) ;
/* And notify. */
notify_fname ( fsp - > conn , NOTIFY_ACTION_MODIFIED ,
FILE_NOTIFY_CHANGE_LAST_WRITE , fsp - > fsp_name - > base_name ) ;
2009-11-06 09:58:12 +03:00
/* Remove the timed event handler. */
TALLOC_FREE ( fsp - > update_write_time_event ) ;
2008-03-12 17:39:38 +03:00
}
2008-09-06 06:00:48 +04:00
/*********************************************************
Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
in the future .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-03-12 17:39:38 +03:00
void trigger_write_time_update ( struct files_struct * fsp )
{
2008-04-07 11:27:22 +04:00
int delay ;
2009-07-02 04:39:10 +04:00
if ( fsp - > posix_open ) {
/* Don't use delayed writes on POSIX files. */
return ;
}
2008-03-12 17:39:38 +03:00
if ( fsp - > write_time_forced ) {
2008-09-06 06:00:48 +04:00
/* No point - "sticky" write times
* in effect .
*/
2008-03-12 17:39:38 +03:00
return ;
}
2009-11-06 03:20:11 +03:00
/* We need to remember someone did a write
* and update to current time on close . */
fsp - > update_write_time_on_close = true ;
2008-09-08 17:12:24 +04:00
if ( fsp - > update_write_time_triggered ) {
2008-09-06 06:00:48 +04:00
/*
2009-11-06 03:20:11 +03:00
* We only update the write time after 2 seconds
* on the first normal write . After that
* no other writes affect this until close .
2008-09-06 06:00:48 +04:00
*/
2008-03-12 17:39:38 +03:00
return ;
}
2008-09-08 17:12:24 +04:00
fsp - > update_write_time_triggered = true ;
2008-03-12 17:39:38 +03:00
2008-04-07 11:27:22 +04:00
delay = lp_parm_int ( SNUM ( fsp - > conn ) ,
" smbd " , " writetimeupdatedelay " ,
WRITE_TIME_UPDATE_USEC_DELAY ) ;
2009-11-06 03:20:11 +03:00
DEBUG ( 5 , ( " Update write time %d usec later on %s \n " ,
delay , fsp_str_dbg ( fsp ) ) ) ;
2008-03-12 17:39:38 +03:00
/* trigger the update 2 seconds later */
fsp - > update_write_time_event =
event_add_timed ( smbd_event_context ( ) , NULL ,
2008-04-07 11:27:22 +04:00
timeval_current_ofs ( 0 , delay ) ,
2008-03-12 17:39:38 +03:00
update_write_time_handler , fsp ) ;
}
2008-09-06 06:00:48 +04:00
void trigger_write_time_update_immediate ( struct files_struct * fsp )
{
2009-11-06 03:20:11 +03:00
struct smb_file_time ft ;
2009-07-02 04:39:10 +04:00
if ( fsp - > posix_open ) {
/* Don't use delayed writes on POSIX files. */
return ;
}
2008-09-06 06:00:48 +04:00
if ( fsp - > write_time_forced ) {
/*
* No point - " sticky " write times
* in effect .
*/
return ;
}
2008-09-08 17:12:24 +04:00
TALLOC_FREE ( fsp - > update_write_time_event ) ;
2009-07-11 01:50:37 +04:00
DEBUG ( 5 , ( " Update write time immediate on %s \n " ,
fsp_str_dbg ( fsp ) ) ) ;
2008-09-08 17:12:24 +04:00
2009-11-06 03:20:11 +03:00
/* After an immediate update, reset the trigger. */
2008-09-08 17:12:24 +04:00
fsp - > update_write_time_triggered = true ;
fsp - > update_write_time_on_close = false ;
2009-11-06 03:20:11 +03:00
ZERO_STRUCT ( ft ) ;
ft . mtime = timespec_current ( ) ;
/* Update the time in the open file db. */
( void ) set_write_time ( fsp - > file_id , ft . mtime ) ;
/* Now set on disk - takes care of notify. */
( void ) smb_set_file_time ( fsp - > conn , fsp , fsp - > fsp_name , & ft , false ) ;
2008-09-06 06:00:48 +04:00
}
2005-05-09 03:16:28 +04:00
/****************************************************************************
Write to a file .
1998-08-17 11:15:54 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-11 05:24:30 +04:00
2007-10-31 02:22:24 +03:00
ssize_t write_file ( struct smb_request * req ,
files_struct * fsp ,
const char * data ,
SMB_OFF_T pos ,
size_t n )
1998-08-17 11:15:54 +04:00
{
2002-07-15 14:35:28 +04:00
write_cache * wcp = fsp - > wcp ;
ssize_t total_written = 0 ;
2007-10-31 02:22:24 +03:00
int write_path = - 1 ;
2002-07-15 14:35:28 +04:00
2002-12-05 07:00:16 +03:00
if ( fsp - > print_file ) {
2010-05-04 12:28:48 +04:00
uint32_t t ;
int ret ;
2002-12-05 07:00:16 +03:00
2010-05-04 12:28:48 +04:00
ret = print_spool_write ( fsp , data , n , pos , & t ) ;
if ( ret ) {
errno = ret ;
2002-12-05 07:00:16 +03:00
return - 1 ;
}
2010-05-04 12:28:48 +04:00
return t ;
2002-12-05 07:00:16 +03:00
}
2002-07-15 14:35:28 +04:00
if ( ! fsp - > can_write ) {
errno = EPERM ;
2006-07-25 04:16:45 +04:00
return - 1 ;
2002-07-15 14:35:28 +04:00
}
if ( ! fsp - > modified ) {
fsp - > modified = True ;
2009-07-11 01:50:37 +04:00
if ( SMB_VFS_FSTAT ( fsp , & fsp - > fsp_name - > st ) = = 0 ) {
2008-03-12 17:39:38 +03:00
trigger_write_time_update ( fsp ) ;
2010-09-22 23:26:13 +04:00
if ( ! fsp - > posix_open & &
( lp_store_dos_attributes ( SNUM ( fsp - > conn ) ) | |
MAP_ARCHIVE ( fsp - > conn ) ) ) {
int dosmode = dos_mode ( fsp - > conn , fsp - > fsp_name ) ;
if ( ! IS_DOS_ARCHIVE ( dosmode ) ) {
file_set_dosmode ( fsp - > conn , fsp - > fsp_name ,
2009-07-11 01:50:37 +04:00
dosmode | aARCH , NULL , false ) ;
2010-09-22 23:26:13 +04:00
}
2004-04-02 22:46:19 +04:00
}
2002-07-15 14:35:28 +04:00
/*
* If this is the first write and we have an exclusive oplock then setup
* the write cache .
*/
if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) & & ! wcp ) {
2009-07-08 23:24:03 +04:00
setup_write_cache ( fsp ,
2009-07-11 01:50:37 +04:00
fsp - > fsp_name - > st . st_ex_size ) ;
2002-07-15 14:35:28 +04:00
wcp = fsp - > wcp ;
2007-10-31 02:22:24 +03:00
}
}
2002-07-15 14:35:28 +04:00
}
1998-08-17 11:15:54 +04:00
2000-10-05 22:50:18 +04:00
# ifdef WITH_PROFILE
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_total_writes ) ;
if ( ! fsp - > oplock_type ) {
DO_PROFILE_INC ( writecache_non_oplock_writes ) ;
}
2000-10-05 22:50:18 +04:00
# endif
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* If this file is level II oplocked then we need
* to grab the shared memory lock and inform all
* other files with a level II lock that they need
* to flush their read caches . We keep the lock over
* the shared memory area whilst doing this .
*/
1999-12-13 16:27:58 +03:00
2009-02-03 22:56:35 +03:00
/* This should actually be improved to span the write. */
contend_level2_oplocks_begin ( fsp , LEVEL2_CONTEND_WRITE ) ;
contend_level2_oplocks_end ( fsp , LEVEL2_CONTEND_WRITE ) ;
1999-12-13 16:27:58 +03:00
2000-10-05 22:50:18 +04:00
# ifdef WITH_PROFILE
2002-07-15 14:35:28 +04:00
if ( profile_p & & profile_p - > writecache_total_writes % 500 = = 0 ) {
DEBUG ( 3 , ( " WRITECACHE: initwrites=%u abutted=%u total=%u \
1999-12-13 16:27:58 +03:00
nonop = % u allocated = % u active = % u direct = % u perfect = % u readhits = % u \ n " ,
2002-07-15 14:35:28 +04:00
profile_p - > writecache_init_writes ,
profile_p - > writecache_abutted_writes ,
profile_p - > writecache_total_writes ,
profile_p - > writecache_non_oplock_writes ,
profile_p - > writecache_allocated_write_caches ,
profile_p - > writecache_num_write_caches ,
profile_p - > writecache_direct_writes ,
profile_p - > writecache_num_perfect_writes ,
profile_p - > writecache_read_hits ) ) ;
DEBUG ( 3 , ( " WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d \n " ,
profile_p - > writecache_flushed_writes [ SEEK_FLUSH ] ,
profile_p - > writecache_flushed_writes [ READ_FLUSH ] ,
profile_p - > writecache_flushed_writes [ WRITE_FLUSH ] ,
profile_p - > writecache_flushed_writes [ READRAW_FLUSH ] ,
profile_p - > writecache_flushed_writes [ OPLOCK_RELEASE_FLUSH ] ,
profile_p - > writecache_flushed_writes [ CLOSE_FLUSH ] ,
profile_p - > writecache_flushed_writes [ SYNC_FLUSH ] ) ) ;
}
2000-10-05 22:50:18 +04:00
# endif
1999-12-13 16:27:58 +03:00
2007-10-31 02:22:24 +03:00
if ( wcp & & req - > unread_bytes ) {
/* If we're using receivefile don't
* deal with a write cache .
*/
flush_write_cache ( fsp , WRITE_FLUSH ) ;
delete_write_cache ( fsp ) ;
wcp = NULL ;
}
2002-07-15 14:35:28 +04:00
if ( ! wcp ) {
DO_PROFILE_INC ( writecache_direct_writes ) ;
2007-10-31 02:22:24 +03:00
total_written = real_write_file ( req , fsp , data , pos , n ) ;
2002-07-15 14:35:28 +04:00
return total_written ;
}
1999-12-13 16:27:58 +03:00
2009-07-11 01:50:37 +04:00
DEBUG ( 9 , ( " write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f "
" wcp->data_size=%u \n " , fsp_str_dbg ( fsp ) , fsp - > fh - > fd ,
( double ) pos , ( unsigned int ) n , ( double ) wcp - > offset ,
( unsigned int ) wcp - > data_size ) ) ;
1999-12-13 16:27:58 +03:00
2005-07-08 08:51:27 +04:00
fsp - > fh - > pos = pos + n ;
2003-08-15 01:16:06 +04:00
2010-07-29 16:48:06 +04:00
if ( ( n = = 1 ) & & ( data [ 0 ] = = ' \0 ' ) & & ( pos > wcp - > file_size ) ) {
int ret ;
/*
* This is a 1 - byte write of a 0 beyond the EOF and
* thus implicitly also beyond the current active
* write cache , the typical file - extending ( and
* allocating , but we ' re using the write cache here )
* write done by Windows . We just have to ftruncate
* the file and rely on posix semantics to return
* zeros for non - written file data that is within the
* file length .
*
* We can not use wcp_file_size_change here because we
* might have an existing write cache , and
* wcp_file_size_change assumes a change to just the
* end of the current write cache .
*/
wcp - > file_size = pos + 1 ;
ret = SMB_VFS_FTRUNCATE ( fsp , wcp - > file_size ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " wcp_file_size_change (%s): ftruncate of size %.0f "
" error %s \n " , fsp_str_dbg ( fsp ) ,
( double ) wcp - > file_size , strerror ( errno ) ) ) ;
return - 1 ;
}
return 1 ;
}
2007-10-31 02:22:24 +03:00
/*
2002-07-15 14:35:28 +04:00
* If we have active cache and it isn ' t contiguous then we flush .
* NOTE : There is a small problem with running out of disk . . . .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
if ( wcp - > data_size ) {
2007-10-19 04:40:25 +04:00
bool cache_flush_needed = False ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
if ( ( pos > = wcp - > offset ) & & ( pos < = wcp - > offset + wcp - > data_size ) ) {
1999-12-13 16:27:58 +03:00
2002-10-03 23:05:36 +04:00
/* ASCII art.... JRA.
+ - - - - - - - - - - - - - - + - - - - -
| Cached data | Rest of allocated cache buffer . . . .
+ - - - - - - - - - - - - - - + - - - - -
+ - - - - - - - - - - - - - - - - - - - +
| Data to write |
+ - - - - - - - - - - - - - - - - - - - +
*/
2002-07-15 14:35:28 +04:00
/*
* Start of write overlaps or abutts the existing data .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
size_t data_used = MIN ( ( wcp - > alloc_size - ( pos - wcp - > offset ) ) , n ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
memcpy ( wcp - > data + ( pos - wcp - > offset ) , data , data_used ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Update the current buffer size with the new data .
*/
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( pos + data_used > wcp - > offset + wcp - > data_size ) {
2002-07-15 14:35:28 +04:00
wcp - > data_size = pos + data_used - wcp - > offset ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Update the file size if changed .
*/
2002-01-20 03:43:28 +03:00
2002-12-04 06:12:09 +03:00
if ( wcp - > offset + wcp - > data_size > wcp - > file_size ) {
2005-05-09 03:16:28 +04:00
if ( wcp_file_size_change ( fsp ) = = - 1 ) {
return - 1 ;
}
2002-12-04 06:12:09 +03:00
}
2002-01-20 03:43:28 +03:00
2002-07-15 14:35:28 +04:00
/*
* If we used all the data then
* return here .
*/
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( n = = data_used ) {
2002-07-15 14:35:28 +04:00
return n ;
2005-05-09 03:16:28 +04:00
} else {
2002-07-15 14:35:28 +04:00
cache_flush_needed = True ;
2005-05-09 03:16:28 +04:00
}
2002-07-15 14:35:28 +04:00
/*
* Move the start of data forward by the amount used ,
* cut down the amount left by the same amount .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
data + = data_used ;
pos + = data_used ;
n - = data_used ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_abutted_writes ) ;
total_written = data_used ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
write_path = 1 ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
} else if ( ( pos < wcp - > offset ) & & ( pos + n > wcp - > offset ) & &
( pos + n < = wcp - > offset + wcp - > alloc_size ) ) {
1999-12-13 16:27:58 +03:00
2002-10-03 23:05:36 +04:00
/* ASCII art.... JRA.
+ - - - - - - - - - - - - - - - +
| Cache buffer |
+ - - - - - - - - - - - - - - - +
+ - - - - - - - - - - - - - - - - - - - +
| Data to write |
+ - - - - - - - - - - - - - - - - - - - +
*/
2002-07-15 14:35:28 +04:00
/*
* End of write overlaps the existing data .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
size_t data_used = pos + n - wcp - > offset ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
memcpy ( wcp - > data , data + n - data_used , data_used ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Update the current buffer size with the new data .
*/
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( pos + n > wcp - > offset + wcp - > data_size ) {
2002-07-15 14:35:28 +04:00
wcp - > data_size = pos + n - wcp - > offset ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Update the file size if changed .
*/
2002-01-20 03:43:28 +03:00
2002-12-04 06:12:09 +03:00
if ( wcp - > offset + wcp - > data_size > wcp - > file_size ) {
2005-05-09 03:16:28 +04:00
if ( wcp_file_size_change ( fsp ) = = - 1 ) {
return - 1 ;
}
2002-12-04 06:12:09 +03:00
}
2002-01-20 03:43:28 +03:00
2002-07-15 14:35:28 +04:00
/*
* We don ' t need to move the start of data , but we
* cut down the amount left by the amount used .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
n - = data_used ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* We cannot have used all the data here .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
cache_flush_needed = True ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_abutted_writes ) ;
total_written = data_used ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
write_path = 2 ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
} else if ( ( pos > = wcp - > file_size ) & &
( wcp - > offset + wcp - > data_size = = wcp - > file_size ) & &
( pos > wcp - > offset + wcp - > data_size ) & &
( pos < wcp - > offset + wcp - > alloc_size ) ) {
1999-12-13 16:27:58 +03:00
2002-10-03 23:05:36 +04:00
/* ASCII art.... JRA.
End of file - - - - > |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| Cached data | Cache buffer |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
+ - - - - - - - - - - - - - - - - - - - +
| Data to write |
+ - - - - - - - - - - - - - - - - - - - +
*/
2002-07-15 14:35:28 +04:00
/*
* Non - contiguous write part of which fits within
* the cache buffer and is extending the file
* and the cache contents reflect the current
* data up to the current end of the file .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
size_t data_used ;
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( pos + n < = wcp - > offset + wcp - > alloc_size ) {
2002-07-15 14:35:28 +04:00
data_used = n ;
2005-05-09 03:16:28 +04:00
} else {
2002-07-15 14:35:28 +04:00
data_used = wcp - > offset + wcp - > alloc_size - pos ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Fill in the non - continuous area with zeros .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
memset ( wcp - > data + wcp - > data_size , ' \0 ' ,
pos - ( wcp - > offset + wcp - > data_size ) ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
memcpy ( wcp - > data + ( pos - wcp - > offset ) , data , data_used ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Update the current buffer size with the new data .
*/
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( pos + data_used > wcp - > offset + wcp - > data_size ) {
2002-07-15 14:35:28 +04:00
wcp - > data_size = pos + data_used - wcp - > offset ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Update the file size if changed .
*/
1999-12-13 16:27:58 +03:00
2002-12-04 06:12:09 +03:00
if ( wcp - > offset + wcp - > data_size > wcp - > file_size ) {
2005-05-09 03:16:28 +04:00
if ( wcp_file_size_change ( fsp ) = = - 1 ) {
return - 1 ;
}
2002-12-04 06:12:09 +03:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* If we used all the data then
* return here .
*/
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( n = = data_used ) {
2002-07-15 14:35:28 +04:00
return n ;
2005-05-09 03:16:28 +04:00
} else {
2002-07-15 14:35:28 +04:00
cache_flush_needed = True ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* Move the start of data forward by the amount used ,
* cut down the amount left by the same amount .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
data + = data_used ;
pos + = data_used ;
n - = data_used ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_abutted_writes ) ;
total_written = data_used ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
write_path = 3 ;
1999-12-13 16:27:58 +03:00
2007-08-03 20:51:43 +04:00
} else if ( ( pos > = wcp - > file_size ) & &
2005-05-24 08:55:18 +04:00
( n = = 1 ) & &
2007-08-03 20:51:43 +04:00
( wcp - > file_size = = wcp - > offset + wcp - > data_size ) & &
( pos < wcp - > file_size + wcp - > alloc_size ) ) {
2005-05-24 08:55:18 +04:00
/*
2007-08-03 20:51:43 +04:00
End of file - - - - > |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| Cached data | Cache buffer |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| < - - - - - - - allocated size - - - - - - - - - - - - - - - - > |
2005-05-24 08:55:18 +04:00
+ - - - - - - - - +
| 1 Byte |
+ - - - - - - - - +
MS - Office seems to do this a lot to determine if there ' s enough
space on the filesystem to write a new file .
2007-08-03 20:51:43 +04:00
Change to :
End of file - - - - > |
+ - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - +
| Zeroed Cached data | 1 Byte |
+ - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - +
*/
2005-05-24 08:55:18 +04:00
flush_write_cache ( fsp , WRITE_FLUSH ) ;
2010-07-29 16:21:14 +04:00
wcp - > offset = wcp - > file_size ;
wcp - > data_size = pos - wcp - > file_size + 1 ;
memset ( wcp - > data , ' \0 ' , wcp - > data_size ) ;
memcpy ( wcp - > data + wcp - > data_size - 1 , data , 1 ) ;
2005-05-24 08:55:18 +04:00
/*
* Update the file size if changed .
*/
if ( wcp - > offset + wcp - > data_size > wcp - > file_size ) {
if ( wcp_file_size_change ( fsp ) = = - 1 ) {
return - 1 ;
}
}
return n ;
2002-07-15 14:35:28 +04:00
} else {
1999-12-13 16:27:58 +03:00
2002-10-03 23:05:36 +04:00
/* ASCII art..... JRA.
Case 1 ) .
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| Cached data | Cache buffer |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
+ - - - - - - - - - - - - - - - - - - - +
| Data to write |
+ - - - - - - - - - - - - - - - - - - - +
Case 2 ) .
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| Cached data | Cache buffer |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
+ - - - - - - - - - - - - - - - - - - - +
| Data to write |
+ - - - - - - - - - - - - - - - - - - - +
Case 3 ) .
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| Cached data | Cache buffer |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Data to write |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
/*
2002-07-15 14:35:28 +04:00
* Write is bigger than buffer , or there is no overlap on the
* low or high ends .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 9 , ( " write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
2005-07-08 08:51:27 +04:00
len = % u \ n " ,fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* If write would fit in the cache , and is larger than
* the data already in the cache , flush the cache and
* preferentially copy the data new data into it . Otherwise
* just write the data directly .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
if ( n < = wcp - > alloc_size & & n > wcp - > data_size ) {
cache_flush_needed = True ;
} else {
2007-10-31 02:22:24 +03:00
ssize_t ret = real_write_file ( NULL , fsp , data , pos , n ) ;
2002-01-20 03:43:28 +03:00
2002-10-03 22:10:59 +04:00
/*
* If the write overlaps the entire cache , then
* discard the current contents of the cache .
* Fix from Rasmus Borup Hansen rbh @ math . ku . dk .
*/
if ( ( pos < = wcp - > offset ) & &
( pos + n > = wcp - > offset + wcp - > data_size ) ) {
DEBUG ( 9 , ( " write_file: discarding overwritten write \
2005-07-08 08:51:27 +04:00
cache : fd = % d , off = % .0f , size = % u \ n " , fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
2002-10-03 22:10:59 +04:00
wcp - > data_size = 0 ;
}
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_direct_writes ) ;
2005-05-09 03:16:28 +04:00
if ( ret = = - 1 ) {
2002-07-15 14:35:28 +04:00
return ret ;
2005-05-09 03:16:28 +04:00
}
2002-01-20 03:43:28 +03:00
2002-12-04 06:12:09 +03:00
if ( pos + ret > wcp - > file_size ) {
wcp - > file_size = pos + ret ;
}
2002-01-20 03:43:28 +03:00
2002-07-15 14:35:28 +04:00
return ret ;
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
write_path = 4 ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
if ( cache_flush_needed ) {
DEBUG ( 3 , ( " WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
1999-12-13 16:27:58 +03:00
n = % u , wcp - > offset = % .0f , wcp - > data_size = % u \ n " ,
2005-07-08 08:51:27 +04:00
write_path , fsp - > fh - > fd , ( double ) wcp - > file_size , ( double ) pos , ( unsigned int ) n ,
2002-07-15 14:35:28 +04:00
( double ) wcp - > offset , ( unsigned int ) wcp - > data_size ) ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
flush_write_cache ( fsp , WRITE_FLUSH ) ;
}
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* If the write request is bigger than the cache
* size , write it all out .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
if ( n > wcp - > alloc_size ) {
2007-10-31 02:22:24 +03:00
ssize_t ret = real_write_file ( NULL , fsp , data , pos , n ) ;
2005-05-09 03:16:28 +04:00
if ( ret = = - 1 ) {
2002-07-15 14:35:28 +04:00
return - 1 ;
2005-05-09 03:16:28 +04:00
}
2002-01-20 03:43:28 +03:00
2002-12-04 06:12:09 +03:00
if ( pos + ret > wcp - > file_size ) {
wcp - > file_size = pos + n ;
}
2002-01-20 03:43:28 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_direct_writes ) ;
return total_written + n ;
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
/*
* If there ' s any data left , cache it .
*/
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
if ( n ) {
2000-10-05 22:50:18 +04:00
# ifdef WITH_PROFILE
2002-07-15 14:35:28 +04:00
if ( wcp - > data_size ) {
DO_PROFILE_INC ( writecache_abutted_writes ) ;
} else {
DO_PROFILE_INC ( writecache_init_writes ) ;
}
2000-10-05 22:50:18 +04:00
# endif
2010-07-07 23:50:23 +04:00
if ( ( wcp - > data_size = = 0 )
& & ( pos > wcp - > file_size )
& & ( pos + n < = wcp - > file_size + wcp - > alloc_size ) ) {
/*
* This is a write completely beyond the
* current EOF , but within reach of the write
* cache . We expect fill - up writes pretty
* soon , so it does not make sense to start
* the write cache at the current
* offset . These fill - up writes would trigger
* separate pwrites or even unnecessary cache
* flushes because they overlap if this is a
* one - byte allocating write .
*/
wcp - > offset = wcp - > file_size ;
wcp - > data_size = pos - wcp - > file_size ;
memset ( wcp - > data , 0 , wcp - > data_size ) ;
}
2002-07-15 14:35:28 +04:00
memcpy ( wcp - > data + wcp - > data_size , data , n ) ;
if ( wcp - > data_size = = 0 ) {
wcp - > offset = pos ;
DO_PROFILE_INC ( writecache_num_write_caches ) ;
}
wcp - > data_size + = n ;
/*
* Update the file size if changed .
*/
2002-12-04 06:12:09 +03:00
if ( wcp - > offset + wcp - > data_size > wcp - > file_size ) {
2005-05-09 03:16:28 +04:00
if ( wcp_file_size_change ( fsp ) = = - 1 ) {
return - 1 ;
}
2002-12-04 06:12:09 +03:00
}
2002-07-15 14:35:28 +04:00
DEBUG ( 9 , ( " wcp->offset = %.0f wcp->data_size = %u cache return %u \n " ,
( double ) wcp - > offset , ( unsigned int ) wcp - > data_size , ( unsigned int ) n ) ) ;
total_written + = n ;
return total_written ; /* .... that's a write :) */
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
return total_written ;
1998-08-17 11:15:54 +04:00
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
Delete the write cache structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-17 11:40:06 +04:00
1999-12-13 16:27:58 +03:00
void delete_write_cache ( files_struct * fsp )
{
2002-07-15 14:35:28 +04:00
write_cache * wcp ;
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( ! fsp ) {
2002-07-15 14:35:28 +04:00
return ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( ! ( wcp = fsp - > wcp ) ) {
2002-07-15 14:35:28 +04:00
return ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_DEC ( writecache_allocated_write_caches ) ;
allocated_write_caches - - ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
SMB_ASSERT ( wcp - > data_size = = 0 ) ;
2000-10-03 01:03:46 +04:00
2002-07-15 14:35:28 +04:00
SAFE_FREE ( wcp - > data ) ;
SAFE_FREE ( fsp - > wcp ) ;
2000-10-03 01:03:46 +04:00
2009-07-11 01:50:37 +04:00
DEBUG ( 10 , ( " delete_write_cache: File %s deleted write cache \n " ,
fsp_str_dbg ( fsp ) ) ) ;
1999-12-13 16:27:58 +03:00
}
/****************************************************************************
Setup the write cache structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool setup_write_cache ( files_struct * fsp , SMB_OFF_T file_size )
1999-12-13 16:27:58 +03:00
{
2002-07-15 14:35:28 +04:00
ssize_t alloc_size = lp_write_cache_size ( SNUM ( fsp - > conn ) ) ;
write_cache * wcp ;
2005-05-09 03:16:28 +04:00
if ( allocated_write_caches > = MAX_WRITE_CACHES ) {
2002-07-15 14:35:28 +04:00
return False ;
2005-05-09 03:16:28 +04:00
}
2002-07-15 14:35:28 +04:00
2005-05-09 03:16:28 +04:00
if ( alloc_size = = 0 | | fsp - > wcp ) {
2002-07-15 14:35:28 +04:00
return False ;
2005-05-09 03:16:28 +04:00
}
2002-07-15 14:35:28 +04:00
2004-12-07 21:25:53 +03:00
if ( ( wcp = SMB_MALLOC_P ( write_cache ) ) = = NULL ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " setup_write_cache: malloc fail. \n " ) ) ;
return False ;
}
wcp - > file_size = file_size ;
wcp - > offset = 0 ;
wcp - > alloc_size = alloc_size ;
wcp - > data_size = 0 ;
2005-06-25 00:25:18 +04:00
if ( ( wcp - > data = ( char * ) SMB_MALLOC ( wcp - > alloc_size ) ) = = NULL ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " setup_write_cache: malloc fail for buffer size %u. \n " ,
( unsigned int ) wcp - > alloc_size ) ) ;
SAFE_FREE ( wcp ) ;
return False ;
}
memset ( wcp - > data , ' \0 ' , wcp - > alloc_size ) ;
fsp - > wcp = wcp ;
DO_PROFILE_INC ( writecache_allocated_write_caches ) ;
allocated_write_caches + + ;
2003-11-02 20:10:12 +03:00
DEBUG ( 10 , ( " setup_write_cache: File %s allocated write cache size %lu \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( unsigned long ) wcp - > alloc_size ) ) ;
2000-10-03 01:03:46 +04:00
2002-07-15 14:35:28 +04:00
return True ;
1999-12-13 16:27:58 +03:00
}
/****************************************************************************
Cope with a size change .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void set_filelen_write_cache ( files_struct * fsp , SMB_OFF_T file_size )
{
2002-07-15 14:35:28 +04:00
if ( fsp - > wcp ) {
/* The cache *must* have been flushed before we do this. */
if ( fsp - > wcp - > data_size ! = 0 ) {
2007-07-09 20:27:13 +04:00
char * msg ;
2008-12-23 23:11:12 +03:00
if ( asprintf ( & msg , " set_filelen_write_cache: size change "
2007-07-09 20:27:13 +04:00
" on file %s with write cache size = %lu \n " ,
2009-07-11 01:50:37 +04:00
fsp - > fsp_name - > base_name ,
2008-12-23 23:11:12 +03:00
( unsigned long ) fsp - > wcp - > data_size ) ! = - 1 ) {
smb_panic ( msg ) ;
} else {
smb_panic ( " set_filelen_write_cache " ) ;
}
2002-07-15 14:35:28 +04:00
}
fsp - > wcp - > file_size = file_size ;
}
1999-12-13 16:27:58 +03:00
}
/*******************************************************************
Flush a write cache struct to disk .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t flush_write_cache ( files_struct * fsp , enum flush_reason_enum reason )
{
2002-07-15 14:35:28 +04:00
write_cache * wcp = fsp - > wcp ;
size_t data_size ;
ssize_t ret ;
1999-12-13 16:27:58 +03:00
2005-05-09 03:16:28 +04:00
if ( ! wcp | | ! wcp - > data_size ) {
2002-07-15 14:35:28 +04:00
return 0 ;
2005-05-09 03:16:28 +04:00
}
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
data_size = wcp - > data_size ;
wcp - > data_size = 0 ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DO_PROFILE_DEC_INC ( writecache_num_write_caches , writecache_flushed_writes [ reason ] ) ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 9 , ( " flushing write cache: fd = %d, off=%.0f, size=%u \n " ,
2005-07-08 08:51:27 +04:00
fsp - > fh - > fd , ( double ) wcp - > offset , ( unsigned int ) data_size ) ) ;
1999-12-13 16:27:58 +03:00
2000-10-05 22:50:18 +04:00
# ifdef WITH_PROFILE
2005-05-09 03:16:28 +04:00
if ( data_size = = wcp - > alloc_size ) {
2002-07-15 14:35:28 +04:00
DO_PROFILE_INC ( writecache_num_perfect_writes ) ;
2005-05-09 03:16:28 +04:00
}
2000-10-05 22:50:18 +04:00
# endif
1999-12-13 16:27:58 +03:00
2007-10-31 02:22:24 +03:00
ret = real_write_file ( NULL , fsp , wcp - > data , wcp - > offset , data_size ) ;
2002-01-20 03:04:15 +03:00
2002-07-15 14:35:28 +04:00
/*
* Ensure file size if kept up to date if write extends file .
*/
2002-01-20 03:04:15 +03:00
2005-05-09 03:16:28 +04:00
if ( ( ret ! = - 1 ) & & ( wcp - > offset + ret > wcp - > file_size ) ) {
2002-07-15 14:35:28 +04:00
wcp - > file_size = wcp - > offset + ret ;
2005-05-09 03:16:28 +04:00
}
2002-01-20 03:04:15 +03:00
2002-07-15 14:35:28 +04:00
return ret ;
1999-12-13 16:27:58 +03:00
}
2000-02-03 08:17:25 +03:00
1998-08-17 11:40:06 +04:00
/*******************************************************************
sync a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-11 05:24:30 +04:00
2007-10-19 04:40:25 +04:00
NTSTATUS sync_file ( connection_struct * conn , files_struct * fsp , bool write_through )
1998-08-17 11:40:06 +04:00
{
2005-09-03 11:19:28 +04:00
if ( fsp - > fh - > fd = = - 1 )
2007-06-15 23:24:04 +04:00
return NT_STATUS_INVALID_HANDLE ;
2005-09-03 11:19:28 +04:00
if ( lp_strict_sync ( SNUM ( conn ) ) & &
( lp_syncalways ( SNUM ( conn ) ) | | write_through ) ) {
2007-06-15 23:24:04 +04:00
int ret = flush_write_cache ( fsp , SYNC_FLUSH ) ;
if ( ret = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
2008-01-07 14:49:02 +03:00
ret = SMB_VFS_FSYNC ( fsp ) ;
2007-06-15 23:24:04 +04:00
if ( ret = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
2002-07-15 14:35:28 +04:00
}
2007-06-15 23:24:04 +04:00
return NT_STATUS_OK ;
1998-08-17 11:40:06 +04:00
}
2002-03-20 03:46:53 +03:00
/************************************************************
Perform a stat whether a valid fd or not .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-17 01:55:21 +03:00
int fsp_stat ( files_struct * fsp )
2002-03-20 03:46:53 +03:00
{
2005-07-08 08:51:27 +04:00
if ( fsp - > fh - > fd = = - 1 ) {
2009-11-17 01:55:21 +03:00
if ( fsp - > posix_open ) {
return SMB_VFS_LSTAT ( fsp - > conn , fsp - > fsp_name ) ;
} else {
return SMB_VFS_STAT ( fsp - > conn , fsp - > fsp_name ) ;
2009-07-11 01:50:37 +04:00
}
2005-05-09 03:16:28 +04:00
} else {
2009-11-17 01:55:21 +03:00
return SMB_VFS_FSTAT ( fsp , & fsp - > fsp_name - > st ) ;
2005-05-09 03:16:28 +04:00
}
2002-03-20 03:46:53 +03:00
}