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 int set_sparse_flag(const SMB_STRUCT_STAT
* const sbuf
)
26 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
27 if (sbuf
->st_ex_size
> sbuf
->st_ex_blocks
* (SMB_OFF_T
)STAT_ST_BLOCKSIZE
) {
28 return FILE_ATTRIBUTE_SPARSE
;
34 static int set_link_read_only_flag(const SMB_STRUCT_STAT
*const sbuf
)
38 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
45 /****************************************************************************
46 Change a dos mode to a unix mode.
47 Base permission for files:
48 if creating file and inheriting (i.e. parent_dir != NULL)
49 apply read/write bits from parent directory.
51 everybody gets read bit set
52 dos readonly is represented in unix by removing everyone's write bit
53 dos archive is represented in unix by the user's execute bit
54 dos system is represented in unix by the group's execute bit
55 dos hidden is represented in unix by the other's execute bit
57 Then apply create mask,
60 Base permission for directories:
61 dos directory is represented in unix by unix's dir bit and the exec bit
63 Then apply create mask,
66 ****************************************************************************/
68 mode_t
unix_mode(connection_struct
*conn
, int dosmode
,
69 const struct smb_filename
*smb_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
76 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
77 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
80 if ((inherit_from_dir
!= NULL
) && lp_inherit_perms(SNUM(conn
))) {
81 struct smb_filename
*smb_fname_parent
= NULL
;
84 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
85 smb_fname_str_dbg(smb_fname
),
88 status
= create_synthetic_smb_fname(talloc_tos(),
89 inherit_from_dir
, NULL
,
90 NULL
, &smb_fname_parent
);
91 if (!NT_STATUS_IS_OK(status
)) {
92 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
93 smb_fname_str_dbg(smb_fname
),
94 inherit_from_dir
, nt_errstr(status
)));
98 if (SMB_VFS_STAT(conn
, smb_fname_parent
) != 0) {
99 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
100 smb_fname_str_dbg(smb_fname
),
101 inherit_from_dir
, strerror(errno
)));
102 TALLOC_FREE(smb_fname_parent
);
103 return(0); /* *** shouldn't happen! *** */
106 /* Save for later - but explicitly remove setuid bit for safety. */
107 dir_mode
= smb_fname_parent
->st
.st_ex_mode
& ~S_ISUID
;
108 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
109 smb_fname_str_dbg(smb_fname
), (int)dir_mode
));
112 TALLOC_FREE(smb_fname_parent
);
115 if (IS_DOS_DIR(dosmode
)) {
116 /* We never make directories read only for the owner as under DOS a user
117 can always create a file in a read-only directory. */
118 result
|= (S_IFDIR
| S_IWUSR
);
121 /* Inherit mode of parent directory. */
124 /* Provisionally add all 'x' bits */
125 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
127 /* Apply directory mask */
128 result
&= lp_dir_mask(SNUM(conn
));
129 /* Add in force bits */
130 result
|= lp_force_dir_mode(SNUM(conn
));
133 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
136 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
139 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
143 /* Inherit 666 component of parent directory mode */
144 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
146 /* Apply mode mask */
147 result
&= lp_create_mask(SNUM(conn
));
148 /* Add in force bits */
149 result
|= lp_force_create_mode(SNUM(conn
));
153 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname
),
158 /****************************************************************************
159 Change a unix mode to a dos mode.
160 ****************************************************************************/
162 static uint32
dos_mode_from_sbuf(connection_struct
*conn
,
163 const struct smb_filename
*smb_fname
)
166 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
168 if (ro_opts
== MAP_READONLY_YES
) {
169 /* Original Samba method - map inverse of user "w" bit. */
170 if ((smb_fname
->st
.st_ex_mode
& S_IWUSR
) == 0) {
173 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
174 /* Check actual permissions for read-only. */
175 if (!can_write_to_file(conn
, smb_fname
)) {
178 } /* Else never set the readonly bit. */
180 if (MAP_ARCHIVE(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXUSR
) != 0))
183 if (MAP_SYSTEM(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXGRP
) != 0))
186 if (MAP_HIDDEN(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXOTH
) != 0))
189 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
190 result
= aDIR
| (result
& aRONLY
);
192 result
|= set_sparse_flag(&smb_fname
->st
);
193 result
|= set_link_read_only_flag(&smb_fname
->st
);
195 DEBUG(8,("dos_mode_from_sbuf returning "));
197 if (result
& aHIDDEN
) DEBUG(8, ("h"));
198 if (result
& aRONLY
) DEBUG(8, ("r"));
199 if (result
& aSYSTEM
) DEBUG(8, ("s"));
200 if (result
& aDIR
) DEBUG(8, ("d"));
201 if (result
& aARCH
) DEBUG(8, ("a"));
207 /****************************************************************************
208 Get DOS attributes from an EA.
209 This can also pull the create time into the stat struct inside smb_fname.
210 ****************************************************************************/
212 static bool get_ea_dos_attribute(connection_struct
*conn
,
213 struct smb_filename
*smb_fname
,
216 struct xattr_DOSATTRIB dosattrib
;
217 enum ndr_err_code ndr_err
;
223 if (!lp_store_dos_attributes(SNUM(conn
))) {
227 /* Don't reset pattr to zero as we may already have filename-based attributes we
230 sizeret
= SMB_VFS_GETXATTR(conn
, smb_fname
->base_name
,
231 SAMBA_XATTR_DOS_ATTRIB
, attrstr
,
236 || errno
== ENOTSUP
) {
240 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute "
241 "from EA on file %s: Error = %s\n",
242 smb_fname_str_dbg(smb_fname
),
244 set_store_dos_attributes(SNUM(conn
), False
);
249 blob
.data
= (uint8_t *)attrstr
;
250 blob
.length
= sizeret
;
252 ndr_err
= ndr_pull_struct_blob(&blob
, talloc_tos(), NULL
, &dosattrib
,
253 (ndr_pull_flags_fn_t
)ndr_pull_xattr_DOSATTRIB
);
255 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
256 smb_fname_str_dbg(smb_fname
), dosattrib
.attrib_hex
));
258 switch (dosattrib
.version
) {
260 dosattr
= dosattrib
.info
.compatinfoFFFF
.attrib
;
263 dosattr
= dosattrib
.info
.info1
.attrib
;
264 if (!null_nttime(dosattrib
.info
.info1
.create_time
)) {
265 struct timespec create_time
=
266 nt_time_to_unix_timespec(
267 &dosattrib
.info
.info1
.create_time
);
269 update_stat_ex_create_time(&smb_fname
->st
,
272 DEBUG(10,("get_ea_dos_attributes: file %s case 1 "
274 smb_fname_str_dbg(smb_fname
),
275 time_to_asc(convert_timespec_to_time_t(
280 dosattr
= dosattrib
.info
.oldinfo2
.attrib
;
281 /* Don't know what flags to check for this case. */
284 dosattr
= dosattrib
.info
.info3
.attrib
;
285 if ((dosattrib
.info
.info3
.valid_flags
& XATTR_DOSINFO_CREATE_TIME
) &&
286 !null_nttime(dosattrib
.info
.info3
.create_time
)) {
287 struct timespec create_time
=
288 nt_time_to_unix_timespec(
289 &dosattrib
.info
.info3
.create_time
);
291 update_stat_ex_create_time(&smb_fname
->st
,
294 DEBUG(10,("get_ea_dos_attributes: file %s case 3 "
296 smb_fname_str_dbg(smb_fname
),
297 time_to_asc(convert_timespec_to_time_t(
302 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on "
303 "file %s - %s\n", smb_fname_str_dbg(smb_fname
),
308 if (S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
311 *pattr
= (uint32
)(dosattr
& SAMBA_ATTRIBUTES_MASK
);
313 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
315 if (dosattr
& aHIDDEN
) DEBUG(8, ("h"));
316 if (dosattr
& aRONLY
) DEBUG(8, ("r"));
317 if (dosattr
& aSYSTEM
) DEBUG(8, ("s"));
318 if (dosattr
& aDIR
) DEBUG(8, ("d"));
319 if (dosattr
& aARCH
) DEBUG(8, ("a"));
326 /****************************************************************************
327 Set DOS attributes in an EA.
328 Also sets the create time.
329 ****************************************************************************/
331 static bool set_ea_dos_attribute(connection_struct
*conn
,
332 struct smb_filename
*smb_fname
,
335 struct xattr_DOSATTRIB dosattrib
;
336 enum ndr_err_code ndr_err
;
338 files_struct
*fsp
= NULL
;
341 if (!lp_store_dos_attributes(SNUM(conn
))) {
345 ZERO_STRUCT(dosattrib
);
348 dosattrib
.version
= 3;
349 dosattrib
.info
.info3
.valid_flags
= XATTR_DOSINFO_ATTRIB
|
350 XATTR_DOSINFO_CREATE_TIME
;
351 dosattrib
.info
.info3
.attrib
= dosmode
;
352 unix_timespec_to_nt_time(&dosattrib
.info
.info3
.create_time
,
353 smb_fname
->st
.st_ex_btime
);
355 ndr_err
= ndr_push_struct_blob(
356 &blob
, talloc_tos(), NULL
, &dosattrib
,
357 (ndr_push_flags_fn_t
)ndr_push_xattr_DOSATTRIB
);
359 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
360 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
361 ndr_errstr(ndr_err
)));
365 if (blob
.data
== NULL
|| blob
.length
== 0) {
369 if (SMB_VFS_SETXATTR(conn
, smb_fname
->base_name
,
370 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
, blob
.length
,
372 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
375 || errno
== ENOTSUP
) {
379 DEBUG(1,("set_ea_dos_attributes: Cannot set "
380 "attribute EA on file %s: Error = %s\n",
381 smb_fname_str_dbg(smb_fname
),
383 set_store_dos_attributes(SNUM(conn
), False
);
388 /* We want DOS semantics, ie allow non owner with write permission to change the
389 bits on a file. Just like file_ntimes below.
392 /* Check if we have write access. */
393 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
397 * We need to open the file with write access whilst
398 * still in our current user context. This ensures we
399 * are not violating security in doing the setxattr.
402 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL
, conn
, smb_fname
,
406 if (SMB_VFS_SETXATTR(conn
, smb_fname
->base_name
,
407 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
,
408 blob
.length
, 0) == 0) {
412 close_file_fchmod(NULL
, fsp
);
415 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
416 (unsigned int)dosmode
,
417 smb_fname_str_dbg(smb_fname
)));
421 /****************************************************************************
422 Change a unix mode to a dos mode for an ms dfs link.
423 ****************************************************************************/
425 uint32
dos_mode_msdfs(connection_struct
*conn
,
426 const struct smb_filename
*smb_fname
)
430 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname
)));
432 if (!VALID_STAT(smb_fname
->st
)) {
436 /* First do any modifications that depend on the path name. */
437 /* hide files with a name starting with a . */
438 if (lp_hide_dot_files(SNUM(conn
))) {
439 const char *p
= strrchr_m(smb_fname
->base_name
, '/');
443 p
= smb_fname
->base_name
;
446 /* Only . and .. are not hidden. */
447 if (p
[0] == '.' && !((p
[1] == '\0') ||
448 (p
[1] == '.' && p
[2] == '\0'))) {
453 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
455 /* Optimization : Only call is_hidden_path if it's not already
457 if (!(result
& aHIDDEN
) &&
458 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
462 if (get_Protocol() <= PROTOCOL_LANMAN2
) {
463 DEBUG(10,("dos_mode_msdfs : filtering result 0x%x\n",
464 (unsigned int)result
));
468 DEBUG(8,("dos_mode_msdfs returning "));
470 if (result
& aHIDDEN
) DEBUG(8, ("h"));
471 if (result
& aRONLY
) DEBUG(8, ("r"));
472 if (result
& aSYSTEM
) DEBUG(8, ("s"));
473 if (result
& aDIR
) DEBUG(8, ("d"));
474 if (result
& aARCH
) DEBUG(8, ("a"));
475 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
482 #ifdef HAVE_STAT_DOS_FLAGS
483 /****************************************************************************
484 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
485 ****************************************************************************/
487 int dos_attributes_to_stat_dos_flags(uint32_t dosmode
)
489 uint32_t dos_stat_flags
= 0;
492 dos_stat_flags
|= UF_DOS_ARCHIVE
;
493 if (dosmode
& aHIDDEN
)
494 dos_stat_flags
|= UF_DOS_HIDDEN
;
495 if (dosmode
& aRONLY
)
496 dos_stat_flags
|= UF_DOS_RO
;
497 if (dosmode
& aSYSTEM
)
498 dos_stat_flags
|= UF_DOS_SYSTEM
;
499 if (dosmode
& FILE_ATTRIBUTE_NONINDEXED
)
500 dos_stat_flags
|= UF_DOS_NOINDEX
;
502 return dos_stat_flags
;
505 /****************************************************************************
506 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
507 ****************************************************************************/
509 static bool get_stat_dos_flags(connection_struct
*conn
,
510 const struct smb_filename
*smb_fname
,
513 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
516 if (!lp_store_dos_attributes(SNUM(conn
))) {
520 DEBUG(5, ("Getting stat dos attributes for %s.\n",
521 smb_fname_str_dbg(smb_fname
)));
523 if (smb_fname
->st
.st_ex_flags
& UF_DOS_ARCHIVE
)
525 if (smb_fname
->st
.st_ex_flags
& UF_DOS_HIDDEN
)
527 if (smb_fname
->st
.st_ex_flags
& UF_DOS_RO
)
529 if (smb_fname
->st
.st_ex_flags
& UF_DOS_SYSTEM
)
531 if (smb_fname
->st
.st_ex_flags
& UF_DOS_NOINDEX
)
532 *dosmode
|= FILE_ATTRIBUTE_NONINDEXED
;
533 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
536 *dosmode
|= set_sparse_flag(&smb_fname
->st
);
537 *dosmode
|= set_link_read_only_flag(&smb_fname
->st
);
542 /****************************************************************************
543 Sets DOS attributes, stored in st_ex_flags of the inode.
544 ****************************************************************************/
546 static bool set_stat_dos_flags(connection_struct
*conn
,
547 const struct smb_filename
*smb_fname
,
549 bool *attributes_changed
)
551 uint32_t new_flags
= 0;
554 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
555 SMB_ASSERT(attributes_changed
);
557 *attributes_changed
= false;
559 if (!lp_store_dos_attributes(SNUM(conn
))) {
563 DEBUG(5, ("Setting stat dos attributes for %s.\n",
564 smb_fname_str_dbg(smb_fname
)));
566 new_flags
= (smb_fname
->st
.st_ex_flags
& ~UF_DOS_FLAGS
) |
567 dos_attributes_to_stat_dos_flags(dosmode
);
569 /* Return early if no flags changed. */
570 if (new_flags
== smb_fname
->st
.st_ex_flags
)
573 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags
,
574 smb_fname
->st
.st_ex_flags
));
576 /* Set new flags with chflags. */
577 error
= SMB_VFS_CHFLAGS(conn
, smb_fname
->base_name
, new_flags
);
579 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
580 "file %s! errno=%d\n", new_flags
,
581 smb_fname_str_dbg(smb_fname
), errno
));
585 *attributes_changed
= true;
588 #endif /* HAVE_STAT_DOS_FLAGS */
590 /****************************************************************************
591 Change a unix mode to a dos mode.
592 May also read the create timespec into the stat struct in smb_fname
593 if "store dos attributes" is true.
594 ****************************************************************************/
596 uint32
dos_mode(connection_struct
*conn
, struct smb_filename
*smb_fname
)
599 bool offline
, used_stat_dos_flags
= false;
601 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname
)));
603 if (!VALID_STAT(smb_fname
->st
)) {
607 /* First do any modifications that depend on the path name. */
608 /* hide files with a name starting with a . */
609 if (lp_hide_dot_files(SNUM(conn
))) {
610 const char *p
= strrchr_m(smb_fname
->base_name
,'/');
614 p
= smb_fname
->base_name
;
617 /* Only . and .. are not hidden. */
618 if (p
[0] == '.' && !((p
[1] == '\0') ||
619 (p
[1] == '.' && p
[2] == '\0'))) {
624 #ifdef HAVE_STAT_DOS_FLAGS
625 used_stat_dos_flags
= get_stat_dos_flags(conn
, smb_fname
, &result
);
627 if (!used_stat_dos_flags
) {
628 /* Get the DOS attributes from an EA by preference. */
629 if (get_ea_dos_attribute(conn
, smb_fname
, &result
)) {
630 result
|= set_sparse_flag(&smb_fname
->st
);
632 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
636 offline
= SMB_VFS_IS_OFFLINE(conn
, smb_fname
->base_name
, &smb_fname
->st
);
637 if (S_ISREG(smb_fname
->st
.st_ex_mode
) && offline
) {
638 result
|= FILE_ATTRIBUTE_OFFLINE
;
641 /* Optimization : Only call is_hidden_path if it's not already
643 if (!(result
& aHIDDEN
) &&
644 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
648 if (get_Protocol() <= PROTOCOL_LANMAN2
) {
649 DEBUG(10,("dos_mode : filtering result 0x%x\n",
650 (unsigned int)result
));
654 DEBUG(8,("dos_mode returning "));
656 if (result
& aHIDDEN
) DEBUG(8, ("h"));
657 if (result
& aRONLY
) DEBUG(8, ("r"));
658 if (result
& aSYSTEM
) DEBUG(8, ("s"));
659 if (result
& aDIR
) DEBUG(8, ("d"));
660 if (result
& aARCH
) DEBUG(8, ("a"));
661 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
668 /*******************************************************************
669 chmod a file - but preserve some bits.
670 If "store dos attributes" is also set it will store the create time
671 from the stat struct in smb_fname (in NTTIME format) in the EA
673 ********************************************************************/
675 int file_set_dosmode(connection_struct
*conn
, struct smb_filename
*smb_fname
,
676 uint32 dosmode
, const char *parent_dir
, bool newfile
)
681 int ret
= -1, lret
= -1;
683 struct timespec new_create_timespec
;
685 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
686 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
688 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
689 dosmode
, smb_fname_str_dbg(smb_fname
)));
691 unixmode
= smb_fname
->st
.st_ex_mode
;
693 get_acl_group_bits(conn
, smb_fname
->base_name
,
694 &smb_fname
->st
.st_ex_mode
);
696 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
701 new_create_timespec
= smb_fname
->st
.st_ex_btime
;
703 old_mode
= dos_mode(conn
, smb_fname
);
705 if (dosmode
& FILE_ATTRIBUTE_OFFLINE
) {
706 if (!(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
707 lret
= SMB_VFS_SET_OFFLINE(conn
, smb_fname
->base_name
);
709 DEBUG(0, ("set_dos_mode: client has asked to "
710 "set FILE_ATTRIBUTE_OFFLINE to "
711 "%s/%s but there was an error while "
712 "setting it or it is not "
713 "supported.\n", parent_dir
,
714 smb_fname_str_dbg(smb_fname
)));
719 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
720 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
722 if (old_mode
== dosmode
&&
723 (timespec_compare(&new_create_timespec
,
724 &smb_fname
->st
.st_ex_btime
) == 0)) {
725 smb_fname
->st
.st_ex_mode
= unixmode
;
729 smb_fname
->st
.st_ex_btime
= new_create_timespec
;
731 #ifdef HAVE_STAT_DOS_FLAGS
733 bool attributes_changed
;
735 if (set_stat_dos_flags(conn
, smb_fname
, dosmode
,
736 &attributes_changed
))
738 if (!newfile
&& attributes_changed
) {
739 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
740 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
741 smb_fname
->base_name
);
743 smb_fname
->st
.st_ex_mode
= unixmode
;
748 /* Store the DOS attributes in an EA by preference. */
749 if (set_ea_dos_attribute(conn
, smb_fname
, dosmode
)) {
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
;
759 unixmode
= unix_mode(conn
, dosmode
, smb_fname
, parent_dir
);
761 /* preserve the s bits */
762 mask
|= (S_ISUID
| S_ISGID
);
764 /* preserve the t bit */
769 /* possibly preserve the x bits */
770 if (!MAP_ARCHIVE(conn
))
772 if (!MAP_SYSTEM(conn
))
774 if (!MAP_HIDDEN(conn
))
777 unixmode
|= (smb_fname
->st
.st_ex_mode
& mask
);
779 /* if we previously had any r bits set then leave them alone */
780 if ((tmp
= smb_fname
->st
.st_ex_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
781 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
785 /* if we previously had any w bits set then leave them alone
786 whilst adding in the new w bits, if the new mode is not rdonly */
787 if (!IS_DOS_READONLY(dosmode
)) {
788 unixmode
|= (smb_fname
->st
.st_ex_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
791 ret
= SMB_VFS_CHMOD(conn
, smb_fname
->base_name
, unixmode
);
793 if(!newfile
|| (lret
!= -1)) {
794 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
795 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
796 smb_fname
->base_name
);
798 smb_fname
->st
.st_ex_mode
= unixmode
;
802 if((errno
!= EPERM
) && (errno
!= EACCES
))
805 if(!lp_dos_filemode(SNUM(conn
)))
808 /* We want DOS semantics, ie allow non owner with write permission to change the
809 bits on a file. Just like file_ntimes below.
812 /* Check if we have write access. */
813 if (CAN_WRITE(conn
)) {
815 * We need to open the file with write access whilst
816 * still in our current user context. This ensures we
817 * are not violating security in doing the fchmod.
818 * This file open does *not* break any oplocks we are
819 * holding. We need to review this.... may need to
820 * break batch oplocks open by others. JRA.
823 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL
, conn
, smb_fname
,
827 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
829 close_file_fchmod(NULL
, fsp
);
831 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
832 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
833 smb_fname
->base_name
);
836 smb_fname
->st
.st_ex_mode
= unixmode
;
843 /*******************************************************************
844 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
846 *******************************************************************/
848 int file_ntimes(connection_struct
*conn
, const struct smb_filename
*smb_fname
,
849 struct smb_file_time
*ft
)
855 DEBUG(6, ("file_ntime: actime: %s",
856 time_to_asc(convert_timespec_to_time_t(ft
->atime
))));
857 DEBUG(6, ("file_ntime: modtime: %s",
858 time_to_asc(convert_timespec_to_time_t(ft
->mtime
))));
859 DEBUG(6, ("file_ntime: ctime: %s",
860 time_to_asc(convert_timespec_to_time_t(ft
->ctime
))));
861 DEBUG(6, ("file_ntime: createtime: %s",
862 time_to_asc(convert_timespec_to_time_t(ft
->create_time
))));
864 /* Don't update the time on read-only shares */
865 /* We need this as set_filetime (which can be called on
866 close and other paths) can end up calling this function
867 without the NEED_WRITE protection. Found by :
868 Leo Weppelman <leo@wau.mis.ah.nl>
871 if (!CAN_WRITE(conn
)) {
875 if(SMB_VFS_NTIMES(conn
, smb_fname
, ft
) == 0) {
879 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
883 if(!lp_dos_filetimes(SNUM(conn
))) {
887 /* We have permission (given by the Samba admin) to
888 break POSIX semantics and allow a user to change
889 the time on a file they don't own but can write to
893 /* Check if we have write access. */
894 if (can_write_to_file(conn
, smb_fname
)) {
895 /* We are allowed to become root and change the filetime. */
897 ret
= SMB_VFS_NTIMES(conn
, smb_fname
, ft
);
904 /******************************************************************
905 Force a "sticky" write time on a pathname. This will always be
906 returned on all future write time queries and set on close.
907 ******************************************************************/
909 bool set_sticky_write_time_path(struct file_id fileid
, struct timespec mtime
)
911 if (null_timespec(mtime
)) {
915 if (!set_sticky_write_time(fileid
, mtime
)) {
922 /******************************************************************
923 Force a "sticky" write time on an fsp. This will always be
924 returned on all future write time queries and set on close.
925 ******************************************************************/
927 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, struct timespec mtime
)
929 if (null_timespec(mtime
)) {
933 fsp
->write_time_forced
= true;
934 TALLOC_FREE(fsp
->update_write_time_event
);
936 return set_sticky_write_time_path(fsp
->file_id
, mtime
);
939 /******************************************************************
940 Set a create time EA.
941 ******************************************************************/
943 NTSTATUS
set_create_timespec_ea(connection_struct
*conn
,
944 const struct smb_filename
*psmb_fname
,
945 struct timespec create_time
)
948 struct smb_filename
*smb_fname
= NULL
;
952 if (!lp_store_dos_attributes(SNUM(conn
))) {
956 status
= create_synthetic_smb_fname(talloc_tos(),
957 psmb_fname
->base_name
,
958 NULL
, &psmb_fname
->st
,
961 if (!NT_STATUS_IS_OK(status
)) {
965 dosmode
= dos_mode(conn
, smb_fname
);
967 smb_fname
->st
.st_ex_btime
= create_time
;
969 ret
= file_set_dosmode(conn
, smb_fname
, dosmode
, NULL
, false);
971 map_nt_error_from_unix(errno
);
974 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
975 smb_fname_str_dbg(smb_fname
)));
980 /******************************************************************
981 Return a create time.
982 ******************************************************************/
984 struct timespec
get_create_timespec(connection_struct
*conn
,
985 struct files_struct
*fsp
,
986 const struct smb_filename
*smb_fname
)
988 return smb_fname
->st
.st_ex_btime
;
991 /******************************************************************
992 Return a change time (may look at EA in future).
993 ******************************************************************/
995 struct timespec
get_change_timespec(connection_struct
*conn
,
996 struct files_struct
*fsp
,
997 const struct smb_filename
*smb_fname
)
999 return smb_fname
->st
.st_ex_mtime
;