tests: Check symlinks are readable as reparse points
[samba.git] / source3 / smbd / fileio.c
blobfc6668e41866fa82d826d01ff15c22bb2477460d
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 off_t new_pos;
35 ssize_t ret = 0;
36 bool ok;
38 /* you can't read from print files */
39 if (fsp->print_file) {
40 errno = EBADF;
41 return -1;
44 ok = vfs_valid_pread_range(pos, n);
45 if (!ok) {
46 errno = EINVAL;
47 return -1;
50 fh_set_pos(fsp->fh, pos);
52 if (n > 0) {
53 ret = SMB_VFS_PREAD(fsp,data,n,pos);
55 if (ret == -1) {
56 return -1;
60 DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
61 fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));
63 new_pos = fh_get_pos(fsp->fh) + ret;
64 fh_set_pos(fsp->fh, new_pos);
65 fh_set_position_information(fsp->fh, new_pos);
67 return(ret);
70 /****************************************************************************
71 *Really* write to a file.
72 ****************************************************************************/
74 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)
80 ssize_t ret;
81 bool ok;
83 ok = vfs_valid_pwrite_range(pos, n);
84 if (!ok) {
85 errno = EINVAL;
86 return -1;
89 if (n == 0) {
90 return 0;
93 fh_set_pos(fsp->fh, pos);
94 if (pos &&
95 lp_strict_allocate(SNUM(fsp->conn)) &&
96 !fsp->fsp_flags.is_sparse)
98 if (vfs_fill_sparse(fsp, pos) == -1) {
99 return -1;
102 ret = vfs_pwrite_data(req, fsp, data, n, pos);
104 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));
107 if (ret != -1) {
108 off_t new_pos = fh_get_pos(fsp->fh) + ret;
109 fh_set_pos(fsp->fh, new_pos);
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
118 return ret;
121 void fsp_flush_write_time_update(struct files_struct *fsp)
124 * Note this won't expect any impersonation!
125 * So don't call any SMB_VFS operations here!
128 DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
130 trigger_write_time_update_immediate(fsp);
133 static void update_write_time_handler(struct tevent_context *ctx,
134 struct tevent_timer *te,
135 struct timeval now,
136 void *private_data)
138 files_struct *fsp = (files_struct *)private_data;
139 fsp_flush_write_time_update(fsp);
142 /*********************************************************
143 Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
144 in the future.
145 *********************************************************/
147 void trigger_write_time_update(struct files_struct *fsp)
149 int delay;
151 if (fsp->fsp_flags.posix_open) {
152 /* Don't use delayed writes on POSIX files. */
153 return;
156 if (fsp->fsp_flags.write_time_forced) {
157 /* No point - "sticky" write times
158 * in effect.
160 return;
163 /* We need to remember someone did a write
164 * and update to current time on close. */
166 fsp->fsp_flags.update_write_time_on_close = true;
168 if (fsp->fsp_flags.update_write_time_triggered) {
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.
174 return;
176 fsp->fsp_flags.update_write_time_triggered = true;
178 delay = lp_parm_int(SNUM(fsp->conn),
179 "smbd", "writetimeupdatedelay",
180 WRITE_TIME_UPDATE_USEC_DELAY);
182 DEBUG(5, ("Update write time %d usec later on %s\n",
183 delay, fsp_str_dbg(fsp)));
185 /* trigger the update 2 seconds later */
186 fsp->update_write_time_event =
187 tevent_add_timer(fsp->conn->sconn->ev_ctx, NULL,
188 timeval_current_ofs_usec(delay),
189 update_write_time_handler, fsp);
192 void trigger_write_time_update_immediate(struct files_struct *fsp)
194 struct smb_file_time ft;
196 init_smb_file_time(&ft);
198 if (fsp->fsp_flags.posix_open) {
199 /* Don't use delayed writes on POSIX files. */
200 return;
203 if (fsp->fsp_flags.write_time_forced) {
205 * No point - "sticky" write times
206 * in effect.
208 return;
211 TALLOC_FREE(fsp->update_write_time_event);
212 DEBUG(5, ("Update write time immediate on %s\n",
213 fsp_str_dbg(fsp)));
215 /* After an immediate update, reset the trigger. */
216 fsp->fsp_flags.update_write_time_triggered = true;
217 fsp->fsp_flags.update_write_time_on_close = false;
219 ft.mtime = timespec_current();
221 /* Update the time in the open file db. */
222 (void)set_write_time(fsp->file_id, ft.mtime);
224 /* Now set on disk - takes care of notify. */
225 (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
228 void mark_file_modified(files_struct *fsp)
230 int dosmode;
232 trigger_write_time_update(fsp);
234 if (fsp->fsp_flags.modified) {
235 return;
238 fsp->fsp_flags.modified = true;
240 if (!(lp_store_dos_attributes(SNUM(fsp->conn)) ||
241 MAP_ARCHIVE(fsp->conn))) {
242 return;
245 dosmode = fdos_mode(fsp);
246 if (dosmode & FILE_ATTRIBUTE_ARCHIVE) {
247 return;
249 file_set_dosmode(fsp->conn, fsp->fsp_name,
250 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
253 /****************************************************************************
254 Write to a file.
255 ****************************************************************************/
257 ssize_t write_file(struct smb_request *req,
258 files_struct *fsp,
259 const char *data,
260 off_t pos,
261 size_t n)
263 ssize_t total_written = 0;
265 if (fsp->print_file) {
266 uint32_t t;
267 int ret;
269 ret = print_spool_write(fsp, data, n, pos, &t);
270 if (ret) {
271 errno = ret;
272 return -1;
274 return t;
277 if (!fsp->fsp_flags.can_write) {
278 errno = EPERM;
279 return -1;
282 mark_file_modified(fsp);
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.
292 /* This should actually be improved to span the write. */
293 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
294 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
296 total_written = real_write_file(req, fsp, data, pos, n);
297 return total_written;
300 /*******************************************************************
301 sync a file
302 ********************************************************************/
304 NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through)
306 if (fsp_get_io_fd(fsp) == -1)
307 return NT_STATUS_INVALID_HANDLE;
309 if (lp_strict_sync(SNUM(conn)) &&
310 (lp_sync_always(SNUM(conn)) || write_through)) {
311 int ret;
312 ret = smb_vfs_fsync_sync(fsp);
313 if (ret == -1) {
314 return map_nt_error_from_unix(errno);
317 return NT_STATUS_OK;