smbd: Remove write cache
[amitay/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 /****************************************************************************
29  Read from a file.
30 ****************************************************************************/
31
32 ssize_t read_file(files_struct *fsp,char *data,off_t pos,size_t n)
33 {
34         ssize_t ret = 0;
35
36         /* you can't read from print files */
37         if (fsp->print_file) {
38                 errno = EBADF;
39                 return -1;
40         }
41
42         fsp->fh->pos = pos;
43
44         if (n > 0) {
45                 ret = SMB_VFS_PREAD(fsp,data,n,pos);
46
47                 if (ret == -1) {
48                         return -1;
49                 }
50         }
51
52         DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
53                   fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
54
55         fsp->fh->pos += ret;
56         fsp->fh->position_information = fsp->fh->pos;
57
58         return(ret);
59 }
60
61 /****************************************************************************
62  *Really* write to a file.
63 ****************************************************************************/
64
65 static ssize_t real_write_file(struct smb_request *req,
66                                 files_struct *fsp,
67                                 const char *data,
68                                 off_t pos,
69                                 size_t n)
70 {
71         ssize_t ret;
72
73         fsp->fh->pos = pos;
74         if (pos && lp_strict_allocate(SNUM(fsp->conn) &&
75                         !fsp->is_sparse)) {
76                 if (vfs_fill_sparse(fsp, pos) == -1) {
77                         return -1;
78                 }
79         }
80         ret = vfs_pwrite_data(req, fsp, data, n, pos);
81
82         DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
83                   fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
84
85         if (ret != -1) {
86                 fsp->fh->pos += ret;
87
88 /* Yes - this is correct - writes don't update this. JRA. */
89 /* Found by Samba4 tests. */
90 #if 0
91                 fsp->position_information = fsp->pos;
92 #endif
93         }
94
95         return ret;
96 }
97
98 void fsp_flush_write_time_update(struct files_struct *fsp)
99 {
100         /*
101          * Note this won't expect any impersonation!
102          * So don't call any SMB_VFS operations here!
103          */
104
105         DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
106
107         /* change the write time in the open file db. */
108         (void)set_write_time(fsp->file_id, timespec_current());
109
110         /* And notify. */
111         notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
112                      FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name);
113
114         /* Remove the timed event handler. */
115         TALLOC_FREE(fsp->update_write_time_event);
116 }
117
118 static void update_write_time_handler(struct tevent_context *ctx,
119                                       struct tevent_timer *te,
120                                       struct timeval now,
121                                       void *private_data)
122 {
123         files_struct *fsp = (files_struct *)private_data;
124         fsp_flush_write_time_update(fsp);
125 }
126
127 /*********************************************************
128  Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
129  in the future.
130 *********************************************************/
131
132 void trigger_write_time_update(struct files_struct *fsp)
133 {
134         int delay;
135
136         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
137                 /* Don't use delayed writes on POSIX files. */
138                 return;
139         }
140
141         if (fsp->write_time_forced) {
142                 /* No point - "sticky" write times
143                  * in effect.
144                  */
145                 return;
146         }
147
148         /* We need to remember someone did a write
149          * and update to current time on close. */
150
151         fsp->update_write_time_on_close = true;
152
153         if (fsp->update_write_time_triggered) {
154                 /*
155                  * We only update the write time after 2 seconds
156                  * on the first normal write. After that
157                  * no other writes affect this until close.
158                  */
159                 return;
160         }
161         fsp->update_write_time_triggered = true;
162
163         delay = lp_parm_int(SNUM(fsp->conn),
164                             "smbd", "writetimeupdatedelay",
165                             WRITE_TIME_UPDATE_USEC_DELAY);
166
167         DEBUG(5, ("Update write time %d usec later on %s\n",
168                   delay, fsp_str_dbg(fsp)));
169
170         /* trigger the update 2 seconds later */
171         fsp->update_write_time_event =
172                 tevent_add_timer(fsp->conn->sconn->ev_ctx, NULL,
173                                  timeval_current_ofs_usec(delay),
174                                  update_write_time_handler, fsp);
175 }
176
177 void trigger_write_time_update_immediate(struct files_struct *fsp)
178 {
179         struct smb_file_time ft;
180
181         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
182                 /* Don't use delayed writes on POSIX files. */
183                 return;
184         }
185
186         if (fsp->write_time_forced) {
187                 /*
188                  * No point - "sticky" write times
189                  * in effect.
190                  */
191                 return;
192         }
193
194         TALLOC_FREE(fsp->update_write_time_event);
195         DEBUG(5, ("Update write time immediate on %s\n",
196                   fsp_str_dbg(fsp)));
197
198         /* After an immediate update, reset the trigger. */
199         fsp->update_write_time_triggered = true;
200         fsp->update_write_time_on_close = false;
201
202         ft = (struct smb_file_time) { .mtime = timespec_current() };
203
204         /* Update the time in the open file db. */
205         (void)set_write_time(fsp->file_id, ft.mtime);
206
207         /* Now set on disk - takes care of notify. */
208         (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
209 }
210
211 void mark_file_modified(files_struct *fsp)
212 {
213         int dosmode;
214
215         if (fsp->modified) {
216                 return;
217         }
218
219         fsp->modified = true;
220
221         if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
222                 return;
223         }
224         trigger_write_time_update(fsp);
225
226         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
227                 return;
228         }
229         if (!(lp_store_dos_attributes(SNUM(fsp->conn)) ||
230               MAP_ARCHIVE(fsp->conn))) {
231                 return;
232         }
233
234         dosmode = dos_mode(fsp->conn, fsp->fsp_name);
235         if (IS_DOS_ARCHIVE(dosmode)) {
236                 return;
237         }
238         file_set_dosmode(fsp->conn, fsp->fsp_name,
239                          dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
240 }
241
242 /****************************************************************************
243  Write to a file.
244 ****************************************************************************/
245
246 ssize_t write_file(struct smb_request *req,
247                         files_struct *fsp,
248                         const char *data,
249                         off_t pos,
250                         size_t n)
251 {
252         ssize_t total_written = 0;
253
254         if (fsp->print_file) {
255                 uint32_t t;
256                 int ret;
257
258                 ret = print_spool_write(fsp, data, n, pos, &t);
259                 if (ret) {
260                         errno = ret;
261                         return -1;
262                 }
263                 return t;
264         }
265
266         if (!fsp->can_write) {
267                 errno = EPERM;
268                 return -1;
269         }
270
271         mark_file_modified(fsp);
272
273         /*
274          * If this file is level II oplocked then we need
275          * to grab the shared memory lock and inform all
276          * other files with a level II lock that they need
277          * to flush their read caches. We keep the lock over
278          * the shared memory area whilst doing this.
279          */
280
281         /* This should actually be improved to span the write. */
282         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
283         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
284
285         total_written = real_write_file(req, fsp, data, pos, n);
286         return total_written;
287 }
288
289 /*******************************************************************
290 sync a file
291 ********************************************************************/
292
293 NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through)
294 {
295         if (fsp->fh->fd == -1)
296                 return NT_STATUS_INVALID_HANDLE;
297
298         if (lp_strict_sync(SNUM(conn)) &&
299             (lp_sync_always(SNUM(conn)) || write_through)) {
300                 int ret;
301                 ret = smb_vfs_fsync_sync(fsp);
302                 if (ret == -1) {
303                         return map_nt_error_from_unix(errno);
304                 }
305         }
306         return NT_STATUS_OK;
307 }