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