s3: Fix bug 6338 -- net rpc trustdom list always display "none"
[Samba/gbeck.git] / source3 / smbd / dosmode.c
blob45ea74d7e4136e0eac77584cf3c3d275c9b5a76d
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 extern enum protocol_types Protocol;
25 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
27 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
28 if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
29 return FILE_ATTRIBUTE_SPARSE;
31 #endif
32 return 0;
35 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
37 #ifdef S_ISLNK
38 #if LINKS_READ_ONLY
39 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
40 return aRONLY;
41 #endif
42 #endif
43 return 0;
46 /****************************************************************************
47 Change a dos mode to a unix mode.
48 Base permission for files:
49 if creating file and inheriting (i.e. parent_dir != NULL)
50 apply read/write bits from parent directory.
51 else
52 everybody gets read bit set
53 dos readonly is represented in unix by removing everyone's write bit
54 dos archive is represented in unix by the user's execute bit
55 dos system is represented in unix by the group's execute bit
56 dos hidden is represented in unix by the other's execute bit
57 if !inheriting {
58 Then apply create mask,
59 then add force bits.
61 Base permission for directories:
62 dos directory is represented in unix by unix's dir bit and the exec bit
63 if !inheriting {
64 Then apply create mask,
65 then add force bits.
67 ****************************************************************************/
69 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
70 const char *inherit_from_dir)
72 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
73 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
74 * inheriting. */
76 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
77 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
80 if (fname && (inherit_from_dir != NULL)
81 && lp_inherit_perms(SNUM(conn))) {
82 SMB_STRUCT_STAT sbuf;
84 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
85 inherit_from_dir));
86 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
87 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
88 inherit_from_dir, strerror(errno)));
89 return(0); /* *** shouldn't happen! *** */
92 /* Save for later - but explicitly remove setuid bit for safety. */
93 dir_mode = sbuf.st_mode & ~S_ISUID;
94 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
95 /* Clear "result" */
96 result = 0;
99 if (IS_DOS_DIR(dosmode)) {
100 /* We never make directories read only for the owner as under DOS a user
101 can always create a file in a read-only directory. */
102 result |= (S_IFDIR | S_IWUSR);
104 if (dir_mode) {
105 /* Inherit mode of parent directory. */
106 result |= dir_mode;
107 } else {
108 /* Provisionally add all 'x' bits */
109 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
111 /* Apply directory mask */
112 result &= lp_dir_mask(SNUM(conn));
113 /* Add in force bits */
114 result |= lp_force_dir_mode(SNUM(conn));
116 } else {
117 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
118 result |= S_IXUSR;
120 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
121 result |= S_IXGRP;
123 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
124 result |= S_IXOTH;
126 if (dir_mode) {
127 /* Inherit 666 component of parent directory mode */
128 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
129 } else {
130 /* Apply mode mask */
131 result &= lp_create_mask(SNUM(conn));
132 /* Add in force bits */
133 result |= lp_force_create_mode(SNUM(conn));
137 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
138 return(result);
141 /****************************************************************************
142 Change a unix mode to a dos mode.
143 ****************************************************************************/
145 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
147 int result = 0;
148 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
150 if (ro_opts == MAP_READONLY_YES) {
151 /* Original Samba method - map inverse of user "w" bit. */
152 if ((sbuf->st_mode & S_IWUSR) == 0) {
153 result |= aRONLY;
155 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
156 /* Check actual permissions for read-only. */
157 if (!can_write_to_file(conn, path, sbuf)) {
158 result |= aRONLY;
160 } /* Else never set the readonly bit. */
162 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
163 result |= aARCH;
165 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
166 result |= aSYSTEM;
168 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
169 result |= aHIDDEN;
171 if (S_ISDIR(sbuf->st_mode))
172 result = aDIR | (result & aRONLY);
174 result |= set_sparse_flag(sbuf);
175 result |= set_link_read_only_flag(sbuf);
177 DEBUG(8,("dos_mode_from_sbuf returning "));
179 if (result & aHIDDEN) DEBUG(8, ("h"));
180 if (result & aRONLY ) DEBUG(8, ("r"));
181 if (result & aSYSTEM) DEBUG(8, ("s"));
182 if (result & aDIR ) DEBUG(8, ("d"));
183 if (result & aARCH ) DEBUG(8, ("a"));
185 DEBUG(8,("\n"));
186 return result;
189 /****************************************************************************
190 Get DOS attributes from an EA.
191 ****************************************************************************/
193 static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
195 ssize_t sizeret;
196 fstring attrstr;
197 unsigned int dosattr;
199 if (!lp_store_dos_attributes(SNUM(conn))) {
200 return False;
203 /* Don't reset pattr to zero as we may already have filename-based attributes we
204 need to preserve. */
206 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
207 if (sizeret == -1) {
208 if (errno == ENOSYS
209 #if defined(ENOTSUP)
210 || errno == ENOTSUP) {
211 #else
213 #endif
214 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
215 path, strerror(errno) ));
216 set_store_dos_attributes(SNUM(conn), False);
218 return False;
220 /* Null terminate string. */
221 attrstr[sizeret] = 0;
222 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
224 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
225 sscanf(attrstr, "%x", &dosattr) != 1) {
226 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
227 return False;
230 if (S_ISDIR(sbuf->st_mode)) {
231 dosattr |= aDIR;
233 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
235 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
237 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
238 if (dosattr & aRONLY ) DEBUG(8, ("r"));
239 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
240 if (dosattr & aDIR ) DEBUG(8, ("d"));
241 if (dosattr & aARCH ) DEBUG(8, ("a"));
243 DEBUG(8,("\n"));
245 return True;
248 /****************************************************************************
249 Set DOS attributes in an EA.
250 ****************************************************************************/
252 static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
254 fstring attrstr;
255 files_struct *fsp = NULL;
256 bool ret = False;
258 if (!lp_store_dos_attributes(SNUM(conn))) {
259 return False;
262 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
263 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
264 if((errno != EPERM) && (errno != EACCES)) {
265 if (errno == ENOSYS
266 #if defined(ENOTSUP)
267 || errno == ENOTSUP) {
268 #else
270 #endif
271 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
272 path, strerror(errno) ));
273 set_store_dos_attributes(SNUM(conn), False);
275 return False;
278 /* We want DOS semantics, ie allow non owner with write permission to change the
279 bits on a file. Just like file_ntimes below.
282 /* Check if we have write access. */
283 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
284 return False;
287 * We need to open the file with write access whilst
288 * still in our current user context. This ensures we
289 * are not violating security in doing the setxattr.
292 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf,
293 &fsp)))
294 return ret;
295 become_root();
296 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
297 ret = True;
299 unbecome_root();
300 close_file_fchmod(NULL, fsp);
301 return ret;
303 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
304 return True;
307 /****************************************************************************
308 Change a unix mode to a dos mode for an ms dfs link.
309 ****************************************************************************/
311 uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
313 uint32 result = 0;
315 DEBUG(8,("dos_mode_msdfs: %s\n", path));
317 if (!VALID_STAT(*sbuf)) {
318 return 0;
321 /* First do any modifications that depend on the path name. */
322 /* hide files with a name starting with a . */
323 if (lp_hide_dot_files(SNUM(conn))) {
324 const char *p = strrchr_m(path,'/');
325 if (p) {
326 p++;
327 } else {
328 p = path;
331 /* Only . and .. are not hidden. */
332 if (p[0] == '.' && !((p[1] == '\0') ||
333 (p[1] == '.' && p[2] == '\0'))) {
334 result |= aHIDDEN;
338 result |= dos_mode_from_sbuf(conn, path, sbuf);
340 /* Optimization : Only call is_hidden_path if it's not already
341 hidden. */
342 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
343 result |= aHIDDEN;
346 if (Protocol <= PROTOCOL_LANMAN2) {
347 DEBUG(10,("dos_mode_msdfs : filtering result 0x%x\n",
348 (unsigned int)result ));
349 result &= 0xff;
352 DEBUG(8,("dos_mode_msdfs returning "));
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]"));
361 DEBUG(8,("\n"));
363 return(result);
366 #ifdef HAVE_STAT_DOS_FLAGS
367 /****************************************************************************
368 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
369 ****************************************************************************/
371 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
373 uint32_t dos_stat_flags = 0;
375 if (dosmode & aARCH)
376 dos_stat_flags |= UF_DOS_ARCHIVE;
377 if (dosmode & aHIDDEN)
378 dos_stat_flags |= UF_DOS_HIDDEN;
379 if (dosmode & aRONLY)
380 dos_stat_flags |= UF_DOS_RO;
381 if (dosmode & aSYSTEM)
382 dos_stat_flags |= UF_DOS_SYSTEM;
383 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
384 dos_stat_flags |= UF_DOS_NOINDEX;
386 return dos_stat_flags;
389 /****************************************************************************
390 Gets DOS attributes, accessed via st_flags in the stat struct.
391 ****************************************************************************/
393 static bool get_stat_dos_flags(connection_struct *conn,
394 const char *fname,
395 const SMB_STRUCT_STAT *sbuf,
396 uint32_t *dosmode)
398 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
399 SMB_ASSERT(dosmode);
401 if (!lp_store_dos_attributes(SNUM(conn))) {
402 return false;
405 DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
407 if (sbuf->st_flags & UF_DOS_ARCHIVE)
408 *dosmode |= aARCH;
409 if (sbuf->st_flags & UF_DOS_HIDDEN)
410 *dosmode |= aHIDDEN;
411 if (sbuf->st_flags & UF_DOS_RO)
412 *dosmode |= aRONLY;
413 if (sbuf->st_flags & UF_DOS_SYSTEM)
414 *dosmode |= aSYSTEM;
415 if (sbuf->st_flags & UF_DOS_NOINDEX)
416 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
417 if (S_ISDIR(sbuf->st_mode))
418 *dosmode |= aDIR;
420 *dosmode |= set_sparse_flag(sbuf);
421 *dosmode |= set_link_read_only_flag(sbuf);
423 return true;
426 /****************************************************************************
427 Sets DOS attributes, stored in st_flags of the inode.
428 ****************************************************************************/
430 static bool set_stat_dos_flags(connection_struct *conn,
431 const char *fname,
432 SMB_STRUCT_STAT *sbuf,
433 uint32_t dosmode,
434 bool *attributes_changed)
436 uint32_t new_flags = 0;
437 int error = 0;
439 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
440 SMB_ASSERT(attributes_changed);
442 *attributes_changed = false;
444 if (!lp_store_dos_attributes(SNUM(conn))) {
445 return false;
448 DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
450 new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) |
451 dos_attributes_to_stat_dos_flags(dosmode);
453 /* Return early if no flags changed. */
454 if (new_flags == sbuf->st_flags)
455 return true;
457 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
458 sbuf->st_flags));
460 /* Set new flags with chflags. */
461 error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
462 if (error) {
463 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
464 "file %s! errno=%d\n", new_flags, fname, errno));
465 return false;
468 *attributes_changed = true;
469 return true;
471 #endif /* HAVE_STAT_DOS_FLAGS */
473 /****************************************************************************
474 Change a unix mode to a dos mode.
475 ****************************************************************************/
477 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
479 uint32 result = 0;
480 bool offline, used_stat_dos_flags = false;
482 DEBUG(8,("dos_mode: %s\n", path));
484 if (!VALID_STAT(*sbuf)) {
485 return 0;
488 /* First do any modifications that depend on the path name. */
489 /* hide files with a name starting with a . */
490 if (lp_hide_dot_files(SNUM(conn))) {
491 const char *p = strrchr_m(path,'/');
492 if (p) {
493 p++;
494 } else {
495 p = path;
498 /* Only . and .. are not hidden. */
499 if (p[0] == '.' && !((p[1] == '\0') ||
500 (p[1] == '.' && p[2] == '\0'))) {
501 result |= aHIDDEN;
505 #ifdef HAVE_STAT_DOS_FLAGS
506 used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result);
507 #endif
508 if (!used_stat_dos_flags) {
509 /* Get the DOS attributes from an EA by preference. */
510 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
511 result |= set_sparse_flag(sbuf);
512 } else {
513 result |= dos_mode_from_sbuf(conn, path, sbuf);
518 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
519 if (S_ISREG(sbuf->st_mode) && offline) {
520 result |= FILE_ATTRIBUTE_OFFLINE;
523 /* Optimization : Only call is_hidden_path if it's not already
524 hidden. */
525 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
526 result |= aHIDDEN;
529 if (Protocol <= PROTOCOL_LANMAN2) {
530 DEBUG(10,("dos_mode : filtering result 0x%x\n",
531 (unsigned int)result ));
532 result &= 0xff;
535 DEBUG(8,("dos_mode returning "));
537 if (result & aHIDDEN) DEBUG(8, ("h"));
538 if (result & aRONLY ) DEBUG(8, ("r"));
539 if (result & aSYSTEM) DEBUG(8, ("s"));
540 if (result & aDIR ) DEBUG(8, ("d"));
541 if (result & aARCH ) DEBUG(8, ("a"));
542 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
544 DEBUG(8,("\n"));
546 return(result);
549 /*******************************************************************
550 chmod a file - but preserve some bits.
551 ********************************************************************/
553 int file_set_dosmode(connection_struct *conn, const char *fname,
554 uint32 dosmode, SMB_STRUCT_STAT *st,
555 const char *parent_dir,
556 bool newfile)
558 SMB_STRUCT_STAT st1;
559 int mask=0;
560 mode_t tmp;
561 mode_t unixmode;
562 int ret = -1, lret = -1;
563 uint32_t old_mode;
565 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
566 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
568 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
570 if (st == NULL) {
571 SET_STAT_INVALID(st1);
572 st = &st1;
575 if (!VALID_STAT(*st)) {
576 if (SMB_VFS_STAT(conn,fname,st))
577 return(-1);
580 unixmode = st->st_mode;
582 get_acl_group_bits(conn, fname, &st->st_mode);
584 if (S_ISDIR(st->st_mode))
585 dosmode |= aDIR;
586 else
587 dosmode &= ~aDIR;
589 old_mode = dos_mode(conn,fname,st);
591 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
592 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
593 lret = SMB_VFS_SET_OFFLINE(conn, fname);
594 if (lret == -1) {
595 DEBUG(0, ("set_dos_mode: client has asked to set "
596 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
597 "an error while setting it or it is not supported.\n",
598 parent_dir, fname));
603 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
604 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
606 if (old_mode == dosmode) {
607 st->st_mode = unixmode;
608 return(0);
611 #ifdef HAVE_STAT_DOS_FLAGS
613 bool attributes_changed;
615 if (set_stat_dos_flags(conn, fname, st, dosmode,
616 &attributes_changed))
618 if (!newfile && attributes_changed) {
619 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
620 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
622 st->st_mode = unixmode;
623 return 0;
626 #endif
628 /* Store the DOS attributes in an EA by preference. */
629 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
630 if (!newfile) {
631 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
632 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
634 st->st_mode = unixmode;
635 return 0;
638 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
640 /* preserve the s bits */
641 mask |= (S_ISUID | S_ISGID);
643 /* preserve the t bit */
644 #ifdef S_ISVTX
645 mask |= S_ISVTX;
646 #endif
648 /* possibly preserve the x bits */
649 if (!MAP_ARCHIVE(conn))
650 mask |= S_IXUSR;
651 if (!MAP_SYSTEM(conn))
652 mask |= S_IXGRP;
653 if (!MAP_HIDDEN(conn))
654 mask |= S_IXOTH;
656 unixmode |= (st->st_mode & mask);
658 /* if we previously had any r bits set then leave them alone */
659 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
660 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
661 unixmode |= tmp;
664 /* if we previously had any w bits set then leave them alone
665 whilst adding in the new w bits, if the new mode is not rdonly */
666 if (!IS_DOS_READONLY(dosmode)) {
667 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
670 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
671 if (ret == 0) {
672 if(!newfile || (lret != -1)) {
673 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
674 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
676 st->st_mode = unixmode;
677 return 0;
680 if((errno != EPERM) && (errno != EACCES))
681 return -1;
683 if(!lp_dos_filemode(SNUM(conn)))
684 return -1;
686 /* We want DOS semantics, ie allow non owner with write permission to change the
687 bits on a file. Just like file_ntimes below.
690 /* Check if we have write access. */
691 if (CAN_WRITE(conn)) {
693 * We need to open the file with write access whilst
694 * still in our current user context. This ensures we
695 * are not violating security in doing the fchmod.
696 * This file open does *not* break any oplocks we are
697 * holding. We need to review this.... may need to
698 * break batch oplocks open by others. JRA.
700 files_struct *fsp;
701 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
702 &fsp)))
703 return -1;
704 become_root();
705 ret = SMB_VFS_FCHMOD(fsp, unixmode);
706 unbecome_root();
707 close_file_fchmod(NULL, fsp);
708 if (!newfile) {
709 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
710 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
712 if (ret == 0) {
713 st->st_mode = unixmode;
717 return( ret );
720 /*******************************************************************
721 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
722 than POSIX.
723 *******************************************************************/
725 int file_ntimes(connection_struct *conn, const char *fname,
726 struct smb_file_time *ft)
728 SMB_STRUCT_STAT sbuf;
729 int ret = -1;
731 errno = 0;
732 ZERO_STRUCT(sbuf);
734 DEBUG(6, ("file_ntime: actime: %s",
735 time_to_asc(convert_timespec_to_time_t(ft->atime))));
736 DEBUG(6, ("file_ntime: modtime: %s",
737 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
738 DEBUG(6, ("file_ntime: createtime: %s",
739 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
741 /* Don't update the time on read-only shares */
742 /* We need this as set_filetime (which can be called on
743 close and other paths) can end up calling this function
744 without the NEED_WRITE protection. Found by :
745 Leo Weppelman <leo@wau.mis.ah.nl>
748 if (!CAN_WRITE(conn)) {
749 return 0;
752 if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
753 return 0;
756 if((errno != EPERM) && (errno != EACCES)) {
757 return -1;
760 if(!lp_dos_filetimes(SNUM(conn))) {
761 return -1;
764 /* We have permission (given by the Samba admin) to
765 break POSIX semantics and allow a user to change
766 the time on a file they don't own but can write to
767 (as DOS does).
770 /* Check if we have write access. */
771 if (can_write_to_file(conn, fname, &sbuf)) {
772 /* We are allowed to become root and change the filetime. */
773 become_root();
774 ret = SMB_VFS_NTIMES(conn, fname, ft);
775 unbecome_root();
778 return ret;
781 /******************************************************************
782 Force a "sticky" write time on a pathname. This will always be
783 returned on all future write time queries and set on close.
784 ******************************************************************/
786 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
787 struct file_id fileid, const struct timespec mtime)
789 if (null_timespec(mtime)) {
790 return true;
793 if (!set_sticky_write_time(fileid, mtime)) {
794 return false;
797 return true;
800 /******************************************************************
801 Force a "sticky" write time on an fsp. This will always be
802 returned on all future write time queries and set on close.
803 ******************************************************************/
805 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
807 fsp->write_time_forced = true;
808 TALLOC_FREE(fsp->update_write_time_event);
810 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
811 fsp->file_id, mtime);
814 /******************************************************************
815 Update a write time immediately, without the 2 second delay.
816 ******************************************************************/
818 bool update_write_time(struct files_struct *fsp)
820 if (!set_write_time(fsp->file_id, timespec_current())) {
821 return false;
824 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
825 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
827 return true;