source: branches/samba-3.2.x/source/smbd/dosmode.c@ 233

Last change on this file since 233 was 233, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.9

File size: 19.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22
23static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
24{
25#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
26 if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
27 return FILE_ATTRIBUTE_SPARSE;
28 }
29#endif
30 return 0;
31}
32
33/****************************************************************************
34 Change a dos mode to a unix mode.
35 Base permission for files:
36 if creating file and inheriting (i.e. parent_dir != NULL)
37 apply read/write bits from parent directory.
38 else
39 everybody gets read bit set
40 dos readonly is represented in unix by removing everyone's write bit
41 dos archive is represented in unix by the user's execute bit
42 dos system is represented in unix by the group's execute bit
43 dos hidden is represented in unix by the other's execute bit
44 if !inheriting {
45 Then apply create mask,
46 then add force bits.
47 }
48 Base permission for directories:
49 dos directory is represented in unix by unix's dir bit and the exec bit
50 if !inheriting {
51 Then apply create mask,
52 then add force bits.
53 }
54****************************************************************************/
55
56mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
57 const char *inherit_from_dir)
58{
59 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
60 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
61 * inheriting. */
62
63 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
64 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
65 }
66
67 if (fname && (inherit_from_dir != NULL)
68 && lp_inherit_perms(SNUM(conn))) {
69 SMB_STRUCT_STAT sbuf;
70
71 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
72 inherit_from_dir));
73 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
74 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
75 inherit_from_dir, strerror(errno)));
76 return(0); /* *** shouldn't happen! *** */
77 }
78
79 /* Save for later - but explicitly remove setuid bit for safety. */
80 dir_mode = sbuf.st_mode & ~S_ISUID;
81 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
82 /* Clear "result" */
83 result = 0;
84 }
85
86 if (IS_DOS_DIR(dosmode)) {
87 /* We never make directories read only for the owner as under DOS a user
88 can always create a file in a read-only directory. */
89 result |= (S_IFDIR | S_IWUSR);
90
91 if (dir_mode) {
92 /* Inherit mode of parent directory. */
93 result |= dir_mode;
94 } else {
95 /* Provisionally add all 'x' bits */
96 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
97
98 /* Apply directory mask */
99 result &= lp_dir_mask(SNUM(conn));
100 /* Add in force bits */
101 result |= lp_force_dir_mode(SNUM(conn));
102 }
103 } else {
104 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
105 result |= S_IXUSR;
106
107 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
108 result |= S_IXGRP;
109
110 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
111 result |= S_IXOTH;
112
113 if (dir_mode) {
114 /* Inherit 666 component of parent directory mode */
115 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
116 } else {
117 /* Apply mode mask */
118 result &= lp_create_mask(SNUM(conn));
119 /* Add in force bits */
120 result |= lp_force_create_mode(SNUM(conn));
121 }
122 }
123
124 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
125 return(result);
126}
127
128/****************************************************************************
129 Change a unix mode to a dos mode.
130****************************************************************************/
131
132static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
133{
134 int result = 0;
135 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
136
137 if (ro_opts == MAP_READONLY_YES) {
138 /* Original Samba method - map inverse of user "w" bit. */
139#ifndef __OS2__x
140 if ((sbuf->st_mode & S_IWUSR) == 0) {
141#else
142 if(os2_isattribute(path,aRONLY)==0) {
143#endif
144 result |= aRONLY;
145 }
146 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
147 /* Check actual permissions for read-only. */
148 if (!can_write_to_file(conn, path, sbuf)) {
149 result |= aRONLY;
150 }
151 } /* Else never set the readonly bit. */
152
153#ifndef __OS2__x
154 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
155#else
156 if(os2_isattribute(path,aARCH)==0)
157#endif
158 result |= aARCH;
159
160#ifndef __OS2__x
161 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
162#else
163 if(os2_isattribute(path,aSYSTEM)==0)
164#endif
165 result |= aSYSTEM;
166
167#ifndef __OS2__x
168 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
169#else
170 if(os2_isattribute(path,aHIDDEN)==0)
171#endif
172
173 if (S_ISDIR(sbuf->st_mode))
174 result = aDIR | (result & aRONLY);
175
176 result |= set_sparse_flag(sbuf);
177
178#ifdef S_ISLNK
179#if LINKS_READ_ONLY
180 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
181 result |= aRONLY;
182#endif
183#endif
184
185 DEBUG(8,("dos_mode_from_sbuf returning "));
186
187 if (result & aHIDDEN) DEBUG(8, ("h"));
188 if (result & aRONLY ) DEBUG(8, ("r"));
189 if (result & aSYSTEM) DEBUG(8, ("s"));
190 if (result & aDIR ) DEBUG(8, ("d"));
191 if (result & aARCH ) DEBUG(8, ("a"));
192
193 DEBUG(8,("\n"));
194 return result;
195}
196
197/****************************************************************************
198 Get DOS attributes from an EA.
199****************************************************************************/
200
201static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
202{
203 ssize_t sizeret;
204 fstring attrstr;
205 unsigned int dosattr;
206
207 if (!lp_store_dos_attributes(SNUM(conn))) {
208 return False;
209 }
210
211 /* Don't reset pattr to zero as we may already have filename-based attributes we
212 need to preserve. */
213
214 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
215 if (sizeret == -1) {
216 if (errno == ENOSYS
217#if defined(ENOTSUP)
218 || errno == ENOTSUP) {
219#else
220 ) {
221#endif
222 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
223 path, strerror(errno) ));
224 set_store_dos_attributes(SNUM(conn), False);
225 }
226 return False;
227 }
228 /* Null terminate string. */
229 attrstr[sizeret] = 0;
230 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
231
232 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
233 sscanf(attrstr, "%x", &dosattr) != 1) {
234 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
235 return False;
236 }
237
238 if (S_ISDIR(sbuf->st_mode)) {
239 dosattr |= aDIR;
240 }
241 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
242
243 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
244
245 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
246 if (dosattr & aRONLY ) DEBUG(8, ("r"));
247 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
248 if (dosattr & aDIR ) DEBUG(8, ("d"));
249 if (dosattr & aARCH ) DEBUG(8, ("a"));
250
251 DEBUG(8,("\n"));
252
253 return True;
254}
255
256/****************************************************************************
257 Set DOS attributes in an EA.
258****************************************************************************/
259
260static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
261{
262 fstring attrstr;
263 files_struct *fsp = NULL;
264 bool ret = False;
265
266 if (!lp_store_dos_attributes(SNUM(conn))) {
267 return False;
268 }
269
270 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
271 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
272 if((errno != EPERM) && (errno != EACCES)) {
273 if (errno == ENOSYS
274#if defined(ENOTSUP)
275 || errno == ENOTSUP) {
276#else
277 ) {
278#endif
279 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
280 path, strerror(errno) ));
281 set_store_dos_attributes(SNUM(conn), False);
282 }
283 return False;
284 }
285
286 /* We want DOS semantics, ie allow non owner with write permission to change the
287 bits on a file. Just like file_ntimes below.
288 */
289
290 /* Check if we have write access. */
291 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
292 return False;
293
294 /*
295 * We need to open the file with write access whilst
296 * still in our current user context. This ensures we
297 * are not violating security in doing the setxattr.
298 */
299
300 if (!NT_STATUS_IS_OK(open_file_fchmod(conn,path,sbuf,&fsp)))
301 return ret;
302 become_root();
303 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
304 ret = True;
305 }
306 unbecome_root();
307 close_file_fchmod(fsp);
308 return ret;
309 }
310 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
311 return True;
312}
313
314/****************************************************************************
315 Change a unix mode to a dos mode for an ms dfs link.
316****************************************************************************/
317
318uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
319{
320 uint32 result = 0;
321
322 DEBUG(8,("dos_mode_msdfs: %s\n", path));
323
324 if (!VALID_STAT(*sbuf)) {
325 return 0;
326 }
327
328 /* First do any modifications that depend on the path name. */
329 /* hide files with a name starting with a . */
330 if (lp_hide_dot_files(SNUM(conn))) {
331 const char *p = strrchr_m(path,'/');
332 if (p) {
333 p++;
334 } else {
335 p = path;
336 }
337
338 /* Only . and .. are not hidden. */
339 if (p[0] == '.' && !((p[1] == '\0') ||
340 (p[1] == '.' && p[2] == '\0'))) {
341 result |= aHIDDEN;
342 }
343 }
344
345 result |= dos_mode_from_sbuf(conn, path, sbuf);
346
347 /* Optimization : Only call is_hidden_path if it's not already
348 hidden. */
349 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
350 result |= aHIDDEN;
351 }
352
353 DEBUG(8,("dos_mode_msdfs returning "));
354
355 if (result & aHIDDEN) DEBUG(8, ("h"));
356 if (result & aRONLY ) DEBUG(8, ("r"));
357 if (result & aSYSTEM) DEBUG(8, ("s"));
358 if (result & aDIR ) DEBUG(8, ("d"));
359 if (result & aARCH ) DEBUG(8, ("a"));
360 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
361
362 DEBUG(8,("\n"));
363
364 return(result);
365}
366
367/****************************************************************************
368 Change a unix mode to a dos mode.
369****************************************************************************/
370
371uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
372{
373 uint32 result = 0;
374 bool offline;
375
376 DEBUG(8,("dos_mode: %s\n", path));
377
378 if (!VALID_STAT(*sbuf)) {
379 return 0;
380 }
381
382 /* First do any modifications that depend on the path name. */
383 /* hide files with a name starting with a . */
384 if (lp_hide_dot_files(SNUM(conn))) {
385 const char *p = strrchr_m(path,'/');
386 if (p) {
387 p++;
388 } else {
389 p = path;
390 }
391
392 /* Only . and .. are not hidden. */
393 if (p[0] == '.' && !((p[1] == '\0') ||
394 (p[1] == '.' && p[2] == '\0'))) {
395 result |= aHIDDEN;
396 }
397 }
398
399 /* Get the DOS attributes from an EA by preference. */
400 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
401 result |= set_sparse_flag(sbuf);
402 } else {
403 result |= dos_mode_from_sbuf(conn, path, sbuf);
404 }
405
406
407 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
408 if (S_ISREG(sbuf->st_mode) && offline) {
409 result |= FILE_ATTRIBUTE_OFFLINE;
410 }
411
412 /* Optimization : Only call is_hidden_path if it's not already
413 hidden. */
414 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
415 result |= aHIDDEN;
416 }
417
418 DEBUG(8,("dos_mode returning "));
419
420 if (result & aHIDDEN) DEBUG(8, ("h"));
421 if (result & aRONLY ) DEBUG(8, ("r"));
422 if (result & aSYSTEM) DEBUG(8, ("s"));
423 if (result & aDIR ) DEBUG(8, ("d"));
424 if (result & aARCH ) DEBUG(8, ("a"));
425 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
426
427 DEBUG(8,("\n"));
428
429 return(result);
430}
431
432/*******************************************************************
433 chmod a file - but preserve some bits.
434********************************************************************/
435
436int file_set_dosmode(connection_struct *conn, const char *fname,
437 uint32 dosmode, SMB_STRUCT_STAT *st,
438 const char *parent_dir,
439 bool newfile)
440{
441 SMB_STRUCT_STAT st1;
442 int mask=0;
443 mode_t tmp;
444 mode_t unixmode;
445 int ret = -1, lret = -1;
446 uint32_t old_mode;
447
448 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
449 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
450
451 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
452
453 if (st == NULL) {
454 SET_STAT_INVALID(st1);
455 st = &st1;
456 }
457
458 if (!VALID_STAT(*st)) {
459 if (SMB_VFS_STAT(conn,fname,st))
460 return(-1);
461 }
462
463 unixmode = st->st_mode;
464
465 get_acl_group_bits(conn, fname, &st->st_mode);
466
467 if (S_ISDIR(st->st_mode))
468 dosmode |= aDIR;
469 else
470 dosmode &= ~aDIR;
471
472 old_mode = dos_mode(conn,fname,st);
473
474 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
475 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
476 lret = SMB_VFS_SET_OFFLINE(conn, fname);
477 if (lret == -1) {
478 DEBUG(0, ("set_dos_mode: client has asked to set "
479 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
480 "an error while setting it or it is not supported.\n",
481 parent_dir, fname));
482 }
483 }
484 }
485
486 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
487 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
488
489 if (old_mode == dosmode) {
490 st->st_mode = unixmode;
491 return(0);
492 }
493
494 /* Store the DOS attributes in an EA by preference. */
495 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
496 if (!newfile) {
497 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
498 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
499 }
500 st->st_mode = unixmode;
501 return 0;
502 }
503
504 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
505
506 /* preserve the s bits */
507 mask |= (S_ISUID | S_ISGID);
508
509 /* preserve the t bit */
510#ifdef S_ISVTX
511 mask |= S_ISVTX;
512#endif
513
514 /* possibly preserve the x bits */
515 if (!MAP_ARCHIVE(conn))
516 mask |= S_IXUSR;
517 if (!MAP_SYSTEM(conn))
518 mask |= S_IXGRP;
519 if (!MAP_HIDDEN(conn))
520 mask |= S_IXOTH;
521
522 unixmode |= (st->st_mode & mask);
523
524 /* if we previously had any r bits set then leave them alone */
525 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
526 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
527 unixmode |= tmp;
528 }
529
530 /* if we previously had any w bits set then leave them alone
531 whilst adding in the new w bits, if the new mode is not rdonly */
532 if (!IS_DOS_READONLY(dosmode)) {
533 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
534 }
535
536 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
537 if (ret == 0) {
538 if(!newfile || (lret != -1)) {
539 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
540 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
541 }
542 st->st_mode = unixmode;
543 return 0;
544 }
545
546 if((errno != EPERM) && (errno != EACCES))
547 return -1;
548
549 if(!lp_dos_filemode(SNUM(conn)))
550 return -1;
551
552 /* We want DOS semantics, ie allow non owner with write permission to change the
553 bits on a file. Just like file_ntimes below.
554 */
555
556 /* Check if we have write access. */
557 if (CAN_WRITE(conn)) {
558 /*
559 * We need to open the file with write access whilst
560 * still in our current user context. This ensures we
561 * are not violating security in doing the fchmod.
562 * This file open does *not* break any oplocks we are
563 * holding. We need to review this.... may need to
564 * break batch oplocks open by others. JRA.
565 */
566 files_struct *fsp;
567 if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,st,&fsp)))
568 return -1;
569 become_root();
570 ret = SMB_VFS_FCHMOD(fsp, unixmode);
571 unbecome_root();
572 close_file_fchmod(fsp);
573 if (!newfile) {
574 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
575 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
576 }
577 if (ret == 0) {
578 st->st_mode = unixmode;
579 }
580 }
581
582 return( ret );
583}
584
585/*******************************************************************
586 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
587 than POSIX.
588*******************************************************************/
589
590int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
591{
592 SMB_STRUCT_STAT sbuf;
593 int ret = -1;
594
595 errno = 0;
596 ZERO_STRUCT(sbuf);
597
598 DEBUG(6, ("file_ntime: actime: %s",
599 time_to_asc(convert_timespec_to_time_t(ts[0]))));
600 DEBUG(6, ("file_ntime: modtime: %s",
601 time_to_asc(convert_timespec_to_time_t(ts[1]))));
602
603 /* Don't update the time on read-only shares */
604 /* We need this as set_filetime (which can be called on
605 close and other paths) can end up calling this function
606 without the NEED_WRITE protection. Found by :
607 Leo Weppelman <leo@wau.mis.ah.nl>
608 */
609
610 if (!CAN_WRITE(conn)) {
611 return 0;
612 }
613
614 if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
615 return 0;
616 }
617
618 if((errno != EPERM) && (errno != EACCES)) {
619 return -1;
620 }
621
622 if(!lp_dos_filetimes(SNUM(conn))) {
623 return -1;
624 }
625
626 /* We have permission (given by the Samba admin) to
627 break POSIX semantics and allow a user to change
628 the time on a file they don't own but can write to
629 (as DOS does).
630 */
631
632 /* Check if we have write access. */
633 if (can_write_to_file(conn, fname, &sbuf)) {
634 /* We are allowed to become root and change the filetime. */
635 become_root();
636 ret = SMB_VFS_NTIMES(conn, fname, ts);
637 unbecome_root();
638 }
639
640 return ret;
641}
642
643/******************************************************************
644 Force a "sticky" write time on a pathname. This will always be
645 returned on all future write time queries and set on close.
646******************************************************************/
647
648bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
649 struct file_id fileid, const struct timespec mtime)
650{
651 if (null_timespec(mtime)) {
652 return true;
653 }
654
655 if (!set_sticky_write_time(fileid, mtime)) {
656 return false;
657 }
658
659 return true;
660}
661
662/******************************************************************
663 Force a "sticky" write time on an fsp. This will always be
664 returned on all future write time queries and set on close.
665******************************************************************/
666
667bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
668{
669 fsp->write_time_forced = true;
670 TALLOC_FREE(fsp->update_write_time_event);
671
672 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
673 fsp->file_id, mtime);
674}
675
676/******************************************************************
677 Update a write time immediately, without the 2 second delay.
678******************************************************************/
679
680bool update_write_time(struct files_struct *fsp)
681{
682 if (!set_write_time(fsp->file_id, timespec_current())) {
683 return false;
684 }
685
686 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
687 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
688
689 return true;
690}
Note: See TracBrowser for help on using the repository browser.