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