smbd: add vfs_valid_{pread,pwrite}_range() checks where needed
[Samba.git] / source3 / smbd / fileio.c
blob000a01e2c0f0b8e2b520be22dac679b5fe3f146b
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.
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.
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.
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/>.
22 #include "includes.h"
23 #include "printing.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "smbprofile.h"
28 /****************************************************************************
29 Read from a file.
30 ****************************************************************************/
32 ssize_t read_file(files_struct *fsp,char *data,off_t pos,size_t n)
34 ssize_t ret = 0;
35 bool ok;
37 /* you can't read from print files */
38 if (fsp->print_file) {
39 errno = EBADF;
40 return -1;
43 ok = vfs_valid_pread_range(pos, n);
44 if (!ok) {
45 errno = EINVAL;
46 return -1;
49 fsp->fh->pos = pos;
51 if (n > 0) {
52 ret = SMB_VFS_PREAD(fsp,data,n,pos);
54 if (ret == -1) {
55 return -1;
59 DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
60 fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
62 fsp->fh->pos += ret;
63 fsp->fh->position_information = fsp->fh->pos;
65 return(ret);
68 /****************************************************************************
69 *Really* write to a file.
70 ****************************************************************************/
72 static ssize_t real_write_file(struct smb_request *req,
73 files_struct *fsp,
74 const char *data,
75 off_t pos,
76 size_t n)
78 ssize_t ret;
79 bool ok;
81 ok = vfs_valid_pwrite_range(pos, n);
82 if (!ok) {
83 errno = EINVAL;
84 return -1;
87 if (n == 0) {
88 return 0;
91 fsp->fh->pos = pos;
92 if (pos && lp_strict_allocate(SNUM(fsp->conn) &&
93 !fsp->is_sparse)) {
94 if (vfs_fill_sparse(fsp, pos) == -1) {
95 return -1;
98 ret = vfs_pwrite_data(req, fsp, data, n, pos);
100 DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
101 fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
103 if (ret != -1) {
104 fsp->fh->pos += ret;
106 /* Yes - this is correct - writes don't update this. JRA. */
107 /* Found by Samba4 tests. */
108 #if 0
109 fsp->position_information = fsp->pos;
110 #endif
113 return ret;
116 void fsp_flush_write_time_update(struct files_struct *fsp)
119 * Note this won't expect any impersonation!
120 * So don't call any SMB_VFS operations here!
123 DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
125 trigger_write_time_update_immediate(fsp);
128 static void update_write_time_handler(struct tevent_context *ctx,
129 struct tevent_timer *te,
130 struct timeval now,
131 void *private_data)
133 files_struct *fsp = (files_struct *)private_data;
134 fsp_flush_write_time_update(fsp);
137 /*********************************************************
138 Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
139 in the future.
140 *********************************************************/
142 void trigger_write_time_update(struct files_struct *fsp)
144 int delay;
146 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
147 /* Don't use delayed writes on POSIX files. */
148 return;
151 if (fsp->write_time_forced) {
152 /* No point - "sticky" write times
153 * in effect.
155 return;
158 /* We need to remember someone did a write
159 * and update to current time on close. */
161 fsp->update_write_time_on_close = true;
163 if (fsp->update_write_time_triggered) {
165 * We only update the write time after 2 seconds
166 * on the first normal write. After that
167 * no other writes affect this until close.
169 return;
171 fsp->update_write_time_triggered = true;
173 delay = lp_parm_int(SNUM(fsp->conn),
174 "smbd", "writetimeupdatedelay",
175 WRITE_TIME_UPDATE_USEC_DELAY);
177 DEBUG(5, ("Update write time %d usec later on %s\n",
178 delay, fsp_str_dbg(fsp)));
180 /* trigger the update 2 seconds later */
181 fsp->update_write_time_event =
182 tevent_add_timer(fsp->conn->sconn->ev_ctx, NULL,
183 timeval_current_ofs_usec(delay),
184 update_write_time_handler, fsp);
187 void trigger_write_time_update_immediate(struct files_struct *fsp)
189 struct smb_file_time ft;
191 init_smb_file_time(&ft);
193 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
194 /* Don't use delayed writes on POSIX files. */
195 return;
198 if (fsp->write_time_forced) {
200 * No point - "sticky" write times
201 * in effect.
203 return;
206 TALLOC_FREE(fsp->update_write_time_event);
207 DEBUG(5, ("Update write time immediate on %s\n",
208 fsp_str_dbg(fsp)));
210 /* After an immediate update, reset the trigger. */
211 fsp->update_write_time_triggered = true;
212 fsp->update_write_time_on_close = false;
214 ft.mtime = timespec_current();
216 /* Update the time in the open file db. */
217 (void)set_write_time(fsp->file_id, ft.mtime);
219 /* Now set on disk - takes care of notify. */
220 (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
223 void mark_file_modified(files_struct *fsp)
225 int dosmode;
227 trigger_write_time_update(fsp);
229 if (fsp->modified) {
230 return;
233 fsp->modified = true;
235 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
236 return;
238 if (!(lp_store_dos_attributes(SNUM(fsp->conn)) ||
239 MAP_ARCHIVE(fsp->conn))) {
240 return;
243 dosmode = dos_mode(fsp->conn, fsp->fsp_name);
244 if (IS_DOS_ARCHIVE(dosmode)) {
245 return;
247 file_set_dosmode(fsp->conn, fsp->fsp_name,
248 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
251 /****************************************************************************
252 Write to a file.
253 ****************************************************************************/
255 ssize_t write_file(struct smb_request *req,
256 files_struct *fsp,
257 const char *data,
258 off_t pos,
259 size_t n)
261 ssize_t total_written = 0;
263 if (fsp->print_file) {
264 uint32_t t;
265 int ret;
267 ret = print_spool_write(fsp, data, n, pos, &t);
268 if (ret) {
269 errno = ret;
270 return -1;
272 return t;
275 if (!fsp->can_write) {
276 errno = EPERM;
277 return -1;
280 mark_file_modified(fsp);
283 * If this file is level II oplocked then we need
284 * to grab the shared memory lock and inform all
285 * other files with a level II lock that they need
286 * to flush their read caches. We keep the lock over
287 * the shared memory area whilst doing this.
290 /* This should actually be improved to span the write. */
291 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
292 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
294 total_written = real_write_file(req, fsp, data, pos, n);
295 return total_written;
298 /*******************************************************************
299 sync a file
300 ********************************************************************/
302 NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through)
304 if (fsp->fh->fd == -1)
305 return NT_STATUS_INVALID_HANDLE;
307 if (lp_strict_sync(SNUM(conn)) &&
308 (lp_sync_always(SNUM(conn)) || write_through)) {
309 int ret;
310 ret = smb_vfs_fsync_sync(fsp);
311 if (ret == -1) {
312 return map_nt_error_from_unix(errno);
315 return NT_STATUS_OK;