067ce5a9ad408befbc87fe3f7424c0827607505c
[samba.git] / source3 / 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 #include "printing.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "smbprofile.h"
27
28 struct write_cache {
29         off_t file_size;
30         off_t offset;
31         size_t alloc_size;
32         size_t data_size;
33         char *data;
34 };
35
36 static bool setup_write_cache(files_struct *, off_t);
37
38 /****************************************************************************
39  Read from write cache if we can.
40 ****************************************************************************/
41
42 static bool read_from_write_cache(files_struct *fsp,char *data,off_t pos,size_t n)
43 {
44         struct write_cache *wcp = fsp->wcp;
45
46         if(!wcp) {
47                 return False;
48         }
49
50         if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) {
51                 return False;
52         }
53
54         memcpy(data, wcp->data + (pos - wcp->offset), n);
55
56         DO_PROFILE_INC(writecache_cached_reads);
57
58         return True;
59 }
60
61 /****************************************************************************
62  Read from a file.
63 ****************************************************************************/
64
65 ssize_t read_file(files_struct *fsp,char *data,off_t pos,size_t n)
66 {
67         ssize_t ret = 0;
68
69         /* you can't read from print files */
70         if (fsp->print_file) {
71                 errno = EBADF;
72                 return -1;
73         }
74
75         /*
76          * Serve from write cache if we can.
77          */
78
79         if(read_from_write_cache(fsp, data, pos, n)) {
80                 fsp->fh->pos = pos + n;
81                 fsp->fh->position_information = fsp->fh->pos;
82                 return n;
83         }
84
85         flush_write_cache(fsp, SAMBA_READ_FLUSH);
86
87         fsp->fh->pos = pos;
88
89         if (n > 0) {
90                 ret = SMB_VFS_PREAD(fsp,data,n,pos);
91
92                 if (ret == -1) {
93                         return -1;
94                 }
95         }
96
97         DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
98                   fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
99
100         fsp->fh->pos += ret;
101         fsp->fh->position_information = fsp->fh->pos;
102
103         return(ret);
104 }
105
106 /****************************************************************************
107  *Really* write to a file.
108 ****************************************************************************/
109
110 static ssize_t real_write_file(struct smb_request *req,
111                                 files_struct *fsp,
112                                 const char *data,
113                                 off_t pos,
114                                 size_t n)
115 {
116         ssize_t ret;
117
118         fsp->fh->pos = pos;
119         if (pos && lp_strict_allocate(SNUM(fsp->conn) &&
120                         !fsp->is_sparse)) {
121                 if (vfs_fill_sparse(fsp, pos) == -1) {
122                         return -1;
123                 }
124         }
125         ret = vfs_pwrite_data(req, fsp, data, n, pos);
126
127         DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
128                   fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
129
130         if (ret != -1) {
131                 fsp->fh->pos += ret;
132
133 /* Yes - this is correct - writes don't update this. JRA. */
134 /* Found by Samba4 tests. */
135 #if 0
136                 fsp->position_information = fsp->pos;
137 #endif
138         }
139
140         return ret;
141 }
142
143 /****************************************************************************
144  File size cache change.
145  Updates size on disk but doesn't flush the cache.
146 ****************************************************************************/
147
148 static int wcp_file_size_change(files_struct *fsp)
149 {
150         int ret;
151         struct write_cache *wcp = fsp->wcp;
152
153         wcp->file_size = wcp->offset + wcp->data_size;
154         ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
155         if (ret == -1) {
156                 DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f "
157                          "error %s\n", fsp_str_dbg(fsp),
158                          (double)wcp->file_size, strerror(errno)));
159         }
160         return ret;
161 }
162
163 void fsp_flush_write_time_update(struct files_struct *fsp)
164 {
165         /*
166          * Note this won't expect any impersonation!
167          * So don't call any SMB_VFS operations here!
168          */
169
170         DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
171
172         /* change the write time in the open file db. */
173         (void)set_write_time(fsp->file_id, timespec_current());
174
175         /* And notify. */
176         notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
177                      FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name);
178
179         /* Remove the timed event handler. */
180         TALLOC_FREE(fsp->update_write_time_event);
181 }
182
183 static void update_write_time_handler(struct tevent_context *ctx,
184                                       struct tevent_timer *te,
185                                       struct timeval now,
186                                       void *private_data)
187 {
188         files_struct *fsp = (files_struct *)private_data;
189         fsp_flush_write_time_update(fsp);
190 }
191
192 /*********************************************************
193  Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
194  in the future.
195 *********************************************************/
196
197 void trigger_write_time_update(struct files_struct *fsp)
198 {
199         int delay;
200
201         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
202                 /* Don't use delayed writes on POSIX files. */
203                 return;
204         }
205
206         if (fsp->write_time_forced) {
207                 /* No point - "sticky" write times
208                  * in effect.
209                  */
210                 return;
211         }
212
213         /* We need to remember someone did a write
214          * and update to current time on close. */
215
216         fsp->update_write_time_on_close = true;
217
218         if (fsp->update_write_time_triggered) {
219                 /*
220                  * We only update the write time after 2 seconds
221                  * on the first normal write. After that
222                  * no other writes affect this until close.
223                  */
224                 return;
225         }
226         fsp->update_write_time_triggered = true;
227
228         delay = lp_parm_int(SNUM(fsp->conn),
229                             "smbd", "writetimeupdatedelay",
230                             WRITE_TIME_UPDATE_USEC_DELAY);
231
232         DEBUG(5, ("Update write time %d usec later on %s\n",
233                   delay, fsp_str_dbg(fsp)));
234
235         /* trigger the update 2 seconds later */
236         fsp->update_write_time_event =
237                 tevent_add_timer(fsp->conn->sconn->ev_ctx, NULL,
238                                  timeval_current_ofs_usec(delay),
239                                  update_write_time_handler, fsp);
240 }
241
242 void trigger_write_time_update_immediate(struct files_struct *fsp)
243 {
244         struct smb_file_time ft;
245
246         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
247                 /* Don't use delayed writes on POSIX files. */
248                 return;
249         }
250
251         if (fsp->write_time_forced) {
252                 /*
253                  * No point - "sticky" write times
254                  * in effect.
255                  */
256                 return;
257         }
258
259         TALLOC_FREE(fsp->update_write_time_event);
260         DEBUG(5, ("Update write time immediate on %s\n",
261                   fsp_str_dbg(fsp)));
262
263         /* After an immediate update, reset the trigger. */
264         fsp->update_write_time_triggered = true;
265         fsp->update_write_time_on_close = false;
266
267         ft = (struct smb_file_time) { .mtime = timespec_current() };
268
269         /* Update the time in the open file db. */
270         (void)set_write_time(fsp->file_id, ft.mtime);
271
272         /* Now set on disk - takes care of notify. */
273         (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
274 }
275
276 void mark_file_modified(files_struct *fsp)
277 {
278         int dosmode;
279
280         if (fsp->modified) {
281                 return;
282         }
283
284         fsp->modified = true;
285
286         if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
287                 return;
288         }
289         trigger_write_time_update(fsp);
290
291         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
292                 return;
293         }
294         if (!(lp_store_dos_attributes(SNUM(fsp->conn)) ||
295               MAP_ARCHIVE(fsp->conn))) {
296                 return;
297         }
298
299         dosmode = dos_mode(fsp->conn, fsp->fsp_name);
300         if (IS_DOS_ARCHIVE(dosmode)) {
301                 return;
302         }
303         file_set_dosmode(fsp->conn, fsp->fsp_name,
304                          dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
305 }
306
307 /****************************************************************************
308  Write to a file.
309 ****************************************************************************/
310
311 ssize_t write_file(struct smb_request *req,
312                         files_struct *fsp,
313                         const char *data,
314                         off_t pos,
315                         size_t n)
316 {
317         struct write_cache *wcp = fsp->wcp;
318         ssize_t total_written = 0;
319         int write_path = -1;
320
321         if (fsp->print_file) {
322                 uint32_t t;
323                 int ret;
324
325                 ret = print_spool_write(fsp, data, n, pos, &t);
326                 if (ret) {
327                         errno = ret;
328                         return -1;
329                 }
330                 return t;
331         }
332
333         if (!fsp->can_write) {
334                 errno = EPERM;
335                 return -1;
336         }
337
338         /*
339          * If this is the first write and we have an exclusive oplock
340          * then setup the write cache.
341          */
342
343         if (!fsp->modified &&
344             EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
345             (wcp == NULL)) {
346                 /*
347                  * Note: no write cache with leases!
348                  * as the handles would have to share the write cache
349                  * that's possible but an improvement for another day...
350                  */
351                 setup_write_cache(fsp, fsp->fsp_name->st.st_ex_size);
352                 wcp = fsp->wcp;
353         }
354
355         mark_file_modified(fsp);
356
357         DO_PROFILE_INC(writecache_total_writes);
358         if (!fsp->oplock_type) {
359                 DO_PROFILE_INC(writecache_non_oplock_writes);
360         }
361
362         /*
363          * If this file is level II oplocked then we need
364          * to grab the shared memory lock and inform all
365          * other files with a level II lock that they need
366          * to flush their read caches. We keep the lock over
367          * the shared memory area whilst doing this.
368          */
369
370         /* This should actually be improved to span the write. */
371         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
372         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
373
374         if (wcp && req->unread_bytes) {
375                 /* If we're using receivefile don't
376                  * deal with a write cache.
377                  */
378                 flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
379                 delete_write_cache(fsp);
380                 wcp = NULL;
381         }
382
383         if(!wcp) {
384                 DO_PROFILE_INC(writecache_direct_writes);
385                 total_written = real_write_file(req, fsp, data, pos, n);
386                 return total_written;
387         }
388
389         DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f "
390                  "wcp->data_size=%u\n", fsp_str_dbg(fsp), fsp->fh->fd,
391                  (double)pos, (unsigned int)n, (double)wcp->offset,
392                  (unsigned int)wcp->data_size));
393
394         fsp->fh->pos = pos + n;
395
396         if ((n == 1) && (data[0] == '\0') && (pos > wcp->file_size)) {
397                 int ret;
398
399                 /*
400                  * This is a 1-byte write of a 0 beyond the EOF and
401                  * thus implicitly also beyond the current active
402                  * write cache, the typical file-extending (and
403                  * allocating, but we're using the write cache here)
404                  * write done by Windows. We just have to ftruncate
405                  * the file and rely on posix semantics to return
406                  * zeros for non-written file data that is within the
407                  * file length.
408                  *
409                  * We can not use wcp_file_size_change here because we
410                  * might have an existing write cache, and
411                  * wcp_file_size_change assumes a change to just the
412                  * end of the current write cache.
413                  */
414
415                 wcp->file_size = pos + 1;
416                 ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
417                 if (ret == -1) {
418                         DEBUG(0, ("wcp_file_size_change (%s): ftruncate of "
419                                   "size %.0f error %s\n", fsp_str_dbg(fsp),
420                                   (double)wcp->file_size, strerror(errno)));
421                         return -1;
422                 }
423                 return 1;
424         }
425
426
427         /*
428          * If we have active cache and it isn't contiguous then we flush.
429          * NOTE: There is a small problem with running out of disk ....
430          */
431
432         if (wcp->data_size) {
433                 bool cache_flush_needed = False;
434
435                 if ((pos >= wcp->offset) &&
436                     (pos <= wcp->offset + wcp->data_size)) {
437
438                         /* ASCII art.... JRA.
439
440       +--------------+-----
441       | Cached data  | Rest of allocated cache buffer....
442       +--------------+-----
443
444             +-------------------+
445             | Data to write     |
446             +-------------------+
447
448                         */
449
450                         /*
451                          * Start of write overlaps or abutts the existing data.
452                          */
453
454                         size_t data_used;
455
456                         data_used = MIN((wcp->alloc_size - (pos - wcp->offset)),
457                                         n);
458
459                         memcpy(wcp->data + (pos - wcp->offset), data,
460                                data_used);
461
462                         /*
463                          * Update the current buffer size with the new data.
464                          */
465
466                         if(pos + data_used > wcp->offset + wcp->data_size) {
467                                 wcp->data_size = pos + data_used - wcp->offset;
468                         }
469
470                         /*
471                          * Update the file size if changed.
472                          */
473
474                         if (wcp->offset + wcp->data_size > wcp->file_size) {
475                                 if (wcp_file_size_change(fsp) == -1) {
476                                         return -1;
477                                 }
478                         }
479
480                         /*
481                          * If we used all the data then
482                          * return here.
483                          */
484
485                         if(n == data_used) {
486                                 return n;
487                         } else {
488                                 cache_flush_needed = True;
489                         }
490                         /*
491                          * Move the start of data forward by the amount used,
492                          * cut down the amount left by the same amount.
493                          */
494
495                         data += data_used;
496                         pos += data_used;
497                         n -= data_used;
498
499                         DO_PROFILE_INC(writecache_abutted_writes);
500                         total_written = data_used;
501
502                         write_path = 1;
503
504                 } else if ((pos < wcp->offset) &&
505                            (pos + n > wcp->offset) &&
506                            (pos + n <= wcp->offset + wcp->alloc_size)) {
507
508                         /* ASCII art.... JRA.
509
510                         +---------------+
511                         | Cache buffer  |
512                         +---------------+
513
514             +-------------------+
515             | Data to write     |
516             +-------------------+
517
518                         */
519
520                         /*
521                          * End of write overlaps the existing data.
522                          */
523
524                         size_t data_used = pos + n - wcp->offset;
525
526                         memcpy(wcp->data, data + n - data_used, data_used);
527
528                         /*
529                          * Update the current buffer size with the new data.
530                          */
531
532                         if(pos + n > wcp->offset + wcp->data_size) {
533                                 wcp->data_size = pos + n - wcp->offset;
534                         }
535
536                         /*
537                          * Update the file size if changed.
538                          */
539
540                         if (wcp->offset + wcp->data_size > wcp->file_size) {
541                                 if (wcp_file_size_change(fsp) == -1) {
542                                         return -1;
543                                 }
544                         }
545
546                         /*
547                          * We don't need to move the start of data, but we
548                          * cut down the amount left by the amount used.
549                          */
550
551                         n -= data_used;
552
553                         /*
554                          * We cannot have used all the data here.
555                          */
556
557                         cache_flush_needed = True;
558
559                         DO_PROFILE_INC(writecache_abutted_writes);
560                         total_written = data_used;
561
562                         write_path = 2;
563
564                 } else if ((pos >= wcp->file_size) &&
565                            (wcp->offset + wcp->data_size == wcp->file_size) &&
566                            (pos > wcp->offset + wcp->data_size) &&
567                            (pos < wcp->offset + wcp->alloc_size) ) {
568
569                         /* ASCII art.... JRA.
570
571                        End of file ---->|
572
573                         +---------------+---------------+
574                         | Cached data   | Cache buffer  |
575                         +---------------+---------------+
576
577                                               +-------------------+
578                                               | Data to write     |
579                                               +-------------------+
580
581                         */
582
583                         /*
584                          * Non-contiguous write part of which fits within
585                          * the cache buffer and is extending the file
586                          * and the cache contents reflect the current
587                          * data up to the current end of the file.
588                          */
589
590                         size_t data_used;
591
592                         if(pos + n <= wcp->offset + wcp->alloc_size) {
593                                 data_used = n;
594                         } else {
595                                 data_used = wcp->offset+wcp->alloc_size-pos;
596                         }
597
598                         /*
599                          * Fill in the non-continuous area with zeros.
600                          */
601
602                         memset(wcp->data + wcp->data_size, '\0',
603                                 pos - (wcp->offset + wcp->data_size) );
604
605                         memcpy(wcp->data + (pos - wcp->offset), data,
606                                data_used);
607
608                         /*
609                          * Update the current buffer size with the new data.
610                          */
611
612                         if(pos + data_used > wcp->offset + wcp->data_size) {
613                                 wcp->data_size = pos + data_used - wcp->offset;
614                         }
615
616                         /*
617                          * Update the file size if changed.
618                          */
619
620                         if (wcp->offset + wcp->data_size > wcp->file_size) {
621                                 if (wcp_file_size_change(fsp) == -1) {
622                                         return -1;
623                                 }
624                         }
625
626                         /*
627                          * If we used all the data then
628                          * return here.
629                          */
630
631                         if(n == data_used) {
632                                 return n;
633                         } else {
634                                 cache_flush_needed = True;
635                         }
636
637                         /*
638                          * Move the start of data forward by the amount used,
639                          * cut down the amount left by the same amount.
640                          */
641
642                         data += data_used;
643                         pos += data_used;
644                         n -= data_used;
645
646                         DO_PROFILE_INC(writecache_abutted_writes);
647                         total_written = data_used;
648
649                         write_path = 3;
650
651                 } else if ( (pos >= wcp->file_size) &&
652                             (n == 1) &&
653                             (wcp->file_size == wcp->offset + wcp->data_size) &&
654                             (pos < wcp->file_size + wcp->alloc_size)) {
655
656                         /*
657
658                 End of file ---->|
659
660                  +---------------+---------------+
661                  | Cached data   | Cache buffer  |
662                  +---------------+---------------+
663
664                                  |<------- allocated size ---------------->|
665
666                                                          +--------+
667                                                          | 1 Byte |
668                                                          +--------+
669
670                         MS-Office seems to do this a lot to determine if
671                         there's enough space on the filesystem to write a new
672                         file.
673
674                         Change to :
675
676                 End of file ---->|
677                                  +-----------------------+--------+
678                                  | Zeroed Cached data    | 1 Byte |
679                                  +-----------------------+--------+
680                         */
681
682                         flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
683                         wcp->offset = wcp->file_size;
684                         wcp->data_size = pos - wcp->file_size + 1;
685                         memset(wcp->data, '\0', wcp->data_size);
686                         memcpy(wcp->data + wcp->data_size-1, data, 1);
687
688                         /*
689                          * Update the file size if changed.
690                          */
691
692                         if (wcp->offset + wcp->data_size > wcp->file_size) {
693                                 if (wcp_file_size_change(fsp) == -1) {
694                                         return -1;
695                                 }
696                         }
697
698                         return n;
699
700                 } else {
701
702                         /* ASCII art..... JRA.
703
704    Case 1).
705
706                         +---------------+---------------+
707                         | Cached data   | Cache buffer  |
708                         +---------------+---------------+
709
710                                                               +---------------+
711                                                               | Data to write |
712                                                               +---------------+
713
714    Case 2).
715
716                            +---------------+---------------+
717                            | Cached data   | Cache buffer  |
718                            +---------------+---------------+
719
720    +-------------------+
721    | Data to write     |
722    +-------------------+
723
724     Case 3).
725
726                            +---------------+---------------+
727                            | Cached data   | Cache buffer  |
728                            +---------------+---------------+
729
730                   +-----------------------------------------------------+
731                   | Data to write                                       |
732                   +-----------------------------------------------------+
733
734                   */
735
736                         /*
737                          * Write is bigger than buffer, or there is no
738                          * overlap on the low or high ends.
739                          */
740
741                         DEBUG(9,("write_file: non cacheable write : fd = %d, "
742                                  "pos = %.0f, len = %u, "
743                                  "current cache pos = %.0f len = %u\n",
744                                  fsp->fh->fd, (double)pos, (unsigned int)n,
745                                  (double)wcp->offset,
746                                  (unsigned int)wcp->data_size ));
747
748                         /*
749                          * If write would fit in the cache, and is
750                          * larger than the data already in the cache,
751                          * flush the cache and preferentially copy the
752                          * data new data into it. Otherwise just write
753                          * the data directly.
754                          */
755
756                         if ( n <= wcp->alloc_size && n > wcp->data_size) {
757                                 cache_flush_needed = True;
758                         } else {
759                                 ssize_t ret = real_write_file(NULL, fsp, data,
760                                                               pos, n);
761
762                                 /*
763                                  * If the write overlaps the entire
764                                  * cache, then discard the current
765                                  * contents of the cache.  Fix from
766                                  * Rasmus Borup Hansen rbh@math.ku.dk.
767                                  */
768
769                                 if ((pos <= wcp->offset) &&
770                                     (pos + n >= wcp->offset+wcp->data_size)) {
771                                         DEBUG(9,("write_file: discarding "
772                                                  "overwritten write cache: "
773                                                  "fd = %d, off=%.0f, "
774                                                  "size=%u\n", fsp->fh->fd,
775                                                  (double)wcp->offset,
776                                                  (unsigned)wcp->data_size));
777                                         wcp->data_size = 0;
778                                 }
779
780                                 DO_PROFILE_INC(writecache_direct_writes);
781                                 if (ret == -1) {
782                                         return ret;
783                                 }
784
785                                 if (pos + ret > wcp->file_size) {
786                                         wcp->file_size = pos + ret;
787                                 }
788
789                                 return ret;
790                         }
791
792                         write_path = 4;
793
794                 }
795
796                 if (cache_flush_needed) {
797                         DEBUG(3, ("SAMBA_WRITE_FLUSH:%d: due to noncontinuous "
798                                   "write: fd = %d, size = %.0f, pos = %.0f, "
799                                   "n = %u, wcp->offset=%.0f, "
800                                   "wcp->data_size=%u\n",
801                                   write_path, fsp->fh->fd,
802                                   (double)wcp->file_size, (double)pos,
803                                   (unsigned int)n, (double)wcp->offset,
804                                   (unsigned int)wcp->data_size ));
805
806                         flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
807                 }
808         }
809
810         /*
811          * If the write request is bigger than the cache
812          * size, write it all out.
813          */
814
815         if (n > wcp->alloc_size ) {
816                 ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
817                 if (ret == -1) {
818                         return -1;
819                 }
820
821                 if (pos + ret > wcp->file_size) {
822                         wcp->file_size = pos + n;
823                 }
824
825                 DO_PROFILE_INC(writecache_direct_writes);
826                 return total_written + n;
827         }
828
829         /*
830          * If there's any data left, cache it.
831          */
832
833         if (n) {
834                 DO_PROFILE_INC(writecache_cached_writes);
835                 if (wcp->data_size) {
836                         DO_PROFILE_INC(writecache_abutted_writes);
837                 } else {
838                         DO_PROFILE_INC(writecache_init_writes);
839                 }
840
841                 if ((wcp->data_size == 0)
842                     && (pos > wcp->file_size)
843                     && (pos + n <= wcp->file_size + wcp->alloc_size)) {
844                         /*
845                          * This is a write completely beyond the
846                          * current EOF, but within reach of the write
847                          * cache. We expect fill-up writes pretty
848                          * soon, so it does not make sense to start
849                          * the write cache at the current
850                          * offset. These fill-up writes would trigger
851                          * separate pwrites or even unnecessary cache
852                          * flushes because they overlap if this is a
853                          * one-byte allocating write.
854                          */
855                         wcp->offset = wcp->file_size;
856                         wcp->data_size = pos - wcp->file_size;
857                         memset(wcp->data, 0, wcp->data_size);
858                 }
859
860                 memcpy(wcp->data+wcp->data_size, data, n);
861                 if (wcp->data_size == 0) {
862                         wcp->offset = pos;
863                 }
864                 wcp->data_size += n;
865
866                 /*
867                  * Update the file size if changed.
868                  */
869
870                 if (wcp->offset + wcp->data_size > wcp->file_size) {
871                         if (wcp_file_size_change(fsp) == -1) {
872                                 return -1;
873                         }
874                 }
875                 DEBUG(9, ("wcp->offset = %.0f wcp->data_size = %u cache "
876                           "return %u\n",
877                           (double)wcp->offset, (unsigned int)wcp->data_size,
878                           (unsigned int)n));
879
880                 total_written += n;
881                 return total_written; /* .... that's a write :) */
882         }
883
884         return total_written;
885 }
886
887 /****************************************************************************
888  Delete the write cache structure.
889 ****************************************************************************/
890
891 void delete_write_cache(files_struct *fsp)
892 {
893         struct write_cache *wcp;
894
895         if(!fsp) {
896                 return;
897         }
898
899         if(!(wcp = fsp->wcp)) {
900                 return;
901         }
902
903         DO_PROFILE_INC(writecache_deallocations);
904         allocated_write_caches--;
905
906         SMB_ASSERT(wcp->data_size == 0);
907
908         SAFE_FREE(wcp->data);
909         SAFE_FREE(fsp->wcp);
910
911         DEBUG(10,("delete_write_cache: File %s deleted write cache\n",
912                   fsp_str_dbg(fsp)));
913 }
914
915 /****************************************************************************
916  Setup the write cache structure.
917 ****************************************************************************/
918
919 static bool setup_write_cache(files_struct *fsp, off_t file_size)
920 {
921         ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
922         struct write_cache *wcp;
923
924         if (allocated_write_caches >= MAX_WRITE_CACHES) {
925                 return False;
926         }
927
928         if(alloc_size == 0 || fsp->wcp) {
929                 return False;
930         }
931
932         if((wcp = SMB_MALLOC_P(struct write_cache)) == NULL) {
933                 DEBUG(0,("setup_write_cache: malloc fail.\n"));
934                 return False;
935         }
936
937         wcp->file_size = file_size;
938         wcp->offset = 0;
939         wcp->alloc_size = alloc_size;
940         wcp->data_size = 0;
941         if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) {
942                 DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
943                         (unsigned int)wcp->alloc_size ));
944                 SAFE_FREE(wcp);
945                 return False;
946         }
947
948         memset(wcp->data, '\0', wcp->alloc_size );
949
950         fsp->wcp = wcp;
951         DO_PROFILE_INC(writecache_allocations);
952         allocated_write_caches++;
953
954         DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n",
955                   fsp_str_dbg(fsp), (unsigned long)wcp->alloc_size));
956
957         return True;
958 }
959
960 /****************************************************************************
961  Cope with a size change.
962 ****************************************************************************/
963
964 void set_filelen_write_cache(files_struct *fsp, off_t file_size)
965 {
966         if(fsp->wcp) {
967                 /* The cache *must* have been flushed before we do this. */
968                 if (fsp->wcp->data_size != 0) {
969                         char *msg;
970                         if (asprintf(&msg, "set_filelen_write_cache: size change "
971                                  "on file %s with write cache size = %lu\n",
972                                  fsp->fsp_name->base_name,
973                                  (unsigned long)fsp->wcp->data_size) != -1) {
974                                 smb_panic(msg);
975                         } else {
976                                 smb_panic("set_filelen_write_cache");
977                         }
978                 }
979                 fsp->wcp->file_size = file_size;
980         }
981 }
982
983 /*******************************************************************
984  Flush a write cache struct to disk.
985 ********************************************************************/
986
987 ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
988 {
989         struct write_cache *wcp = fsp->wcp;
990         size_t data_size;
991         ssize_t ret;
992
993         if(!wcp || !wcp->data_size) {
994                 return 0;
995         }
996
997         data_size = wcp->data_size;
998         wcp->data_size = 0;
999
1000         switch (reason) {
1001         case SAMBA_SEEK_FLUSH:
1002                 DO_PROFILE_INC(writecache_flush_reason_seek);
1003                 break;
1004         case SAMBA_READ_FLUSH:
1005                 DO_PROFILE_INC(writecache_flush_reason_read);
1006                 break;
1007         case SAMBA_WRITE_FLUSH:
1008                 DO_PROFILE_INC(writecache_flush_reason_write);;
1009                 break;
1010         case SAMBA_READRAW_FLUSH:
1011                 DO_PROFILE_INC(writecache_flush_reason_readraw);
1012                 break;
1013         case SAMBA_OPLOCK_RELEASE_FLUSH:
1014                 DO_PROFILE_INC(writecache_flush_reason_oplock);
1015                 break;
1016         case SAMBA_CLOSE_FLUSH:
1017                 DO_PROFILE_INC(writecache_flush_reason_close);
1018                 break;
1019         case SAMBA_SYNC_FLUSH:
1020                 DO_PROFILE_INC(writecache_flush_reason_sync);
1021                 break;
1022         case SAMBA_SIZECHANGE_FLUSH:
1023                 DO_PROFILE_INC(writecache_flush_reason_sizechange);
1024                 break;
1025         default:
1026                 break;
1027         }
1028
1029         DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
1030                 fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size));
1031
1032         if(data_size == wcp->alloc_size) {
1033                 DO_PROFILE_INC(writecache_perfect_writes);
1034         }
1035
1036         ret = real_write_file(NULL, fsp, wcp->data, wcp->offset, data_size);
1037
1038         /*
1039          * Ensure file size if kept up to date if write extends file.
1040          */
1041
1042         if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) {
1043                 wcp->file_size = wcp->offset + ret;
1044         }
1045
1046         return ret;
1047 }
1048
1049 /*******************************************************************
1050 sync a file
1051 ********************************************************************/
1052
1053 NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through)
1054 {
1055         if (fsp->fh->fd == -1)
1056                 return NT_STATUS_INVALID_HANDLE;
1057
1058         if (lp_strict_sync(SNUM(conn)) &&
1059             (lp_sync_always(SNUM(conn)) || write_through)) {
1060                 int ret = flush_write_cache(fsp, SAMBA_SYNC_FLUSH);
1061                 if (ret == -1) {
1062                         return map_nt_error_from_unix(errno);
1063                 }
1064                 ret = smb_vfs_fsync_sync(fsp);
1065                 if (ret == -1) {
1066                         return map_nt_error_from_unix(errno);
1067                 }
1068         }
1069         return NT_STATUS_OK;
1070 }