1/*
2   Unix SMB/Netbios implementation.
3   Version 1.9.
4   read/write to a files_struct
5   Copyright (C) Andrew Tridgell 1992-1998
6   Copyright (C) Jeremy Allison 2000-2002. - write cache.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23#include "includes.h"
24
25static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
26
27/****************************************************************************
28 Read from write cache if we can.
29****************************************************************************/
30
31/* Foxconn modified start pling 11/25/2009 */
32//static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
33static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_BIG_UINT pos,size_t n)
34/* Foxconn modified end pling 11/25/2009 */
35{
36	write_cache *wcp = fsp->wcp;
37
38	if(!wcp)
39		return False;
40
41	if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size)
42		return False;
43
44	memcpy(data, wcp->data + (pos - wcp->offset), n);
45
46	DO_PROFILE_INC(writecache_read_hits);
47
48	return True;
49}
50
51/****************************************************************************
52 Read from a file.
53****************************************************************************/
54
55/* Foxconn modified start pling 11/25/2009 */
56//ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
57ssize_t read_file(files_struct *fsp,char *data,SMB_BIG_UINT pos,size_t n)
58/* Foxconn modified end pling 11/25/2009 */
59{
60	ssize_t ret=0,readret;
61
62	/* you can't read from print files */
63	if (fsp->print_file)
64		return -1;
65
66	/*
67	 * Serve from write cache if we can.
68	 */
69
70	if(read_from_write_cache(fsp, data, pos, n)) {
71		fsp->pos = pos + n;
72		fsp->position_information = fsp->pos;
73		return n;
74	}
75
76	flush_write_cache(fsp, READ_FLUSH);
77
78	fsp->pos = pos;
79
80	if (n > 0) {
81#ifdef DMF_FIX
82		int numretries = 3;
83tryagain:
84		readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos);
85
86		if (readret == -1) {
87			if ((errno == EAGAIN) && numretries) {
88				DEBUG(3,("read_file EAGAIN retry in 10 seconds\n"));
89				(void)sleep(10);
90				--numretries;
91				goto tryagain;
92			}
93			return -1;
94		}
95#else /* NO DMF fix. */
96		readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos);
97
98		if (readret == -1)
99			return -1;
100#endif
101		if (readret > 0)
102			ret += readret;
103	}
104
105	DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
106		fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
107
108	fsp->pos += ret;
109	fsp->position_information = fsp->pos;
110
111	return(ret);
112}
113
114/* how many write cache buffers have been allocated */
115static unsigned int allocated_write_caches;
116
117/****************************************************************************
118 *Really* write to a file.
119****************************************************************************/
120
121/* Foxconn modified start pling 11/18/2009 */
122//static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n)
123static ssize_t real_write_file(files_struct *fsp,char *data, SMB_BIG_UINT pos, size_t n)
124/* Foxconn modified end pling 11/18/2009 */
125{
126	ssize_t ret;
127
128        if (pos == -1)
129                ret = vfs_write_data(fsp, data, n);
130        else {
131		fsp->pos = pos;
132                ret = vfs_pwrite_data(fsp, data, n, pos);
133	}
134
135	DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
136		fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
137
138	if (ret != -1) {
139		fsp->pos += ret;
140
141		/*
142		 * It turns out that setting the last write time from a Windows
143		 * client stops any subsequent writes from updating the write time.
144		 * Doing this after the write gives a race condition here where
145		 * a stat may see the changed write time before we reset it here,
146		 * but it's cheaper than having to store the write time in shared
147		 * memory and look it up using dev/inode across all running smbd's.
148		 * The 99% solution will hopefully be good enough in this case. JRA.
149		 */
150
151		if (fsp->pending_modtime) {
152			set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime);
153
154			/* If we didn't get the "set modtime" call ourselves, we must
155			   store the last write time to restore on close. JRA. */
156			if (!fsp->pending_modtime_owner) {
157				fsp->last_write_time = time(NULL);
158			}
159		}
160
161/* Yes - this is correct - writes don't update this. JRA. */
162/* Found by Samba4 tests. */
163#if 0
164		fsp->position_information = fsp->pos;
165#endif
166	}
167
168	return ret;
169}
170
171/****************************************************************************
172write to a file
173****************************************************************************/
174
175/* Foxconn modified start pling 11/18/2009 */
176//ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
177ssize_t write_file(files_struct *fsp, char *data, SMB_BIG_UINT pos, size_t n)
178/* Foxconn modified end pling 11/18/2009 */
179{
180	write_cache *wcp = fsp->wcp;
181	ssize_t total_written = 0;
182	int write_path = -1;
183
184	if (fsp->print_file) {
185		fstring sharename;
186		uint32 jobid;
187
188		if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
189			DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
190						(unsigned int)fsp->rap_print_jobid ));
191			errno = EBADF;
192			return -1;
193		}
194
195		return print_job_write(SNUM(fsp->conn), jobid, data, n);
196	}
197
198	if (!fsp->can_write) {
199		errno = EPERM;
200		return(0);
201	}
202
203	if (!fsp->modified) {
204		SMB_STRUCT_STAT st;
205		fsp->modified = True;
206
207		if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) {
208			int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
209			fsp->size = (SMB_BIG_UINT)st.st_size;
210			if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
211				file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False);
212			}
213
214			/*
215			 * If this is the first write and we have an exclusive oplock then setup
216			 * the write cache.
217			 */
218
219			if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
220				setup_write_cache(fsp, st.st_size);
221				wcp = fsp->wcp;
222			}
223		}
224	}
225
226#ifdef WITH_PROFILE
227	DO_PROFILE_INC(writecache_total_writes);
228	if (!fsp->oplock_type) {
229		DO_PROFILE_INC(writecache_non_oplock_writes);
230	}
231#endif
232
233	/*
234	 * If this file is level II oplocked then we need
235	 * to grab the shared memory lock and inform all
236	 * other files with a level II lock that they need
237	 * to flush their read caches. We keep the lock over
238	 * the shared memory area whilst doing this.
239	 */
240
241	release_level_2_oplocks_on_change(fsp);
242
243#ifdef WITH_PROFILE
244	if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
245		DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
246nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
247			profile_p->writecache_init_writes,
248			profile_p->writecache_abutted_writes,
249			profile_p->writecache_total_writes,
250			profile_p->writecache_non_oplock_writes,
251			profile_p->writecache_allocated_write_caches,
252			profile_p->writecache_num_write_caches,
253			profile_p->writecache_direct_writes,
254			profile_p->writecache_num_perfect_writes,
255			profile_p->writecache_read_hits ));
256
257		DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
258			profile_p->writecache_flushed_writes[SEEK_FLUSH],
259			profile_p->writecache_flushed_writes[READ_FLUSH],
260			profile_p->writecache_flushed_writes[WRITE_FLUSH],
261			profile_p->writecache_flushed_writes[READRAW_FLUSH],
262			profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
263			profile_p->writecache_flushed_writes[CLOSE_FLUSH],
264			profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
265	}
266#endif
267
268	if(!wcp) {
269		DO_PROFILE_INC(writecache_direct_writes);
270		total_written = real_write_file(fsp, data, pos, n);
271		if ((total_written != -1) && (pos + total_written > (SMB_OFF_T)fsp->size))
272			fsp->size = (SMB_BIG_UINT)(pos + total_written);
273		return total_written;
274	}
275
276	DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
277		fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
278
279	fsp->pos = pos + n;
280
281	/*
282	 * If we have active cache and it isn't contiguous then we flush.
283	 * NOTE: There is a small problem with running out of disk ....
284	 */
285
286	if (wcp->data_size) {
287
288		BOOL cache_flush_needed = False;
289
290		if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
291
292			/* ASCII art.... JRA.
293
294      +--------------+-----
295      | Cached data  | Rest of allocated cache buffer....
296      +--------------+-----
297
298            +-------------------+
299            | Data to write     |
300            +-------------------+
301
302	    		*/
303
304			/*
305			 * Start of write overlaps or abutts the existing data.
306			 */
307
308			size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
309
310			memcpy(wcp->data + (pos - wcp->offset), data, data_used);
311
312			/*
313			 * Update the current buffer size with the new data.
314			 */
315
316			if(pos + data_used > wcp->offset + wcp->data_size)
317				wcp->data_size = pos + data_used - wcp->offset;
318
319			/*
320			 * Update the file size if changed.
321			 */
322
323			if (wcp->offset + wcp->data_size > wcp->file_size) {
324				wcp->file_size = wcp->offset + wcp->data_size;
325				fsp->size = (SMB_BIG_UINT)wcp->file_size;
326			}
327
328			/*
329			 * If we used all the data then
330			 * return here.
331			 */
332
333			if(n == data_used)
334				return n;
335			else
336				cache_flush_needed = True;
337
338			/*
339			 * Move the start of data forward by the amount used,
340			 * cut down the amount left by the same amount.
341			 */
342
343			data += data_used;
344			pos += data_used;
345			n -= data_used;
346
347			DO_PROFILE_INC(writecache_abutted_writes);
348			total_written = data_used;
349
350			write_path = 1;
351
352		} else if ((pos < wcp->offset) && (pos + n > wcp->offset) &&
353					(pos + n <= wcp->offset + wcp->alloc_size)) {
354
355			/* ASCII art.... JRA.
356
357                        +---------------+
358                        | Cache buffer  |
359                        +---------------+
360
361            +-------------------+
362            | Data to write     |
363            +-------------------+
364
365	    		*/
366
367			/*
368			 * End of write overlaps the existing data.
369			 */
370
371			size_t data_used = pos + n - wcp->offset;
372
373			memcpy(wcp->data, data + n - data_used, data_used);
374
375			/*
376			 * Update the current buffer size with the new data.
377			 */
378
379			if(pos + n > wcp->offset + wcp->data_size)
380				wcp->data_size = pos + n - wcp->offset;
381
382			/*
383			 * Update the file size if changed.
384			 */
385
386			if (wcp->offset + wcp->data_size > wcp->file_size) {
387				wcp->file_size = wcp->offset + wcp->data_size;
388				fsp->size = (SMB_BIG_UINT)wcp->file_size;
389			}
390
391			/*
392			 * We don't need to move the start of data, but we
393			 * cut down the amount left by the amount used.
394			 */
395
396			n -= data_used;
397
398			/*
399			 * We cannot have used all the data here.
400			 */
401
402			cache_flush_needed = True;
403
404			DO_PROFILE_INC(writecache_abutted_writes);
405			total_written = data_used;
406
407			write_path = 2;
408
409		} else if ( (pos >= wcp->file_size) &&
410					(wcp->offset + wcp->data_size == wcp->file_size) &&
411					(pos > wcp->offset + wcp->data_size) &&
412					(pos < wcp->offset + wcp->alloc_size) ) {
413
414			/* ASCII art.... JRA.
415
416                       End of file ---->|
417
418                        +---------------+---------------+
419                        | Cached data   | Cache buffer  |
420                        +---------------+---------------+
421
422                                              +-------------------+
423                                              | Data to write     |
424                                              +-------------------+
425
426	    		*/
427
428			/*
429			 * Non-contiguous write part of which fits within
430			 * the cache buffer and is extending the file
431			 * and the cache contents reflect the current
432			 * data up to the current end of the file.
433			 */
434
435			size_t data_used;
436
437			if(pos + n <= wcp->offset + wcp->alloc_size)
438				data_used = n;
439			else
440				data_used = wcp->offset + wcp->alloc_size - pos;
441
442			/*
443			 * Fill in the non-continuous area with zeros.
444			 */
445
446			memset(wcp->data + wcp->data_size, '\0',
447				pos - (wcp->offset + wcp->data_size) );
448
449			memcpy(wcp->data + (pos - wcp->offset), data, data_used);
450
451			/*
452			 * Update the current buffer size with the new data.
453			 */
454
455			if(pos + data_used > wcp->offset + wcp->data_size)
456				wcp->data_size = pos + data_used - wcp->offset;
457
458			/*
459			 * Update the file size if changed.
460			 */
461
462			if (wcp->offset + wcp->data_size > wcp->file_size) {
463				wcp->file_size = wcp->offset + wcp->data_size;
464				fsp->size = (SMB_BIG_UINT)wcp->file_size;
465			}
466
467			/*
468			 * If we used all the data then
469			 * return here.
470			 */
471
472			if(n == data_used)
473				return n;
474			else
475				cache_flush_needed = True;
476
477			/*
478			 * Move the start of data forward by the amount used,
479			 * cut down the amount left by the same amount.
480			 */
481
482			data += data_used;
483			pos += data_used;
484			n -= data_used;
485
486			DO_PROFILE_INC(writecache_abutted_writes);
487			total_written = data_used;
488
489			write_path = 3;
490
491		} else {
492
493			/* ASCII art..... JRA.
494
495   Case 1).
496
497                        +---------------+---------------+
498                        | Cached data   | Cache buffer  |
499                        +---------------+---------------+
500
501                                                              +-------------------+
502                                                              | Data to write     |
503                                                              +-------------------+
504
505   Case 2).
506
507                           +---------------+---------------+
508                           | Cached data   | Cache buffer  |
509                           +---------------+---------------+
510
511   +-------------------+
512   | Data to write     |
513   +-------------------+
514
515    Case 3).
516
517                           +---------------+---------------+
518                           | Cached data   | Cache buffer  |
519                           +---------------+---------------+
520
521                  +-----------------------------------------------------+
522                  | Data to write                                       |
523                  +-----------------------------------------------------+
524
525		  */
526
527 			/*
528			 * Write is bigger than buffer, or there is no overlap on the
529			 * low or high ends.
530			 */
531
532			DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
533len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
534
535			/*
536			 * Update the file size if needed.
537			 */
538
539			if(pos + n > wcp->file_size) {
540				wcp->file_size = pos + n;
541				fsp->size = (SMB_BIG_UINT)wcp->file_size;
542			}
543
544			/*
545			 * If write would fit in the cache, and is larger than
546			 * the data already in the cache, flush the cache and
547			 * preferentially copy the data new data into it. Otherwise
548			 * just write the data directly.
549			 */
550
551			if ( n <= wcp->alloc_size && n > wcp->data_size) {
552				cache_flush_needed = True;
553			} else {
554				ssize_t ret = real_write_file(fsp, data, pos, n);
555
556				/*
557				 * If the write overlaps the entire cache, then
558				 * discard the current contents of the cache.
559				 * Fix from Rasmus Borup Hansen rbh@math.ku.dk.
560				 */
561
562				if ((pos <= wcp->offset) &&
563						(pos + n >= wcp->offset + wcp->data_size) ) {
564					DEBUG(9,("write_file: discarding overwritten write \
565cache: fd = %d, off=%.0f, size=%u\n", fsp->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
566					wcp->data_size = 0;
567				}
568
569				DO_PROFILE_INC(writecache_direct_writes);
570				if (ret == -1)
571					return ret;
572
573				if (pos + ret > wcp->file_size) {
574					wcp->file_size = pos + ret;
575					fsp->size = (SMB_BIG_UINT)wcp->file_size;
576				}
577
578				return ret;
579			}
580
581			write_path = 4;
582
583		}
584
585		if(wcp->data_size > wcp->file_size) {
586			wcp->file_size = wcp->data_size;
587			fsp->size = (SMB_BIG_UINT)wcp->file_size;
588		}
589
590		if (cache_flush_needed) {
591			DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
592n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
593				write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
594				(double)wcp->offset, (unsigned int)wcp->data_size ));
595
596			flush_write_cache(fsp, WRITE_FLUSH);
597		}
598	}
599
600	/*
601	 * If the write request is bigger than the cache
602	 * size, write it all out.
603	 */
604
605	if (n > wcp->alloc_size ) {
606		ssize_t ret = real_write_file(fsp, data, pos, n);
607		if (ret == -1)
608			return -1;
609
610		if (pos + ret > wcp->file_size) {
611			wcp->file_size = pos + n;
612			fsp->size = (SMB_BIG_UINT)wcp->file_size;
613		}
614
615		DO_PROFILE_INC(writecache_direct_writes);
616		return total_written + n;
617	}
618
619	/*
620	 * If there's any data left, cache it.
621	 */
622
623	if (n) {
624#ifdef WITH_PROFILE
625		if (wcp->data_size) {
626			DO_PROFILE_INC(writecache_abutted_writes);
627		} else {
628			DO_PROFILE_INC(writecache_init_writes);
629		}
630#endif
631		memcpy(wcp->data+wcp->data_size, data, n);
632		if (wcp->data_size == 0) {
633			wcp->offset = pos;
634			DO_PROFILE_INC(writecache_num_write_caches);
635		}
636		wcp->data_size += n;
637
638		/*
639		 * Update the file size if changed.
640		 */
641
642		if (wcp->offset + wcp->data_size > wcp->file_size) {
643			wcp->file_size = wcp->offset + wcp->data_size;
644			fsp->size = (SMB_BIG_UINT)wcp->file_size;
645		}
646		DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
647			(double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
648
649		total_written += n;
650		return total_written; /* .... that's a write :) */
651	}
652
653	return total_written;
654}
655
656/****************************************************************************
657 Delete the write cache structure.
658****************************************************************************/
659
660void delete_write_cache(files_struct *fsp)
661{
662	write_cache *wcp;
663
664	if(!fsp)
665		return;
666
667	if(!(wcp = fsp->wcp))
668		return;
669
670	DO_PROFILE_DEC(writecache_allocated_write_caches);
671	allocated_write_caches--;
672
673	SMB_ASSERT(wcp->data_size == 0);
674
675	SAFE_FREE(wcp->data);
676	SAFE_FREE(fsp->wcp);
677
678	DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
679}
680
681/****************************************************************************
682 Setup the write cache structure.
683****************************************************************************/
684
685static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
686{
687	ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
688	write_cache *wcp;
689
690	if (allocated_write_caches >= MAX_WRITE_CACHES)
691		return False;
692
693	if(alloc_size == 0 || fsp->wcp)
694		return False;
695
696	if((wcp = SMB_MALLOC_P(write_cache)) == NULL) {
697		DEBUG(0,("setup_write_cache: malloc fail.\n"));
698		return False;
699	}
700
701	wcp->file_size = file_size;
702	wcp->offset = 0;
703	wcp->alloc_size = alloc_size;
704	wcp->data_size = 0;
705	if((wcp->data = SMB_MALLOC(wcp->alloc_size)) == NULL) {
706		DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
707			(unsigned int)wcp->alloc_size ));
708		SAFE_FREE(wcp);
709		return False;
710	}
711
712	memset(wcp->data, '\0', wcp->alloc_size );
713
714	fsp->wcp = wcp;
715	DO_PROFILE_INC(writecache_allocated_write_caches);
716	allocated_write_caches++;
717
718	DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n",
719		fsp->fsp_name, (unsigned long)wcp->alloc_size ));
720
721	return True;
722}
723
724/****************************************************************************
725 Cope with a size change.
726****************************************************************************/
727
728void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
729{
730	fsp->size = (SMB_BIG_UINT)file_size;
731	if(fsp->wcp) {
732		/* The cache *must* have been flushed before we do this. */
733		if (fsp->wcp->data_size != 0) {
734			pstring msg;
735			slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \
736on file %s with write cache size = %lu\n", fsp->fsp_name, (unsigned long)fsp->wcp->data_size );
737			smb_panic(msg);
738		}
739		fsp->wcp->file_size = file_size;
740	}
741}
742
743/*******************************************************************
744 Flush a write cache struct to disk.
745********************************************************************/
746
747ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
748{
749	write_cache *wcp = fsp->wcp;
750	size_t data_size;
751	ssize_t ret;
752
753	if(!wcp || !wcp->data_size)
754		return 0;
755
756	data_size = wcp->data_size;
757	wcp->data_size = 0;
758
759	DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
760
761	DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
762		fsp->fd, (double)wcp->offset, (unsigned int)data_size));
763
764#ifdef WITH_PROFILE
765	if(data_size == wcp->alloc_size)
766		DO_PROFILE_INC(writecache_num_perfect_writes);
767#endif
768
769	ret = real_write_file(fsp, wcp->data, wcp->offset, data_size);
770
771	/*
772	 * Ensure file size if kept up to date if write extends file.
773	 */
774
775	if ((ret != -1) && (wcp->offset + ret > wcp->file_size))
776		wcp->file_size = wcp->offset + ret;
777
778	return ret;
779}
780
781/*******************************************************************
782sync a file
783********************************************************************/
784
785void sync_file(connection_struct *conn, files_struct *fsp)
786{
787	if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) {
788		flush_write_cache(fsp, SYNC_FLUSH);
789		SMB_VFS_FSYNC(fsp,fsp->fd);
790	}
791}
792
793
794/************************************************************
795 Perform a stat whether a valid fd or not.
796************************************************************/
797
798int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst)
799{
800	if (fsp->fd == -1)
801		return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst);
802	else
803		return SMB_VFS_FSTAT(fsp,fsp->fd, pst);
804}
805