source: branches/samba-3.3.x/source/smbd/dosmode.c@ 221

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

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 19.4 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__
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__
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__
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__
168 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
169#else
170 if(os2_isattribute(path,aHIDDEN)==0)
171#endif
172 result |= aHIDDEN;
173
174 if (S_ISDIR(sbuf->st_mode))
175 result = aDIR | (result & aRONLY);
176
177 result |= set_sparse_flag(sbuf);
178
179#ifdef S_ISLNK
180#if LINKS_READ_ONLY
181 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
182 result |= aRONLY;
183#endif
184#endif
185
186 DEBUG(8,("dos_mode_from_sbuf returning "));
187
188 if (result & aHIDDEN) DEBUG(8, ("h"));
189 if (result & aRONLY ) DEBUG(8, ("r"));
190 if (result & aSYSTEM) DEBUG(8, ("s"));
191 if (result & aDIR ) DEBUG(8, ("d"));
192 if (result & aARCH ) DEBUG(8, ("a"));
193
194 DEBUG(8,("\n"));
195 return result;
196}
197
198/****************************************************************************
199 Get DOS attributes from an EA.
200****************************************************************************/
201
202static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
203{
204 ssize_t sizeret;
205 fstring attrstr;
206 unsigned int dosattr;
207
208 if (!lp_store_dos_attributes(SNUM(conn))) {
209 return False;
210 }
211
212 /* Don't reset pattr to zero as we may already have filename-based attributes we
213 need to preserve. */
214
215 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
216 if (sizeret == -1) {
217 if (errno == ENOSYS
218#if defined(ENOTSUP)
219 || errno == ENOTSUP) {
220#else
221 ) {
222#endif
223 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
224 path, strerror(errno) ));
225 set_store_dos_attributes(SNUM(conn), False);
226 }
227 return False;
228 }
229 /* Null terminate string. */
230 attrstr[sizeret] = 0;
231 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
232
233 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
234 sscanf(attrstr, "%x", &dosattr) != 1) {
235 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
236 return False;
237 }
238
239 if (S_ISDIR(sbuf->st_mode)) {
240 dosattr |= aDIR;
241 }
242 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
243
244 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
245
246 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
247 if (dosattr & aRONLY ) DEBUG(8, ("r"));
248 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
249 if (dosattr & aDIR ) DEBUG(8, ("d"));
250 if (dosattr & aARCH ) DEBUG(8, ("a"));
251
252 DEBUG(8,("\n"));
253
254 return True;
255}
256
257/****************************************************************************
258 Set DOS attributes in an EA.
259****************************************************************************/
260
261static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
262{
263 fstring attrstr;
264 files_struct *fsp = NULL;
265 bool ret = False;
266
267 if (!lp_store_dos_attributes(SNUM(conn))) {
268 return False;
269 }
270
271 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
272 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
273 if((errno != EPERM) && (errno != EACCES)) {
274 if (errno == ENOSYS
275#if defined(ENOTSUP)
276 || errno == ENOTSUP) {
277#else
278 ) {
279#endif
280 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
281 path, strerror(errno) ));
282 set_store_dos_attributes(SNUM(conn), False);
283 }
284 return False;
285 }
286
287 /* We want DOS semantics, ie allow non owner with write permission to change the
288 bits on a file. Just like file_ntimes below.
289 */
290
291 /* Check if we have write access. */
292 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
293 return False;
294
295 /*
296 * We need to open the file with write access whilst
297 * still in our current user context. This ensures we
298 * are not violating security in doing the setxattr.
299 */
300
301 if (!NT_STATUS_IS_OK(open_file_fchmod(conn,path,sbuf,&fsp)))
302 return ret;
303 become_root();
304 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
305 ret = True;
306 }
307 unbecome_root();
308 close_file_fchmod(fsp);
309 return ret;
310 }
311 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
312 return True;
313}
314
315/****************************************************************************
316 Change a unix mode to a dos mode for an ms dfs link.
317****************************************************************************/
318
319uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
320{
321 uint32 result = 0;
322
323 DEBUG(8,("dos_mode_msdfs: %s\n", path));
324
325 if (!VALID_STAT(*sbuf)) {
326 return 0;
327 }
328
329 /* First do any modifications that depend on the path name. */
330 /* hide files with a name starting with a . */
331 if (lp_hide_dot_files(SNUM(conn))) {
332 const char *p = strrchr_m(path,'/');
333 if (p) {
334 p++;
335 } else {
336 p = path;
337 }
338
339 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
340 result |= aHIDDEN;
341 }
342 }
343
344 result |= dos_mode_from_sbuf(conn, path, sbuf);
345
346 /* Optimization : Only call is_hidden_path if it's not already
347 hidden. */
348 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
349 result |= aHIDDEN;
350 }
351
352 DEBUG(8,("dos_mode_msdfs returning "));
353
354 if (result & aHIDDEN) DEBUG(8, ("h"));
355 if (result & aRONLY ) DEBUG(8, ("r"));
356 if (result & aSYSTEM) DEBUG(8, ("s"));
357 if (result & aDIR ) DEBUG(8, ("d"));
358 if (result & aARCH ) DEBUG(8, ("a"));
359 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
360
361 DEBUG(8,("\n"));
362
363 return(result);
364}
365
366/****************************************************************************
367 Change a unix mode to a dos mode.
368****************************************************************************/
369
370uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
371{
372 uint32 result = 0;
373 bool offline;
374
375 DEBUG(8,("dos_mode: %s\n", path));
376
377 if (!VALID_STAT(*sbuf)) {
378 return 0;
379 }
380
381 /* First do any modifications that depend on the path name. */
382 /* hide files with a name starting with a . */
383 if (lp_hide_dot_files(SNUM(conn))) {
384 const char *p = strrchr_m(path,'/');
385 if (p) {
386 p++;
387 } else {
388 p = path;
389 }
390
391 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
392 result |= aHIDDEN;
393 }
394 }
395
396 /* Get the DOS attributes from an EA by preference. */
397 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
398 result |= set_sparse_flag(sbuf);
399 } else {
400 result |= dos_mode_from_sbuf(conn, path, sbuf);
401 }
402
403
404 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
405 if (S_ISREG(sbuf->st_mode) && offline) {
406 result |= FILE_ATTRIBUTE_OFFLINE;
407 }
408
409 /* Optimization : Only call is_hidden_path if it's not already
410 hidden. */
411 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
412 result |= aHIDDEN;
413 }
414
415 DEBUG(8,("dos_mode returning "));
416
417 if (result & aHIDDEN) DEBUG(8, ("h"));
418 if (result & aRONLY ) DEBUG(8, ("r"));
419 if (result & aSYSTEM) DEBUG(8, ("s"));
420 if (result & aDIR ) DEBUG(8, ("d"));
421 if (result & aARCH ) DEBUG(8, ("a"));
422 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
423
424 DEBUG(8,("\n"));
425
426 return(result);
427}
428
429/*******************************************************************
430 chmod a file - but preserve some bits.
431********************************************************************/
432
433int file_set_dosmode(connection_struct *conn, const char *fname,
434 uint32 dosmode, SMB_STRUCT_STAT *st,
435 const char *parent_dir,
436 bool newfile)
437{
438 SMB_STRUCT_STAT st1;
439 int mask=0;
440 mode_t tmp;
441 mode_t unixmode;
442 int ret = -1, lret = -1;
443 uint32_t old_mode;
444
445 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
446 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
447
448 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
449
450 if (st == NULL) {
451 SET_STAT_INVALID(st1);
452 st = &st1;
453 }
454
455 if (!VALID_STAT(*st)) {
456 if (SMB_VFS_STAT(conn,fname,st))
457 return(-1);
458 }
459
460 unixmode = st->st_mode;
461
462 get_acl_group_bits(conn, fname, &st->st_mode);
463
464 if (S_ISDIR(st->st_mode))
465 dosmode |= aDIR;
466 else
467 dosmode &= ~aDIR;
468
469 old_mode = dos_mode(conn,fname,st);
470
471 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
472 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
473 lret = SMB_VFS_SET_OFFLINE(conn, fname);
474 if (lret == -1) {
475 DEBUG(0, ("set_dos_mode: client has asked to set "
476 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
477 "an error while setting it or it is not supported.\n",
478 parent_dir, fname));
479 }
480 }
481 }
482
483 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
484 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
485
486 if (old_mode == dosmode) {
487 st->st_mode = unixmode;
488 return(0);
489 }
490
491 /* Store the DOS attributes in an EA by preference. */
492 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
493 if (!newfile) {
494 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
495 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
496 }
497 st->st_mode = unixmode;
498 return 0;
499 }
500
501 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
502
503 /* preserve the s bits */
504 mask |= (S_ISUID | S_ISGID);
505
506 /* preserve the t bit */
507#ifdef S_ISVTX
508 mask |= S_ISVTX;
509#endif
510
511 /* possibly preserve the x bits */
512 if (!MAP_ARCHIVE(conn))
513 mask |= S_IXUSR;
514 if (!MAP_SYSTEM(conn))
515 mask |= S_IXGRP;
516 if (!MAP_HIDDEN(conn))
517 mask |= S_IXOTH;
518
519 unixmode |= (st->st_mode & mask);
520
521 /* if we previously had any r bits set then leave them alone */
522 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
523 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
524 unixmode |= tmp;
525 }
526
527 /* if we previously had any w bits set then leave them alone
528 whilst adding in the new w bits, if the new mode is not rdonly */
529 if (!IS_DOS_READONLY(dosmode)) {
530 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
531 }
532
533 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
534 if (ret == 0) {
535 if(!newfile || (lret != -1)) {
536 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
537 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
538 }
539 st->st_mode = unixmode;
540 return 0;
541 }
542
543 if((errno != EPERM) && (errno != EACCES))
544 return -1;
545
546 if(!lp_dos_filemode(SNUM(conn)))
547 return -1;
548
549 /* We want DOS semantics, ie allow non owner with write permission to change the
550 bits on a file. Just like file_ntimes below.
551 */
552
553 /* Check if we have write access. */
554 if (CAN_WRITE(conn)) {
555 /*
556 * We need to open the file with write access whilst
557 * still in our current user context. This ensures we
558 * are not violating security in doing the fchmod.
559 * This file open does *not* break any oplocks we are
560 * holding. We need to review this.... may need to
561 * break batch oplocks open by others. JRA.
562 */
563 files_struct *fsp;
564 if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,st,&fsp)))
565 return -1;
566 become_root();
567 ret = SMB_VFS_FCHMOD(fsp, unixmode);
568 unbecome_root();
569 close_file_fchmod(fsp);
570 if (!newfile) {
571 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
572 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
573 }
574 if (ret == 0) {
575 st->st_mode = unixmode;
576 }
577 }
578
579 return( ret );
580}
581
582/*******************************************************************
583 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
584 than POSIX.
585*******************************************************************/
586
587int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
588{
589 SMB_STRUCT_STAT sbuf;
590 int ret = -1;
591
592 errno = 0;
593 ZERO_STRUCT(sbuf);
594
595 DEBUG(6, ("file_ntime: actime: %s",
596 time_to_asc(convert_timespec_to_time_t(ts[0]))));
597 DEBUG(6, ("file_ntime: modtime: %s",
598 time_to_asc(convert_timespec_to_time_t(ts[1]))));
599
600 /* Don't update the time on read-only shares */
601 /* We need this as set_filetime (which can be called on
602 close and other paths) can end up calling this function
603 without the NEED_WRITE protection. Found by :
604 Leo Weppelman <leo@wau.mis.ah.nl>
605 */
606
607 if (!CAN_WRITE(conn)) {
608 return 0;
609 }
610
611 if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
612 return 0;
613 }
614
615 if((errno != EPERM) && (errno != EACCES)) {
616 return -1;
617 }
618
619 if(!lp_dos_filetimes(SNUM(conn))) {
620 return -1;
621 }
622
623 /* We have permission (given by the Samba admin) to
624 break POSIX semantics and allow a user to change
625 the time on a file they don't own but can write to
626 (as DOS does).
627 */
628
629 /* Check if we have write access. */
630 if (can_write_to_file(conn, fname, &sbuf)) {
631 /* We are allowed to become root and change the filetime. */
632 become_root();
633 ret = SMB_VFS_NTIMES(conn, fname, ts);
634 unbecome_root();
635 }
636
637 return ret;
638}
639
640/******************************************************************
641 Force a "sticky" write time on a pathname. This will always be
642 returned on all future write time queries and set on close.
643******************************************************************/
644
645bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
646 struct file_id fileid, const struct timespec mtime)
647{
648 if (null_timespec(mtime)) {
649 return true;
650 }
651
652 if (!set_sticky_write_time(fileid, mtime)) {
653 return false;
654 }
655
656 return true;
657}
658
659/******************************************************************
660 Force a "sticky" write time on an fsp. This will always be
661 returned on all future write time queries and set on close.
662******************************************************************/
663
664bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
665{
666 fsp->write_time_forced = true;
667 TALLOC_FREE(fsp->update_write_time_event);
668
669 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
670 fsp->file_id, mtime);
671}
672
673/******************************************************************
674 Update a write time immediately, without the 2 second delay.
675******************************************************************/
676
677bool update_write_time(struct files_struct *fsp)
678{
679 if (!set_write_time(fsp->file_id, timespec_current())) {
680 return false;
681 }
682
683 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
684 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
685
686 return true;
687}
Note: See TracBrowser for help on using the repository browser.