s3-printing: remove pcap_cache_loaded asserts
[Samba.git] / source3 / smbd / dosmode.c
blob2092712fbdecb9fd718931c614aa69b1432f7b9d
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 uint32_t filter_mode_by_protocol(uint32_t mode)
27 if (Protocol <= PROTOCOL_LANMAN2) {
28 DEBUG(10,("filter_mode_by_protocol: "
29 "filtering result 0x%x to 0x%x\n",
30 (unsigned int)mode,
31 (unsigned int)(mode & 0x3f) ));
32 mode &= 0x3f;
34 return mode;
37 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
39 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
40 if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
41 return FILE_ATTRIBUTE_SPARSE;
43 #endif
44 return 0;
47 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
49 #ifdef S_ISLNK
50 #if LINKS_READ_ONLY
51 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
52 return aRONLY;
53 #endif
54 #endif
55 return 0;
58 /****************************************************************************
59 Change a dos mode to a unix mode.
60 Base permission for files:
61 if creating file and inheriting (i.e. parent_dir != NULL)
62 apply read/write bits from parent directory.
63 else
64 everybody gets read bit set
65 dos readonly is represented in unix by removing everyone's write bit
66 dos archive is represented in unix by the user's execute bit
67 dos system is represented in unix by the group's execute bit
68 dos hidden is represented in unix by the other's execute bit
69 if !inheriting {
70 Then apply create mask,
71 then add force bits.
73 Base permission for directories:
74 dos directory is represented in unix by unix's dir bit and the exec bit
75 if !inheriting {
76 Then apply create mask,
77 then add force bits.
79 ****************************************************************************/
81 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
82 const char *inherit_from_dir)
84 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
85 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
86 * inheriting. */
88 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
89 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
92 if (fname && (inherit_from_dir != NULL)
93 && lp_inherit_perms(SNUM(conn))) {
94 SMB_STRUCT_STAT sbuf;
96 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
97 inherit_from_dir));
98 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
99 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
100 inherit_from_dir, strerror(errno)));
101 return(0); /* *** shouldn't happen! *** */
104 /* Save for later - but explicitly remove setuid bit for safety. */
105 dir_mode = sbuf.st_mode & ~S_ISUID;
106 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
107 /* Clear "result" */
108 result = 0;
111 if (IS_DOS_DIR(dosmode)) {
112 /* We never make directories read only for the owner as under DOS a user
113 can always create a file in a read-only directory. */
114 result |= (S_IFDIR | S_IWUSR);
116 if (dir_mode) {
117 /* Inherit mode of parent directory. */
118 result |= dir_mode;
119 } else {
120 /* Provisionally add all 'x' bits */
121 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
123 /* Apply directory mask */
124 result &= lp_dir_mask(SNUM(conn));
125 /* Add in force bits */
126 result |= lp_force_dir_mode(SNUM(conn));
128 } else {
129 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
130 result |= S_IXUSR;
132 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
133 result |= S_IXGRP;
135 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
136 result |= S_IXOTH;
138 if (dir_mode) {
139 /* Inherit 666 component of parent directory mode */
140 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
141 } else {
142 /* Apply mode mask */
143 result &= lp_create_mask(SNUM(conn));
144 /* Add in force bits */
145 result |= lp_force_create_mode(SNUM(conn));
149 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
150 return(result);
153 /****************************************************************************
154 Change a unix mode to a dos mode.
155 ****************************************************************************/
157 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
159 int result = 0;
160 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
162 if (ro_opts == MAP_READONLY_YES) {
163 /* Original Samba method - map inverse of user "w" bit. */
164 if ((sbuf->st_mode & S_IWUSR) == 0) {
165 result |= aRONLY;
167 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
168 /* Check actual permissions for read-only. */
169 if (!can_write_to_file(conn, path, sbuf)) {
170 result |= aRONLY;
172 } /* Else never set the readonly bit. */
174 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
175 result |= aARCH;
177 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
178 result |= aSYSTEM;
180 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
181 result |= aHIDDEN;
183 if (S_ISDIR(sbuf->st_mode))
184 result = aDIR | (result & aRONLY);
186 result |= set_sparse_flag(sbuf);
187 result |= set_link_read_only_flag(sbuf);
189 DEBUG(8,("dos_mode_from_sbuf returning "));
191 if (result & aHIDDEN) DEBUG(8, ("h"));
192 if (result & aRONLY ) DEBUG(8, ("r"));
193 if (result & aSYSTEM) DEBUG(8, ("s"));
194 if (result & aDIR ) DEBUG(8, ("d"));
195 if (result & aARCH ) DEBUG(8, ("a"));
197 DEBUG(8,("\n"));
198 return result;
201 /****************************************************************************
202 Get DOS attributes from an EA.
203 ****************************************************************************/
205 static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
207 ssize_t sizeret;
208 fstring attrstr;
209 unsigned int dosattr;
211 if (!lp_store_dos_attributes(SNUM(conn))) {
212 return False;
215 /* Don't reset pattr to zero as we may already have filename-based attributes we
216 need to preserve. */
218 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
219 if (sizeret == -1) {
220 if (errno == ENOSYS
221 #if defined(ENOTSUP)
222 || errno == ENOTSUP) {
223 #else
225 #endif
226 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
227 path, strerror(errno) ));
228 set_store_dos_attributes(SNUM(conn), False);
230 return False;
232 /* Null terminate string. */
233 attrstr[sizeret] = 0;
234 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
236 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
237 sscanf(attrstr, "%x", &dosattr) != 1) {
238 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
239 return False;
242 if (S_ISDIR(sbuf->st_mode)) {
243 dosattr |= aDIR;
245 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
247 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
249 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
250 if (dosattr & aRONLY ) DEBUG(8, ("r"));
251 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
252 if (dosattr & aDIR ) DEBUG(8, ("d"));
253 if (dosattr & aARCH ) DEBUG(8, ("a"));
255 DEBUG(8,("\n"));
257 return True;
260 /****************************************************************************
261 Set DOS attributes in an EA.
262 ****************************************************************************/
264 static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
266 fstring attrstr;
267 files_struct *fsp = NULL;
268 bool ret = False;
270 if (!lp_store_dos_attributes(SNUM(conn))) {
271 return False;
274 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
275 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
276 if((errno != EPERM) && (errno != EACCES)) {
277 if (errno == ENOSYS
278 #if defined(ENOTSUP)
279 || errno == ENOTSUP) {
280 #else
282 #endif
283 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
284 path, strerror(errno) ));
285 set_store_dos_attributes(SNUM(conn), False);
287 return False;
290 /* We want DOS semantics, ie allow non owner with write permission to change the
291 bits on a file. Just like file_ntimes below.
294 /* Check if we have write access. */
295 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
296 return False;
299 * We need to open the file with write access whilst
300 * still in our current user context. This ensures we
301 * are not violating security in doing the setxattr.
304 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, path, sbuf,
305 &fsp)))
306 return ret;
307 become_root();
308 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
309 ret = True;
311 unbecome_root();
312 close_file(NULL, fsp, NORMAL_CLOSE);
313 return ret;
315 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
316 return True;
319 /****************************************************************************
320 Change a unix mode to a dos mode for an ms dfs link.
321 ****************************************************************************/
323 uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
325 uint32 result = 0;
327 DEBUG(8,("dos_mode_msdfs: %s\n", path));
329 if (!VALID_STAT(*sbuf)) {
330 return 0;
333 /* First do any modifications that depend on the path name. */
334 /* hide files with a name starting with a . */
335 if (lp_hide_dot_files(SNUM(conn))) {
336 const char *p = strrchr_m(path,'/');
337 if (p) {
338 p++;
339 } else {
340 p = path;
343 /* Only . and .. are not hidden. */
344 if (p[0] == '.' && !((p[1] == '\0') ||
345 (p[1] == '.' && p[2] == '\0'))) {
346 result |= aHIDDEN;
350 result |= dos_mode_from_sbuf(conn, path, sbuf);
352 /* Optimization : Only call is_hidden_path if it's not already
353 hidden. */
354 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
355 result |= aHIDDEN;
358 if (result == 0) {
359 result = FILE_ATTRIBUTE_NORMAL;
362 result = filter_mode_by_protocol(result);
364 DEBUG(8,("dos_mode_msdfs returning "));
366 if (result & aHIDDEN) DEBUG(8, ("h"));
367 if (result & aRONLY ) DEBUG(8, ("r"));
368 if (result & aSYSTEM) DEBUG(8, ("s"));
369 if (result & aDIR ) DEBUG(8, ("d"));
370 if (result & aARCH ) DEBUG(8, ("a"));
371 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
373 DEBUG(8,("\n"));
375 return(result);
378 #ifdef HAVE_STAT_DOS_FLAGS
379 /****************************************************************************
380 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
381 ****************************************************************************/
383 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
385 uint32_t dos_stat_flags = 0;
387 if (dosmode & aARCH)
388 dos_stat_flags |= UF_DOS_ARCHIVE;
389 if (dosmode & aHIDDEN)
390 dos_stat_flags |= UF_DOS_HIDDEN;
391 if (dosmode & aRONLY)
392 dos_stat_flags |= UF_DOS_RO;
393 if (dosmode & aSYSTEM)
394 dos_stat_flags |= UF_DOS_SYSTEM;
395 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
396 dos_stat_flags |= UF_DOS_NOINDEX;
398 return dos_stat_flags;
401 /****************************************************************************
402 Gets DOS attributes, accessed via st_flags in the stat struct.
403 ****************************************************************************/
405 static bool get_stat_dos_flags(connection_struct *conn,
406 const char *fname,
407 const SMB_STRUCT_STAT *sbuf,
408 uint32_t *dosmode)
410 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
411 SMB_ASSERT(dosmode);
413 if (!lp_store_dos_attributes(SNUM(conn))) {
414 return false;
417 DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
419 if (sbuf->st_flags & UF_DOS_ARCHIVE)
420 *dosmode |= aARCH;
421 if (sbuf->st_flags & UF_DOS_HIDDEN)
422 *dosmode |= aHIDDEN;
423 if (sbuf->st_flags & UF_DOS_RO)
424 *dosmode |= aRONLY;
425 if (sbuf->st_flags & UF_DOS_SYSTEM)
426 *dosmode |= aSYSTEM;
427 if (sbuf->st_flags & UF_DOS_NOINDEX)
428 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
429 if (S_ISDIR(sbuf->st_mode))
430 *dosmode |= aDIR;
432 *dosmode |= set_sparse_flag(sbuf);
433 *dosmode |= set_link_read_only_flag(sbuf);
435 return true;
438 /****************************************************************************
439 Sets DOS attributes, stored in st_flags of the inode.
440 ****************************************************************************/
442 static bool set_stat_dos_flags(connection_struct *conn,
443 const char *fname,
444 SMB_STRUCT_STAT *sbuf,
445 uint32_t dosmode,
446 bool *attributes_changed)
448 uint32_t new_flags = 0;
449 int error = 0;
451 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
452 SMB_ASSERT(attributes_changed);
454 *attributes_changed = false;
456 if (!lp_store_dos_attributes(SNUM(conn))) {
457 return false;
460 DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
462 new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) |
463 dos_attributes_to_stat_dos_flags(dosmode);
465 /* Return early if no flags changed. */
466 if (new_flags == sbuf->st_flags)
467 return true;
469 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
470 sbuf->st_flags));
472 /* Set new flags with chflags. */
473 error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
474 if (error) {
475 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
476 "file %s! errno=%d\n", new_flags, fname, errno));
477 return false;
480 *attributes_changed = true;
481 return true;
483 #endif /* HAVE_STAT_DOS_FLAGS */
485 /****************************************************************************
486 Change a unix mode to a dos mode.
487 ****************************************************************************/
489 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
491 uint32 result = 0;
492 bool offline, used_stat_dos_flags = false;
494 DEBUG(8,("dos_mode: %s\n", path));
496 if (!VALID_STAT(*sbuf)) {
497 return 0;
500 /* First do any modifications that depend on the path name. */
501 /* hide files with a name starting with a . */
502 if (lp_hide_dot_files(SNUM(conn))) {
503 const char *p = strrchr_m(path,'/');
504 if (p) {
505 p++;
506 } else {
507 p = path;
510 /* Only . and .. are not hidden. */
511 if (p[0] == '.' && !((p[1] == '\0') ||
512 (p[1] == '.' && p[2] == '\0'))) {
513 result |= aHIDDEN;
517 #ifdef HAVE_STAT_DOS_FLAGS
518 used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result);
519 #endif
520 if (!used_stat_dos_flags) {
521 /* Get the DOS attributes from an EA by preference. */
522 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
523 result |= set_sparse_flag(sbuf);
524 } else {
525 result |= dos_mode_from_sbuf(conn, path, sbuf);
530 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
531 if (S_ISREG(sbuf->st_mode) && offline) {
532 result |= FILE_ATTRIBUTE_OFFLINE;
535 /* Optimization : Only call is_hidden_path if it's not already
536 hidden. */
537 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
538 result |= aHIDDEN;
541 if (result == 0) {
542 result = FILE_ATTRIBUTE_NORMAL;
545 result = filter_mode_by_protocol(result);
547 DEBUG(8,("dos_mode returning "));
549 if (result & aHIDDEN) DEBUG(8, ("h"));
550 if (result & aRONLY ) DEBUG(8, ("r"));
551 if (result & aSYSTEM) DEBUG(8, ("s"));
552 if (result & aDIR ) DEBUG(8, ("d"));
553 if (result & aARCH ) DEBUG(8, ("a"));
554 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
556 DEBUG(8,("\n"));
558 return(result);
561 /*******************************************************************
562 chmod a file - but preserve some bits.
563 ********************************************************************/
565 int file_set_dosmode(connection_struct *conn, const char *fname,
566 uint32 dosmode, SMB_STRUCT_STAT *st,
567 const char *parent_dir,
568 bool newfile)
570 SMB_STRUCT_STAT st1;
571 int mask=0;
572 mode_t tmp;
573 mode_t unixmode;
574 int ret = -1, lret = -1;
575 uint32_t old_mode;
577 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
578 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
580 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
582 if (st == NULL) {
583 SET_STAT_INVALID(st1);
584 st = &st1;
587 if (!VALID_STAT(*st)) {
588 if (SMB_VFS_STAT(conn,fname,st))
589 return(-1);
592 unixmode = st->st_mode;
594 get_acl_group_bits(conn, fname, &st->st_mode);
596 if (S_ISDIR(st->st_mode))
597 dosmode |= aDIR;
598 else
599 dosmode &= ~aDIR;
601 old_mode = dos_mode(conn,fname,st);
603 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
604 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
605 lret = SMB_VFS_SET_OFFLINE(conn, fname);
606 if (lret == -1) {
607 DEBUG(0, ("set_dos_mode: client has asked to set "
608 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
609 "an error while setting it or it is not supported.\n",
610 parent_dir, fname));
615 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
616 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
618 if (old_mode == dosmode) {
619 st->st_mode = unixmode;
620 return(0);
623 #ifdef HAVE_STAT_DOS_FLAGS
625 bool attributes_changed;
627 if (set_stat_dos_flags(conn, fname, st, dosmode,
628 &attributes_changed))
630 if (!newfile && attributes_changed) {
631 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
632 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
634 st->st_mode = unixmode;
635 return 0;
638 #endif
640 /* Store the DOS attributes in an EA by preference. */
641 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
642 if (!newfile) {
643 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
644 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
646 st->st_mode = unixmode;
647 return 0;
650 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
652 /* preserve the s bits */
653 mask |= (S_ISUID | S_ISGID);
655 /* preserve the t bit */
656 #ifdef S_ISVTX
657 mask |= S_ISVTX;
658 #endif
660 /* possibly preserve the x bits */
661 if (!MAP_ARCHIVE(conn))
662 mask |= S_IXUSR;
663 if (!MAP_SYSTEM(conn))
664 mask |= S_IXGRP;
665 if (!MAP_HIDDEN(conn))
666 mask |= S_IXOTH;
668 unixmode |= (st->st_mode & mask);
670 /* if we previously had any r bits set then leave them alone */
671 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
672 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
673 unixmode |= tmp;
676 /* if we previously had any w bits set then leave them alone
677 whilst adding in the new w bits, if the new mode is not rdonly */
678 if (!IS_DOS_READONLY(dosmode)) {
679 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
682 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
683 if (ret == 0) {
684 if(!newfile || (lret != -1)) {
685 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
686 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
688 st->st_mode = unixmode;
689 return 0;
692 if((errno != EPERM) && (errno != EACCES))
693 return -1;
695 if(!lp_dos_filemode(SNUM(conn)))
696 return -1;
698 /* We want DOS semantics, ie allow non owner with write permission to change the
699 bits on a file. Just like file_ntimes below.
702 /* Check if we have write access. */
703 if (CAN_WRITE(conn)) {
705 * We need to open the file with write access whilst
706 * still in our current user context. This ensures we
707 * are not violating security in doing the fchmod.
709 files_struct *fsp;
710 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, fname, st,
711 &fsp)))
712 return -1;
713 become_root();
714 ret = SMB_VFS_FCHMOD(fsp, unixmode);
715 unbecome_root();
716 close_file(NULL, fsp, NORMAL_CLOSE);
717 if (!newfile) {
718 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
719 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
721 if (ret == 0) {
722 st->st_mode = unixmode;
726 return( ret );
729 /*******************************************************************
730 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
731 than POSIX.
732 *******************************************************************/
734 int file_ntimes(connection_struct *conn, const char *fname,
735 struct smb_file_time *ft)
737 SMB_STRUCT_STAT sbuf;
738 int ret = -1;
740 errno = 0;
741 ZERO_STRUCT(sbuf);
743 DEBUG(6, ("file_ntime: actime: %s",
744 time_to_asc(convert_timespec_to_time_t(ft->atime))));
745 DEBUG(6, ("file_ntime: modtime: %s",
746 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
747 DEBUG(6, ("file_ntime: createtime: %s",
748 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
750 /* Don't update the time on read-only shares */
751 /* We need this as set_filetime (which can be called on
752 close and other paths) can end up calling this function
753 without the NEED_WRITE protection. Found by :
754 Leo Weppelman <leo@wau.mis.ah.nl>
757 if (!CAN_WRITE(conn)) {
758 return 0;
761 if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
762 return 0;
765 if((errno != EPERM) && (errno != EACCES)) {
766 return -1;
769 if(!lp_dos_filetimes(SNUM(conn))) {
770 return -1;
773 /* We have permission (given by the Samba admin) to
774 break POSIX semantics and allow a user to change
775 the time on a file they don't own but can write to
776 (as DOS does).
779 /* Check if we have write access. */
780 if (can_write_to_file(conn, fname, &sbuf)) {
781 /* We are allowed to become root and change the filetime. */
782 become_root();
783 ret = SMB_VFS_NTIMES(conn, fname, ft);
784 unbecome_root();
787 return ret;
790 /******************************************************************
791 Force a "sticky" write time on a pathname. This will always be
792 returned on all future write time queries and set on close.
793 ******************************************************************/
795 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
796 struct file_id fileid, const struct timespec mtime)
798 if (null_timespec(mtime)) {
799 return true;
802 if (!set_sticky_write_time(fileid, mtime)) {
803 return false;
806 return true;
809 /******************************************************************
810 Force a "sticky" write time on an fsp. This will always be
811 returned on all future write time queries and set on close.
812 ******************************************************************/
814 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
816 fsp->write_time_forced = true;
817 TALLOC_FREE(fsp->update_write_time_event);
819 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
820 fsp->file_id, mtime);
823 /******************************************************************
824 Update a write time immediately, without the 2 second delay.
825 ******************************************************************/
827 bool update_write_time(struct files_struct *fsp)
829 if (!set_write_time(fsp->file_id, timespec_current())) {
830 return false;
833 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
834 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
836 return true;