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