packaging: don't clutter the output of fillup-templates with popd output
[Samba.git] / source3 / smbd / dosmode.c
blob555718bd83a02f2760365e3c83984003fc25326e
1 /*
2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
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.
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.
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/>.
21 #include "includes.h"
23 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
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;
29 #endif
30 return 0;
33 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
35 #ifdef S_ISLNK
36 #if LINKS_READ_ONLY
37 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
38 return aRONLY;
39 #endif
40 #endif
41 return 0;
44 /****************************************************************************
45 Change a dos mode to a unix mode.
46 Base permission for files:
47 if creating file and inheriting (i.e. parent_dir != NULL)
48 apply read/write bits from parent directory.
49 else
50 everybody gets read bit set
51 dos readonly is represented in unix by removing everyone's write bit
52 dos archive is represented in unix by the user's execute bit
53 dos system is represented in unix by the group's execute bit
54 dos hidden is represented in unix by the other's execute bit
55 if !inheriting {
56 Then apply create mask,
57 then add force bits.
59 Base permission for directories:
60 dos directory is represented in unix by unix's dir bit and the exec bit
61 if !inheriting {
62 Then apply create mask,
63 then add force bits.
65 ****************************************************************************/
67 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
68 const char *inherit_from_dir)
70 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
71 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
72 * inheriting. */
74 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
75 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
78 if (fname && (inherit_from_dir != NULL)
79 && lp_inherit_perms(SNUM(conn))) {
80 SMB_STRUCT_STAT sbuf;
82 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
83 inherit_from_dir));
84 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
85 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
86 inherit_from_dir, strerror(errno)));
87 return(0); /* *** shouldn't happen! *** */
90 /* Save for later - but explicitly remove setuid bit for safety. */
91 dir_mode = sbuf.st_mode & ~S_ISUID;
92 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
93 /* Clear "result" */
94 result = 0;
97 if (IS_DOS_DIR(dosmode)) {
98 /* We never make directories read only for the owner as under DOS a user
99 can always create a file in a read-only directory. */
100 result |= (S_IFDIR | S_IWUSR);
102 if (dir_mode) {
103 /* Inherit mode of parent directory. */
104 result |= dir_mode;
105 } else {
106 /* Provisionally add all 'x' bits */
107 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
109 /* Apply directory mask */
110 result &= lp_dir_mask(SNUM(conn));
111 /* Add in force bits */
112 result |= lp_force_dir_mode(SNUM(conn));
114 } else {
115 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
116 result |= S_IXUSR;
118 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
119 result |= S_IXGRP;
121 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
122 result |= S_IXOTH;
124 if (dir_mode) {
125 /* Inherit 666 component of parent directory mode */
126 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
127 } else {
128 /* Apply mode mask */
129 result &= lp_create_mask(SNUM(conn));
130 /* Add in force bits */
131 result |= lp_force_create_mode(SNUM(conn));
135 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
136 return(result);
139 /****************************************************************************
140 Change a unix mode to a dos mode.
141 ****************************************************************************/
143 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
145 int result = 0;
146 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
148 if (ro_opts == MAP_READONLY_YES) {
149 /* Original Samba method - map inverse of user "w" bit. */
150 if ((sbuf->st_mode & S_IWUSR) == 0) {
151 result |= aRONLY;
153 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
154 /* Check actual permissions for read-only. */
155 if (!can_write_to_file(conn, path, sbuf)) {
156 result |= aRONLY;
158 } /* Else never set the readonly bit. */
160 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
161 result |= aARCH;
163 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
164 result |= aSYSTEM;
166 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
167 result |= aHIDDEN;
169 if (S_ISDIR(sbuf->st_mode))
170 result = aDIR | (result & aRONLY);
172 result |= set_sparse_flag(sbuf);
173 result |= set_link_read_only_flag(sbuf);
175 DEBUG(8,("dos_mode_from_sbuf returning "));
177 if (result & aHIDDEN) DEBUG(8, ("h"));
178 if (result & aRONLY ) DEBUG(8, ("r"));
179 if (result & aSYSTEM) DEBUG(8, ("s"));
180 if (result & aDIR ) DEBUG(8, ("d"));
181 if (result & aARCH ) DEBUG(8, ("a"));
183 DEBUG(8,("\n"));
184 return result;
187 /****************************************************************************
188 Get DOS attributes from an EA.
189 ****************************************************************************/
191 static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
193 ssize_t sizeret;
194 fstring attrstr;
195 unsigned int dosattr;
197 if (!lp_store_dos_attributes(SNUM(conn))) {
198 return False;
201 /* Don't reset pattr to zero as we may already have filename-based attributes we
202 need to preserve. */
204 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
205 if (sizeret == -1) {
206 if (errno == ENOSYS
207 #if defined(ENOTSUP)
208 || errno == ENOTSUP) {
209 #else
211 #endif
212 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
213 path, strerror(errno) ));
214 set_store_dos_attributes(SNUM(conn), False);
216 return False;
218 /* Null terminate string. */
219 attrstr[sizeret] = 0;
220 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
222 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
223 sscanf(attrstr, "%x", &dosattr) != 1) {
224 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
225 return False;
228 if (S_ISDIR(sbuf->st_mode)) {
229 dosattr |= aDIR;
231 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
233 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
235 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
236 if (dosattr & aRONLY ) DEBUG(8, ("r"));
237 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
238 if (dosattr & aDIR ) DEBUG(8, ("d"));
239 if (dosattr & aARCH ) DEBUG(8, ("a"));
241 DEBUG(8,("\n"));
243 return True;
246 /****************************************************************************
247 Set DOS attributes in an EA.
248 ****************************************************************************/
250 static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
252 fstring attrstr;
253 files_struct *fsp = NULL;
254 bool ret = False;
256 if (!lp_store_dos_attributes(SNUM(conn))) {
257 return False;
260 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
261 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
262 if((errno != EPERM) && (errno != EACCES)) {
263 if (errno == ENOSYS
264 #if defined(ENOTSUP)
265 || errno == ENOTSUP) {
266 #else
268 #endif
269 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
270 path, strerror(errno) ));
271 set_store_dos_attributes(SNUM(conn), False);
273 return False;
276 /* We want DOS semantics, ie allow non owner with write permission to change the
277 bits on a file. Just like file_ntimes below.
280 /* Check if we have write access. */
281 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
282 return False;
285 * We need to open the file with write access whilst
286 * still in our current user context. This ensures we
287 * are not violating security in doing the setxattr.
290 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf,
291 &fsp)))
292 return ret;
293 become_root();
294 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
295 ret = True;
297 unbecome_root();
298 close_file_fchmod(NULL, fsp);
299 return ret;
301 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
302 return True;
305 /****************************************************************************
306 Change a unix mode to a dos mode for an ms dfs link.
307 ****************************************************************************/
309 uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
311 uint32 result = 0;
313 DEBUG(8,("dos_mode_msdfs: %s\n", path));
315 if (!VALID_STAT(*sbuf)) {
316 return 0;
319 /* First do any modifications that depend on the path name. */
320 /* hide files with a name starting with a . */
321 if (lp_hide_dot_files(SNUM(conn))) {
322 const char *p = strrchr_m(path,'/');
323 if (p) {
324 p++;
325 } else {
326 p = path;
329 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
330 result |= aHIDDEN;
334 result |= dos_mode_from_sbuf(conn, path, sbuf);
336 /* Optimization : Only call is_hidden_path if it's not already
337 hidden. */
338 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
339 result |= aHIDDEN;
342 DEBUG(8,("dos_mode_msdfs returning "));
344 if (result & aHIDDEN) DEBUG(8, ("h"));
345 if (result & aRONLY ) DEBUG(8, ("r"));
346 if (result & aSYSTEM) DEBUG(8, ("s"));
347 if (result & aDIR ) DEBUG(8, ("d"));
348 if (result & aARCH ) DEBUG(8, ("a"));
349 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
351 DEBUG(8,("\n"));
353 return(result);
356 #ifdef HAVE_STAT_DOS_FLAGS
357 /****************************************************************************
358 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
359 ****************************************************************************/
361 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
363 uint32_t dos_stat_flags = 0;
365 if (dosmode & aARCH)
366 dos_stat_flags |= UF_DOS_ARCHIVE;
367 if (dosmode & aHIDDEN)
368 dos_stat_flags |= UF_DOS_HIDDEN;
369 if (dosmode & aRONLY)
370 dos_stat_flags |= UF_DOS_RO;
371 if (dosmode & aSYSTEM)
372 dos_stat_flags |= UF_DOS_SYSTEM;
373 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
374 dos_stat_flags |= UF_DOS_NOINDEX;
376 return dos_stat_flags;
379 /****************************************************************************
380 Gets DOS attributes, accessed via st_flags in the stat struct.
381 ****************************************************************************/
383 static bool get_stat_dos_flags(connection_struct *conn,
384 const char *fname,
385 const SMB_STRUCT_STAT *sbuf,
386 uint32_t *dosmode)
388 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
389 SMB_ASSERT(dosmode);
391 if (!lp_store_dos_attributes(SNUM(conn))) {
392 return false;
395 DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
397 if (sbuf->st_flags & UF_DOS_ARCHIVE)
398 *dosmode |= aARCH;
399 if (sbuf->st_flags & UF_DOS_HIDDEN)
400 *dosmode |= aHIDDEN;
401 if (sbuf->st_flags & UF_DOS_RO)
402 *dosmode |= aRONLY;
403 if (sbuf->st_flags & UF_DOS_SYSTEM)
404 *dosmode |= aSYSTEM;
405 if (sbuf->st_flags & UF_DOS_NOINDEX)
406 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
407 if (S_ISDIR(sbuf->st_mode))
408 *dosmode |= aDIR;
410 *dosmode |= set_sparse_flag(sbuf);
411 *dosmode |= set_link_read_only_flag(sbuf);
413 return true;
416 /****************************************************************************
417 Sets DOS attributes, stored in st_flags of the inode.
418 ****************************************************************************/
420 static bool set_stat_dos_flags(connection_struct *conn,
421 const char *fname,
422 SMB_STRUCT_STAT *sbuf,
423 uint32_t dosmode,
424 bool *attributes_changed)
426 uint32_t new_flags = 0;
427 int error = 0;
429 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
430 SMB_ASSERT(attributes_changed);
432 *attributes_changed = false;
434 if (!lp_store_dos_attributes(SNUM(conn))) {
435 return false;
438 DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
440 new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) |
441 dos_attributes_to_stat_dos_flags(dosmode);
443 /* Return early if no flags changed. */
444 if (new_flags == sbuf->st_flags)
445 return true;
447 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
448 sbuf->st_flags));
450 /* Set new flags with chflags. */
451 error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
452 if (error) {
453 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
454 "file %s! errno=%d\n", new_flags, fname, errno));
455 return false;
458 *attributes_changed = true;
459 return true;
461 #endif /* HAVE_STAT_DOS_FLAGS */
463 /****************************************************************************
464 Change a unix mode to a dos mode.
465 ****************************************************************************/
467 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
469 uint32 result = 0;
470 bool offline, used_stat_dos_flags = false;
472 DEBUG(8,("dos_mode: %s\n", path));
474 if (!VALID_STAT(*sbuf)) {
475 return 0;
478 /* First do any modifications that depend on the path name. */
479 /* hide files with a name starting with a . */
480 if (lp_hide_dot_files(SNUM(conn))) {
481 const char *p = strrchr_m(path,'/');
482 if (p) {
483 p++;
484 } else {
485 p = path;
488 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
489 result |= aHIDDEN;
493 #ifdef HAVE_STAT_DOS_FLAGS
494 used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result);
495 #endif
496 if (!used_stat_dos_flags) {
497 /* Get the DOS attributes from an EA by preference. */
498 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
499 result |= set_sparse_flag(sbuf);
500 } else {
501 result |= dos_mode_from_sbuf(conn, path, sbuf);
506 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
507 if (S_ISREG(sbuf->st_mode) && offline) {
508 result |= FILE_ATTRIBUTE_OFFLINE;
511 /* Optimization : Only call is_hidden_path if it's not already
512 hidden. */
513 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
514 result |= aHIDDEN;
517 DEBUG(8,("dos_mode returning "));
519 if (result & aHIDDEN) DEBUG(8, ("h"));
520 if (result & aRONLY ) DEBUG(8, ("r"));
521 if (result & aSYSTEM) DEBUG(8, ("s"));
522 if (result & aDIR ) DEBUG(8, ("d"));
523 if (result & aARCH ) DEBUG(8, ("a"));
524 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
526 DEBUG(8,("\n"));
528 return(result);
531 /*******************************************************************
532 chmod a file - but preserve some bits.
533 ********************************************************************/
535 int file_set_dosmode(connection_struct *conn, const char *fname,
536 uint32 dosmode, SMB_STRUCT_STAT *st,
537 const char *parent_dir,
538 bool newfile)
540 SMB_STRUCT_STAT st1;
541 int mask=0;
542 mode_t tmp;
543 mode_t unixmode;
544 int ret = -1, lret = -1;
545 uint32_t old_mode;
547 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
548 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
550 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
552 if (st == NULL) {
553 SET_STAT_INVALID(st1);
554 st = &st1;
557 if (!VALID_STAT(*st)) {
558 if (SMB_VFS_STAT(conn,fname,st))
559 return(-1);
562 unixmode = st->st_mode;
564 get_acl_group_bits(conn, fname, &st->st_mode);
566 if (S_ISDIR(st->st_mode))
567 dosmode |= aDIR;
568 else
569 dosmode &= ~aDIR;
571 old_mode = dos_mode(conn,fname,st);
573 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
574 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
575 lret = SMB_VFS_SET_OFFLINE(conn, fname);
576 if (lret == -1) {
577 DEBUG(0, ("set_dos_mode: client has asked to set "
578 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
579 "an error while setting it or it is not supported.\n",
580 parent_dir, fname));
585 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
586 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
588 if (old_mode == dosmode) {
589 st->st_mode = unixmode;
590 return(0);
593 #ifdef HAVE_STAT_DOS_FLAGS
595 bool attributes_changed;
597 if (set_stat_dos_flags(conn, fname, st, dosmode,
598 &attributes_changed))
600 if (!newfile && attributes_changed) {
601 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
602 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
604 st->st_mode = unixmode;
605 return 0;
608 #endif
610 /* Store the DOS attributes in an EA by preference. */
611 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
612 if (!newfile) {
613 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
614 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
616 st->st_mode = unixmode;
617 return 0;
620 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
622 /* preserve the s bits */
623 mask |= (S_ISUID | S_ISGID);
625 /* preserve the t bit */
626 #ifdef S_ISVTX
627 mask |= S_ISVTX;
628 #endif
630 /* possibly preserve the x bits */
631 if (!MAP_ARCHIVE(conn))
632 mask |= S_IXUSR;
633 if (!MAP_SYSTEM(conn))
634 mask |= S_IXGRP;
635 if (!MAP_HIDDEN(conn))
636 mask |= S_IXOTH;
638 unixmode |= (st->st_mode & mask);
640 /* if we previously had any r bits set then leave them alone */
641 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
642 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
643 unixmode |= tmp;
646 /* if we previously had any w bits set then leave them alone
647 whilst adding in the new w bits, if the new mode is not rdonly */
648 if (!IS_DOS_READONLY(dosmode)) {
649 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
652 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
653 if (ret == 0) {
654 if(!newfile || (lret != -1)) {
655 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
656 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
658 st->st_mode = unixmode;
659 return 0;
662 if((errno != EPERM) && (errno != EACCES))
663 return -1;
665 if(!lp_dos_filemode(SNUM(conn)))
666 return -1;
668 /* We want DOS semantics, ie allow non owner with write permission to change the
669 bits on a file. Just like file_ntimes below.
672 /* Check if we have write access. */
673 if (CAN_WRITE(conn)) {
675 * We need to open the file with write access whilst
676 * still in our current user context. This ensures we
677 * are not violating security in doing the fchmod.
678 * This file open does *not* break any oplocks we are
679 * holding. We need to review this.... may need to
680 * break batch oplocks open by others. JRA.
682 files_struct *fsp;
683 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
684 &fsp)))
685 return -1;
686 become_root();
687 ret = SMB_VFS_FCHMOD(fsp, unixmode);
688 unbecome_root();
689 close_file_fchmod(NULL, fsp);
690 if (!newfile) {
691 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
692 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
694 if (ret == 0) {
695 st->st_mode = unixmode;
699 return( ret );
702 /*******************************************************************
703 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
704 than POSIX.
705 *******************************************************************/
707 int file_ntimes(connection_struct *conn, const char *fname,
708 struct smb_file_time *ft)
710 SMB_STRUCT_STAT sbuf;
711 int ret = -1;
713 errno = 0;
714 ZERO_STRUCT(sbuf);
716 DEBUG(6, ("file_ntime: actime: %s",
717 time_to_asc(convert_timespec_to_time_t(ft->atime))));
718 DEBUG(6, ("file_ntime: modtime: %s",
719 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
720 DEBUG(6, ("file_ntime: createtime: %s",
721 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
723 /* Don't update the time on read-only shares */
724 /* We need this as set_filetime (which can be called on
725 close and other paths) can end up calling this function
726 without the NEED_WRITE protection. Found by :
727 Leo Weppelman <leo@wau.mis.ah.nl>
730 if (!CAN_WRITE(conn)) {
731 return 0;
734 if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
735 return 0;
738 if((errno != EPERM) && (errno != EACCES)) {
739 return -1;
742 if(!lp_dos_filetimes(SNUM(conn))) {
743 return -1;
746 /* We have permission (given by the Samba admin) to
747 break POSIX semantics and allow a user to change
748 the time on a file they don't own but can write to
749 (as DOS does).
752 /* Check if we have write access. */
753 if (can_write_to_file(conn, fname, &sbuf)) {
754 /* We are allowed to become root and change the filetime. */
755 become_root();
756 ret = SMB_VFS_NTIMES(conn, fname, ft);
757 unbecome_root();
760 return ret;
763 /******************************************************************
764 Force a "sticky" write time on a pathname. This will always be
765 returned on all future write time queries and set on close.
766 ******************************************************************/
768 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
769 struct file_id fileid, const struct timespec mtime)
771 if (null_timespec(mtime)) {
772 return true;
775 if (!set_sticky_write_time(fileid, mtime)) {
776 return false;
779 return true;
782 /******************************************************************
783 Force a "sticky" write time on an fsp. This will always be
784 returned on all future write time queries and set on close.
785 ******************************************************************/
787 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
789 fsp->write_time_forced = true;
790 TALLOC_FREE(fsp->update_write_time_event);
792 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
793 fsp->file_id, mtime);
796 /******************************************************************
797 Update a write time immediately, without the 2 second delay.
798 ******************************************************************/
800 bool update_write_time(struct files_struct *fsp)
802 if (!set_write_time(fsp->file_id, timespec_current())) {
803 return false;
806 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
807 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
809 return true;