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