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