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/>.
22 #include "librpc/gen_ndr/ndr_xattr.h"
24 static uint32_t filter_mode_by_protocol(uint32_t mode)
26 if (get_Protocol() <= PROTOCOL_LANMAN2) {
27 DEBUG(10,("filter_mode_by_protocol: "
28 "filtering result 0x%x to 0x%x\n",
30 (unsigned int)(mode & 0x3f) ));
36 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
38 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
39 if (sbuf->st_ex_size > sbuf->st_ex_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
40 return FILE_ATTRIBUTE_SPARSE;
46 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
50 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
57 /****************************************************************************
58 Change a dos mode to a unix mode.
59 Base permission for files:
60 if creating file and inheriting (i.e. parent_dir != NULL)
61 apply read/write bits from parent directory.
63 everybody gets read bit set
64 dos readonly is represented in unix by removing everyone's write bit
65 dos archive is represented in unix by the user's execute bit
66 dos system is represented in unix by the group's execute bit
67 dos hidden is represented in unix by the other's execute bit
69 Then apply create mask,
72 Base permission for directories:
73 dos directory is represented in unix by unix's dir bit and the exec bit
75 Then apply create mask,
78 ****************************************************************************/
80 mode_t unix_mode(connection_struct *conn, int dosmode,
81 const struct smb_filename *smb_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
88 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
89 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
92 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
93 struct smb_filename *smb_fname_parent = NULL;
96 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
97 smb_fname_str_dbg(smb_fname),
100 status = create_synthetic_smb_fname(talloc_tos(),
101 inherit_from_dir, NULL,
102 NULL, &smb_fname_parent);
103 if (!NT_STATUS_IS_OK(status)) {
104 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
105 smb_fname_str_dbg(smb_fname),
106 inherit_from_dir, nt_errstr(status)));
110 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
111 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
112 smb_fname_str_dbg(smb_fname),
113 inherit_from_dir, strerror(errno)));
114 TALLOC_FREE(smb_fname_parent);
115 return(0); /* *** shouldn't happen! *** */
118 /* Save for later - but explicitly remove setuid bit for safety. */
119 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
120 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
121 smb_fname_str_dbg(smb_fname), (int)dir_mode));
124 TALLOC_FREE(smb_fname_parent);
127 if (IS_DOS_DIR(dosmode)) {
128 /* We never make directories read only for the owner as under DOS a user
129 can always create a file in a read-only directory. */
130 result |= (S_IFDIR | S_IWUSR);
133 /* Inherit mode of parent directory. */
136 /* Provisionally add all 'x' bits */
137 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
139 /* Apply directory mask */
140 result &= lp_dir_mask(SNUM(conn));
141 /* Add in force bits */
142 result |= lp_force_dir_mode(SNUM(conn));
145 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
148 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
151 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
155 /* Inherit 666 component of parent directory mode */
156 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
158 /* Apply mode mask */
159 result &= lp_create_mask(SNUM(conn));
160 /* Add in force bits */
161 result |= lp_force_create_mode(SNUM(conn));
165 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
170 /****************************************************************************
171 Change a unix mode to a dos mode.
172 ****************************************************************************/
174 static uint32 dos_mode_from_sbuf(connection_struct *conn,
175 const struct smb_filename *smb_fname)
178 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
180 if (ro_opts == MAP_READONLY_YES) {
181 /* Original Samba method - map inverse of user "w" bit. */
182 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
185 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
186 /* Check actual permissions for read-only. */
187 if (!can_write_to_file(conn, smb_fname)) {
190 } /* Else never set the readonly bit. */
192 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
195 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
198 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
201 if (S_ISDIR(smb_fname->st.st_ex_mode))
202 result = aDIR | (result & aRONLY);
204 result |= set_sparse_flag(&smb_fname->st);
205 result |= set_link_read_only_flag(&smb_fname->st);
207 DEBUG(8,("dos_mode_from_sbuf returning "));
209 if (result & aHIDDEN) DEBUG(8, ("h"));
210 if (result & aRONLY ) DEBUG(8, ("r"));
211 if (result & aSYSTEM) DEBUG(8, ("s"));
212 if (result & aDIR ) DEBUG(8, ("d"));
213 if (result & aARCH ) DEBUG(8, ("a"));
219 /****************************************************************************
220 Get DOS attributes from an EA.
221 This can also pull the create time into the stat struct inside smb_fname.
222 ****************************************************************************/
224 static bool get_ea_dos_attribute(connection_struct *conn,
225 struct smb_filename *smb_fname,
228 struct xattr_DOSATTRIB dosattrib;
229 enum ndr_err_code ndr_err;
235 if (!lp_store_dos_attributes(SNUM(conn))) {
239 /* Don't reset pattr to zero as we may already have filename-based attributes we
242 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
243 SAMBA_XATTR_DOS_ATTRIB, attrstr,
248 || errno == ENOTSUP) {
252 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute "
253 "from EA on file %s: Error = %s\n",
254 smb_fname_str_dbg(smb_fname),
256 set_store_dos_attributes(SNUM(conn), False);
261 blob.data = (uint8_t *)attrstr;
262 blob.length = sizeret;
264 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &dosattrib,
265 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
267 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
268 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
270 switch (dosattrib.version) {
272 dosattr = dosattrib.info.compatinfoFFFF.attrib;
275 dosattr = dosattrib.info.info1.attrib;
276 if (!null_nttime(dosattrib.info.info1.create_time)) {
277 struct timespec create_time =
278 nt_time_to_unix_timespec(
279 &dosattrib.info.info1.create_time);
281 update_stat_ex_create_time(&smb_fname->st,
284 DEBUG(10,("get_ea_dos_attributes: file %s case 1 "
286 smb_fname_str_dbg(smb_fname),
287 time_to_asc(convert_timespec_to_time_t(
292 dosattr = dosattrib.info.oldinfo2.attrib;
293 /* Don't know what flags to check for this case. */
296 dosattr = dosattrib.info.info3.attrib;
297 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
298 !null_nttime(dosattrib.info.info3.create_time)) {
299 struct timespec create_time =
300 nt_time_to_unix_timespec(
301 &dosattrib.info.info3.create_time);
303 update_stat_ex_create_time(&smb_fname->st,
306 DEBUG(10,("get_ea_dos_attributes: file %s case 3 "
308 smb_fname_str_dbg(smb_fname),
309 time_to_asc(convert_timespec_to_time_t(
314 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on "
315 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
320 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
323 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
325 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
327 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
328 if (dosattr & aRONLY ) DEBUG(8, ("r"));
329 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
330 if (dosattr & aDIR ) DEBUG(8, ("d"));
331 if (dosattr & aARCH ) DEBUG(8, ("a"));
338 /****************************************************************************
339 Set DOS attributes in an EA.
340 Also sets the create time.
341 ****************************************************************************/
343 static bool set_ea_dos_attribute(connection_struct *conn,
344 struct smb_filename *smb_fname,
347 struct xattr_DOSATTRIB dosattrib;
348 enum ndr_err_code ndr_err;
350 files_struct *fsp = NULL;
353 if (!lp_store_dos_attributes(SNUM(conn))) {
357 ZERO_STRUCT(dosattrib);
360 dosattrib.version = 3;
361 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
362 XATTR_DOSINFO_CREATE_TIME;
363 dosattrib.info.info3.attrib = dosmode;
364 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
365 smb_fname->st.st_ex_btime);
367 ndr_err = ndr_push_struct_blob(
368 &blob, talloc_tos(), NULL, &dosattrib,
369 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
371 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
373 ndr_errstr(ndr_err)));
377 if (blob.data == NULL || blob.length == 0) {
381 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
382 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
384 if((errno != EPERM) && (errno != EACCES)) {
387 || errno == ENOTSUP) {
391 DEBUG(1,("set_ea_dos_attributes: Cannot set "
392 "attribute EA on file %s: Error = %s\n",
393 smb_fname_str_dbg(smb_fname),
395 set_store_dos_attributes(SNUM(conn), False);
400 /* We want DOS semantics, ie allow non owner with write permission to change the
401 bits on a file. Just like file_ntimes below.
404 /* Check if we have write access. */
405 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
409 * We need to open the file with write access whilst
410 * still in our current user context. This ensures we
411 * are not violating security in doing the setxattr.
414 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
418 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
419 SAMBA_XATTR_DOS_ATTRIB, blob.data,
420 blob.length, 0) == 0) {
424 close_file_fchmod(NULL, fsp);
427 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
428 (unsigned int)dosmode,
429 smb_fname_str_dbg(smb_fname)));
433 /****************************************************************************
434 Change a unix mode to a dos mode for an ms dfs link.
435 ****************************************************************************/
437 uint32 dos_mode_msdfs(connection_struct *conn,
438 const struct smb_filename *smb_fname)
442 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
444 if (!VALID_STAT(smb_fname->st)) {
448 /* First do any modifications that depend on the path name. */
449 /* hide files with a name starting with a . */
450 if (lp_hide_dot_files(SNUM(conn))) {
451 const char *p = strrchr_m(smb_fname->base_name, '/');
455 p = smb_fname->base_name;
458 /* Only . and .. are not hidden. */
459 if (p[0] == '.' && !((p[1] == '\0') ||
460 (p[1] == '.' && p[2] == '\0'))) {
465 result |= dos_mode_from_sbuf(conn, smb_fname);
467 /* Optimization : Only call is_hidden_path if it's not already
469 if (!(result & aHIDDEN) &&
470 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
475 result = FILE_ATTRIBUTE_NORMAL;
478 result = filter_mode_by_protocol(result);
480 DEBUG(8,("dos_mode_msdfs returning "));
482 if (result & aHIDDEN) DEBUG(8, ("h"));
483 if (result & aRONLY ) DEBUG(8, ("r"));
484 if (result & aSYSTEM) DEBUG(8, ("s"));
485 if (result & aDIR ) DEBUG(8, ("d"));
486 if (result & aARCH ) DEBUG(8, ("a"));
487 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
494 #ifdef HAVE_STAT_DOS_FLAGS
495 /****************************************************************************
496 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
497 ****************************************************************************/
499 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
501 uint32_t dos_stat_flags = 0;
504 dos_stat_flags |= UF_DOS_ARCHIVE;
505 if (dosmode & aHIDDEN)
506 dos_stat_flags |= UF_DOS_HIDDEN;
507 if (dosmode & aRONLY)
508 dos_stat_flags |= UF_DOS_RO;
509 if (dosmode & aSYSTEM)
510 dos_stat_flags |= UF_DOS_SYSTEM;
511 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
512 dos_stat_flags |= UF_DOS_NOINDEX;
514 return dos_stat_flags;
517 /****************************************************************************
518 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
519 ****************************************************************************/
521 static bool get_stat_dos_flags(connection_struct *conn,
522 const struct smb_filename *smb_fname,
525 SMB_ASSERT(VALID_STAT(smb_fname->st));
528 if (!lp_store_dos_attributes(SNUM(conn))) {
532 DEBUG(5, ("Getting stat dos attributes for %s.\n",
533 smb_fname_str_dbg(smb_fname)));
535 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
537 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
539 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
541 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
543 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
544 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
545 if (S_ISDIR(smb_fname->st.st_ex_mode))
548 *dosmode |= set_sparse_flag(&smb_fname->st);
549 *dosmode |= set_link_read_only_flag(&smb_fname->st);
554 /****************************************************************************
555 Sets DOS attributes, stored in st_ex_flags of the inode.
556 ****************************************************************************/
558 static bool set_stat_dos_flags(connection_struct *conn,
559 const struct smb_filename *smb_fname,
561 bool *attributes_changed)
563 uint32_t new_flags = 0;
566 SMB_ASSERT(VALID_STAT(smb_fname->st));
567 SMB_ASSERT(attributes_changed);
569 *attributes_changed = false;
571 if (!lp_store_dos_attributes(SNUM(conn))) {
575 DEBUG(5, ("Setting stat dos attributes for %s.\n",
576 smb_fname_str_dbg(smb_fname)));
578 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
579 dos_attributes_to_stat_dos_flags(dosmode);
581 /* Return early if no flags changed. */
582 if (new_flags == smb_fname->st.st_ex_flags)
585 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
586 smb_fname->st.st_ex_flags));
588 /* Set new flags with chflags. */
589 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
591 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
592 "file %s! errno=%d\n", new_flags,
593 smb_fname_str_dbg(smb_fname), errno));
597 *attributes_changed = true;
600 #endif /* HAVE_STAT_DOS_FLAGS */
602 /****************************************************************************
603 Change a unix mode to a dos mode.
604 May also read the create timespec into the stat struct in smb_fname
605 if "store dos attributes" is true.
606 ****************************************************************************/
608 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
611 bool offline, used_stat_dos_flags = false;
613 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
615 if (!VALID_STAT(smb_fname->st)) {
619 /* First do any modifications that depend on the path name. */
620 /* hide files with a name starting with a . */
621 if (lp_hide_dot_files(SNUM(conn))) {
622 const char *p = strrchr_m(smb_fname->base_name,'/');
626 p = smb_fname->base_name;
629 /* Only . and .. are not hidden. */
630 if (p[0] == '.' && !((p[1] == '\0') ||
631 (p[1] == '.' && p[2] == '\0'))) {
636 #ifdef HAVE_STAT_DOS_FLAGS
637 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
639 if (!used_stat_dos_flags) {
640 /* Get the DOS attributes from an EA by preference. */
641 if (get_ea_dos_attribute(conn, smb_fname, &result)) {
642 result |= set_sparse_flag(&smb_fname->st);
644 result |= dos_mode_from_sbuf(conn, smb_fname);
648 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st);
649 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
650 result |= FILE_ATTRIBUTE_OFFLINE;
653 /* Optimization : Only call is_hidden_path if it's not already
655 if (!(result & aHIDDEN) &&
656 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
661 result = FILE_ATTRIBUTE_NORMAL;
664 result = filter_mode_by_protocol(result);
666 DEBUG(8,("dos_mode returning "));
668 if (result & aHIDDEN) DEBUG(8, ("h"));
669 if (result & aRONLY ) DEBUG(8, ("r"));
670 if (result & aSYSTEM) DEBUG(8, ("s"));
671 if (result & aDIR ) DEBUG(8, ("d"));
672 if (result & aARCH ) DEBUG(8, ("a"));
673 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
680 /*******************************************************************
681 chmod a file - but preserve some bits.
682 If "store dos attributes" is also set it will store the create time
683 from the stat struct in smb_fname (in NTTIME format) in the EA
685 ********************************************************************/
687 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
688 uint32 dosmode, const char *parent_dir, bool newfile)
693 int ret = -1, lret = -1;
695 struct timespec new_create_timespec;
697 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
698 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
700 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
701 dosmode, smb_fname_str_dbg(smb_fname)));
703 unixmode = smb_fname->st.st_ex_mode;
705 get_acl_group_bits(conn, smb_fname->base_name,
706 &smb_fname->st.st_ex_mode);
708 if (S_ISDIR(smb_fname->st.st_ex_mode))
713 new_create_timespec = smb_fname->st.st_ex_btime;
715 old_mode = dos_mode(conn, smb_fname);
717 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
718 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
719 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name);
721 DEBUG(0, ("set_dos_mode: client has asked to "
722 "set FILE_ATTRIBUTE_OFFLINE to "
723 "%s/%s but there was an error while "
724 "setting it or it is not "
725 "supported.\n", parent_dir,
726 smb_fname_str_dbg(smb_fname)));
731 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
732 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
734 if (old_mode == dosmode &&
735 (timespec_compare(&new_create_timespec,
736 &smb_fname->st.st_ex_btime) == 0)) {
737 smb_fname->st.st_ex_mode = unixmode;
741 smb_fname->st.st_ex_btime = new_create_timespec;
743 #ifdef HAVE_STAT_DOS_FLAGS
745 bool attributes_changed;
747 if (set_stat_dos_flags(conn, smb_fname, dosmode,
748 &attributes_changed))
750 if (!newfile && attributes_changed) {
751 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
752 FILE_NOTIFY_CHANGE_ATTRIBUTES,
753 smb_fname->base_name);
755 smb_fname->st.st_ex_mode = unixmode;
760 /* Store the DOS attributes in an EA by preference. */
761 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
763 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
764 FILE_NOTIFY_CHANGE_ATTRIBUTES,
765 smb_fname->base_name);
767 smb_fname->st.st_ex_mode = unixmode;
771 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
773 /* preserve the s bits */
774 mask |= (S_ISUID | S_ISGID);
776 /* preserve the t bit */
781 /* possibly preserve the x bits */
782 if (!MAP_ARCHIVE(conn))
784 if (!MAP_SYSTEM(conn))
786 if (!MAP_HIDDEN(conn))
789 unixmode |= (smb_fname->st.st_ex_mode & mask);
791 /* if we previously had any r bits set then leave them alone */
792 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
793 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
797 /* if we previously had any w bits set then leave them alone
798 whilst adding in the new w bits, if the new mode is not rdonly */
799 if (!IS_DOS_READONLY(dosmode)) {
800 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
803 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
805 if(!newfile || (lret != -1)) {
806 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
807 FILE_NOTIFY_CHANGE_ATTRIBUTES,
808 smb_fname->base_name);
810 smb_fname->st.st_ex_mode = unixmode;
814 if((errno != EPERM) && (errno != EACCES))
817 if(!lp_dos_filemode(SNUM(conn)))
820 /* We want DOS semantics, ie allow non owner with write permission to change the
821 bits on a file. Just like file_ntimes below.
824 /* Check if we have write access. */
825 if (CAN_WRITE(conn)) {
827 * We need to open the file with write access whilst
828 * still in our current user context. This ensures we
829 * are not violating security in doing the fchmod.
830 * This file open does *not* break any oplocks we are
831 * holding. We need to review this.... may need to
832 * break batch oplocks open by others. JRA.
835 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
839 ret = SMB_VFS_FCHMOD(fsp, unixmode);
841 close_file_fchmod(NULL, fsp);
843 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
844 FILE_NOTIFY_CHANGE_ATTRIBUTES,
845 smb_fname->base_name);
848 smb_fname->st.st_ex_mode = unixmode;
855 /*******************************************************************
856 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
858 *******************************************************************/
860 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
861 struct smb_file_time *ft)
867 DEBUG(6, ("file_ntime: actime: %s",
868 time_to_asc(convert_timespec_to_time_t(ft->atime))));
869 DEBUG(6, ("file_ntime: modtime: %s",
870 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
871 DEBUG(6, ("file_ntime: ctime: %s",
872 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
873 DEBUG(6, ("file_ntime: createtime: %s",
874 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
876 /* Don't update the time on read-only shares */
877 /* We need this as set_filetime (which can be called on
878 close and other paths) can end up calling this function
879 without the NEED_WRITE protection. Found by :
880 Leo Weppelman <leo@wau.mis.ah.nl>
883 if (!CAN_WRITE(conn)) {
887 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
891 if((errno != EPERM) && (errno != EACCES)) {
895 if(!lp_dos_filetimes(SNUM(conn))) {
899 /* We have permission (given by the Samba admin) to
900 break POSIX semantics and allow a user to change
901 the time on a file they don't own but can write to
905 /* Check if we have write access. */
906 if (can_write_to_file(conn, smb_fname)) {
907 /* We are allowed to become root and change the filetime. */
909 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
916 /******************************************************************
917 Force a "sticky" write time on a pathname. This will always be
918 returned on all future write time queries and set on close.
919 ******************************************************************/
921 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
923 if (null_timespec(mtime)) {
927 if (!set_sticky_write_time(fileid, mtime)) {
934 /******************************************************************
935 Force a "sticky" write time on an fsp. This will always be
936 returned on all future write time queries and set on close.
937 ******************************************************************/
939 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
941 if (null_timespec(mtime)) {
945 fsp->write_time_forced = true;
946 TALLOC_FREE(fsp->update_write_time_event);
948 return set_sticky_write_time_path(fsp->file_id, mtime);
951 /******************************************************************
952 Set a create time EA.
953 ******************************************************************/
955 NTSTATUS set_create_timespec_ea(connection_struct *conn,
956 const struct smb_filename *psmb_fname,
957 struct timespec create_time)
960 struct smb_filename *smb_fname = NULL;
964 if (!lp_store_dos_attributes(SNUM(conn))) {
968 status = create_synthetic_smb_fname(talloc_tos(),
969 psmb_fname->base_name,
970 NULL, &psmb_fname->st,
973 if (!NT_STATUS_IS_OK(status)) {
977 dosmode = dos_mode(conn, smb_fname);
979 smb_fname->st.st_ex_btime = create_time;
981 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
983 map_nt_error_from_unix(errno);
986 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
987 smb_fname_str_dbg(smb_fname)));
992 /******************************************************************
993 Return a create time.
994 ******************************************************************/
996 struct timespec get_create_timespec(connection_struct *conn,
997 struct files_struct *fsp,
998 const struct smb_filename *smb_fname)
1000 return smb_fname->st.st_ex_btime;
1003 /******************************************************************
1004 Return a change time (may look at EA in future).
1005 ******************************************************************/
1007 struct timespec get_change_timespec(connection_struct *conn,
1008 struct files_struct *fsp,
1009 const struct smb_filename *smb_fname)
1011 return smb_fname->st.st_ex_mtime;