s3/docs: Fix typo.
[Samba/gebeck_regimport.git] / source3 / smbd / dosmode.c
blob8149eea7f59ad8726ac20c40fea9d55269723046
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_ex_size > sbuf->st_ex_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_ex_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, const 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_ex_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_ex_mode & S_IXUSR) != 0))
161 result |= aARCH;
163 if (MAP_SYSTEM(conn) && ((sbuf->st_ex_mode & S_IXGRP) != 0))
164 result |= aSYSTEM;
166 if (MAP_HIDDEN(conn) && ((sbuf->st_ex_mode & S_IXOTH) != 0))
167 result |= aHIDDEN;
169 if (S_ISDIR(sbuf->st_ex_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, const 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_ex_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, const SMB_STRUCT_STAT *psbuf)
311 SMB_STRUCT_STAT sbuf = *psbuf;
312 uint32 result = 0;
314 DEBUG(8,("dos_mode_msdfs: %s\n", path));
316 if (!VALID_STAT(sbuf)) {
317 return 0;
320 /* First do any modifications that depend on the path name. */
321 /* hide files with a name starting with a . */
322 if (lp_hide_dot_files(SNUM(conn))) {
323 const char *p = strrchr_m(path,'/');
324 if (p) {
325 p++;
326 } else {
327 p = path;
330 /* Only . and .. are not hidden. */
331 if (p[0] == '.' && !((p[1] == '\0') ||
332 (p[1] == '.' && p[2] == '\0'))) {
333 result |= aHIDDEN;
337 result |= dos_mode_from_sbuf(conn, path, &sbuf);
339 /* Optimization : Only call is_hidden_path if it's not already
340 hidden. */
341 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
342 result |= aHIDDEN;
345 DEBUG(8,("dos_mode_msdfs returning "));
347 if (result & aHIDDEN) DEBUG(8, ("h"));
348 if (result & aRONLY ) DEBUG(8, ("r"));
349 if (result & aSYSTEM) DEBUG(8, ("s"));
350 if (result & aDIR ) DEBUG(8, ("d"));
351 if (result & aARCH ) DEBUG(8, ("a"));
352 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
354 DEBUG(8,("\n"));
356 return(result);
359 #ifdef HAVE_STAT_DOS_FLAGS
360 /****************************************************************************
361 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
362 ****************************************************************************/
364 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
366 uint32_t dos_stat_flags = 0;
368 if (dosmode & aARCH)
369 dos_stat_flags |= UF_DOS_ARCHIVE;
370 if (dosmode & aHIDDEN)
371 dos_stat_flags |= UF_DOS_HIDDEN;
372 if (dosmode & aRONLY)
373 dos_stat_flags |= UF_DOS_RO;
374 if (dosmode & aSYSTEM)
375 dos_stat_flags |= UF_DOS_SYSTEM;
376 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
377 dos_stat_flags |= UF_DOS_NOINDEX;
379 return dos_stat_flags;
382 /****************************************************************************
383 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
384 ****************************************************************************/
386 static bool get_stat_dos_flags(connection_struct *conn,
387 const char *fname,
388 const SMB_STRUCT_STAT *sbuf,
389 uint32_t *dosmode)
391 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
392 SMB_ASSERT(dosmode);
394 if (!lp_store_dos_attributes(SNUM(conn))) {
395 return false;
398 DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
400 if (sbuf->st_ex_flags & UF_DOS_ARCHIVE)
401 *dosmode |= aARCH;
402 if (sbuf->st_ex_flags & UF_DOS_HIDDEN)
403 *dosmode |= aHIDDEN;
404 if (sbuf->st_ex_flags & UF_DOS_RO)
405 *dosmode |= aRONLY;
406 if (sbuf->st_ex_flags & UF_DOS_SYSTEM)
407 *dosmode |= aSYSTEM;
408 if (sbuf->st_ex_flags & UF_DOS_NOINDEX)
409 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
410 if (S_ISDIR(sbuf->st_ex_mode))
411 *dosmode |= aDIR;
413 *dosmode |= set_sparse_flag(sbuf);
414 *dosmode |= set_link_read_only_flag(sbuf);
416 return true;
419 /****************************************************************************
420 Sets DOS attributes, stored in st_ex_flags of the inode.
421 ****************************************************************************/
423 static bool set_stat_dos_flags(connection_struct *conn,
424 const char *fname,
425 SMB_STRUCT_STAT *sbuf,
426 uint32_t dosmode,
427 bool *attributes_changed)
429 uint32_t new_flags = 0;
430 int error = 0;
432 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
433 SMB_ASSERT(attributes_changed);
435 *attributes_changed = false;
437 if (!lp_store_dos_attributes(SNUM(conn))) {
438 return false;
441 DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
443 new_flags = (sbuf->st_ex_flags & ~UF_DOS_FLAGS) |
444 dos_attributes_to_stat_dos_flags(dosmode);
446 /* Return early if no flags changed. */
447 if (new_flags == sbuf->st_ex_flags)
448 return true;
450 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
451 sbuf->st_ex_flags));
453 /* Set new flags with chflags. */
454 error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
455 if (error) {
456 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
457 "file %s! errno=%d\n", new_flags, fname, errno));
458 return false;
461 *attributes_changed = true;
462 return true;
464 #endif /* HAVE_STAT_DOS_FLAGS */
466 /****************************************************************************
467 Change a unix mode to a dos mode.
468 ****************************************************************************/
470 uint32 dos_mode(connection_struct *conn, const char *path, const SMB_STRUCT_STAT *psbuf)
472 SMB_STRUCT_STAT sbuf = *psbuf;
473 uint32 result = 0;
474 bool offline, used_stat_dos_flags = false;
476 DEBUG(8,("dos_mode: %s\n", path));
478 if (!VALID_STAT(sbuf)) {
479 return 0;
482 /* First do any modifications that depend on the path name. */
483 /* hide files with a name starting with a . */
484 if (lp_hide_dot_files(SNUM(conn))) {
485 const char *p = strrchr_m(path,'/');
486 if (p) {
487 p++;
488 } else {
489 p = path;
492 /* Only . and .. are not hidden. */
493 if (p[0] == '.' && !((p[1] == '\0') ||
494 (p[1] == '.' && p[2] == '\0'))) {
495 result |= aHIDDEN;
499 #ifdef HAVE_STAT_DOS_FLAGS
500 used_stat_dos_flags = get_stat_dos_flags(conn, path, &sbuf, &result);
501 #endif
502 if (!used_stat_dos_flags) {
503 /* Get the DOS attributes from an EA by preference. */
504 if (get_ea_dos_attribute(conn, path, &sbuf, &result)) {
505 result |= set_sparse_flag(&sbuf);
506 } else {
507 result |= dos_mode_from_sbuf(conn, path, &sbuf);
511 offline = SMB_VFS_IS_OFFLINE(conn, path, &sbuf);
512 if (S_ISREG(sbuf.st_ex_mode) && offline) {
513 result |= FILE_ATTRIBUTE_OFFLINE;
516 /* Optimization : Only call is_hidden_path if it's not already
517 hidden. */
518 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
519 result |= aHIDDEN;
522 DEBUG(8,("dos_mode returning "));
524 if (result & aHIDDEN) DEBUG(8, ("h"));
525 if (result & aRONLY ) DEBUG(8, ("r"));
526 if (result & aSYSTEM) DEBUG(8, ("s"));
527 if (result & aDIR ) DEBUG(8, ("d"));
528 if (result & aARCH ) DEBUG(8, ("a"));
529 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
531 DEBUG(8,("\n"));
533 return(result);
536 /*******************************************************************
537 chmod a file - but preserve some bits.
538 ********************************************************************/
540 int file_set_dosmode(connection_struct *conn, const char *fname,
541 uint32 dosmode, SMB_STRUCT_STAT *st,
542 const char *parent_dir,
543 bool newfile)
545 SMB_STRUCT_STAT st1;
546 int mask=0;
547 mode_t tmp;
548 mode_t unixmode;
549 int ret = -1, lret = -1;
550 uint32_t old_mode;
552 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
553 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
555 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
557 if (st == NULL) {
558 SET_STAT_INVALID(st1);
559 st = &st1;
562 if (!VALID_STAT(*st)) {
563 if (SMB_VFS_STAT(conn,fname,st))
564 return(-1);
567 unixmode = st->st_ex_mode;
569 get_acl_group_bits(conn, fname, &st->st_ex_mode);
571 if (S_ISDIR(st->st_ex_mode))
572 dosmode |= aDIR;
573 else
574 dosmode &= ~aDIR;
576 old_mode = dos_mode(conn,fname,st);
578 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
579 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
580 lret = SMB_VFS_SET_OFFLINE(conn, fname);
581 if (lret == -1) {
582 DEBUG(0, ("set_dos_mode: client has asked to set "
583 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
584 "an error while setting it or it is not supported.\n",
585 parent_dir, fname));
590 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
591 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
593 if (old_mode == dosmode) {
594 st->st_ex_mode = unixmode;
595 return(0);
598 #ifdef HAVE_STAT_DOS_FLAGS
600 bool attributes_changed;
602 if (set_stat_dos_flags(conn, fname, st, dosmode,
603 &attributes_changed))
605 if (!newfile && attributes_changed) {
606 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
607 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
609 st->st_ex_mode = unixmode;
610 return 0;
613 #endif
615 /* Store the DOS attributes in an EA by preference. */
616 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
617 if (!newfile) {
618 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
619 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
621 st->st_ex_mode = unixmode;
622 return 0;
625 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
627 /* preserve the s bits */
628 mask |= (S_ISUID | S_ISGID);
630 /* preserve the t bit */
631 #ifdef S_ISVTX
632 mask |= S_ISVTX;
633 #endif
635 /* possibly preserve the x bits */
636 if (!MAP_ARCHIVE(conn))
637 mask |= S_IXUSR;
638 if (!MAP_SYSTEM(conn))
639 mask |= S_IXGRP;
640 if (!MAP_HIDDEN(conn))
641 mask |= S_IXOTH;
643 unixmode |= (st->st_ex_mode & mask);
645 /* if we previously had any r bits set then leave them alone */
646 if ((tmp = st->st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
647 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
648 unixmode |= tmp;
651 /* if we previously had any w bits set then leave them alone
652 whilst adding in the new w bits, if the new mode is not rdonly */
653 if (!IS_DOS_READONLY(dosmode)) {
654 unixmode |= (st->st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
657 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
658 if (ret == 0) {
659 if(!newfile || (lret != -1)) {
660 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
661 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
663 st->st_ex_mode = unixmode;
664 return 0;
667 if((errno != EPERM) && (errno != EACCES))
668 return -1;
670 if(!lp_dos_filemode(SNUM(conn)))
671 return -1;
673 /* We want DOS semantics, ie allow non owner with write permission to change the
674 bits on a file. Just like file_ntimes below.
677 /* Check if we have write access. */
678 if (CAN_WRITE(conn)) {
680 * We need to open the file with write access whilst
681 * still in our current user context. This ensures we
682 * are not violating security in doing the fchmod.
683 * This file open does *not* break any oplocks we are
684 * holding. We need to review this.... may need to
685 * break batch oplocks open by others. JRA.
687 files_struct *fsp;
688 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
689 &fsp)))
690 return -1;
691 become_root();
692 ret = SMB_VFS_FCHMOD(fsp, unixmode);
693 unbecome_root();
694 close_file_fchmod(NULL, fsp);
695 if (!newfile) {
696 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
697 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
699 if (ret == 0) {
700 st->st_ex_mode = unixmode;
704 return( ret );
707 /*******************************************************************
708 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
709 than POSIX.
710 *******************************************************************/
712 int file_ntimes(connection_struct *conn, const char *fname,
713 struct smb_file_time *ft)
715 SMB_STRUCT_STAT sbuf;
716 int ret = -1;
718 errno = 0;
719 ZERO_STRUCT(sbuf);
721 DEBUG(6, ("file_ntime: actime: %s",
722 time_to_asc(convert_timespec_to_time_t(ft->atime))));
723 DEBUG(6, ("file_ntime: modtime: %s",
724 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
725 DEBUG(6, ("file_ntime: createtime: %s",
726 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
728 /* Don't update the time on read-only shares */
729 /* We need this as set_filetime (which can be called on
730 close and other paths) can end up calling this function
731 without the NEED_WRITE protection. Found by :
732 Leo Weppelman <leo@wau.mis.ah.nl>
735 if (!CAN_WRITE(conn)) {
736 return 0;
739 if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
740 return 0;
743 if((errno != EPERM) && (errno != EACCES)) {
744 return -1;
747 if(!lp_dos_filetimes(SNUM(conn))) {
748 return -1;
751 /* We have permission (given by the Samba admin) to
752 break POSIX semantics and allow a user to change
753 the time on a file they don't own but can write to
754 (as DOS does).
757 /* Check if we have write access. */
758 if (can_write_to_file(conn, fname, &sbuf)) {
759 /* We are allowed to become root and change the filetime. */
760 become_root();
761 ret = SMB_VFS_NTIMES(conn, fname, ft);
762 unbecome_root();
765 return ret;
768 /******************************************************************
769 Force a "sticky" write time on a pathname. This will always be
770 returned on all future write time queries and set on close.
771 ******************************************************************/
773 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
774 struct file_id fileid, const struct timespec mtime)
776 if (null_timespec(mtime)) {
777 return true;
780 if (!set_sticky_write_time(fileid, mtime)) {
781 return false;
784 return true;
787 /******************************************************************
788 Force a "sticky" write time on an fsp. This will always be
789 returned on all future write time queries and set on close.
790 ******************************************************************/
792 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
794 fsp->write_time_forced = true;
795 TALLOC_FREE(fsp->update_write_time_event);
797 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
798 fsp->file_id, mtime);
801 /******************************************************************
802 Update a write time immediately, without the 2 second delay.
803 ******************************************************************/
805 bool update_write_time(struct files_struct *fsp)
807 if (!set_write_time(fsp->file_id, timespec_current())) {
808 return false;
811 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
812 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
814 return true;