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/>.
23 static int set_sparse_flag(const SMB_STRUCT_STAT
* const sbuf
)
25 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
26 if (sbuf
->st_ex_size
> sbuf
->st_ex_blocks
* (SMB_OFF_T
)STAT_ST_BLOCKSIZE
) {
27 return FILE_ATTRIBUTE_SPARSE
;
33 static int set_link_read_only_flag(const SMB_STRUCT_STAT
*const sbuf
)
37 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
44 /****************************************************************************
45 Change a dos mode to a unix mode.
46 Base permission for files:
47 if creating file and inheriting (i.e. parent_dir != NULL)
48 apply read/write bits from parent directory.
50 everybody gets read bit set
51 dos readonly is represented in unix by removing everyone's write bit
52 dos archive is represented in unix by the user's execute bit
53 dos system is represented in unix by the group's execute bit
54 dos hidden is represented in unix by the other's execute bit
56 Then apply create mask,
59 Base permission for directories:
60 dos directory is represented in unix by unix's dir bit and the exec bit
62 Then apply create mask,
65 ****************************************************************************/
67 mode_t
unix_mode(connection_struct
*conn
, int dosmode
, const char *fname
,
68 const char *inherit_from_dir
)
70 mode_t result
= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
71 mode_t dir_mode
= 0; /* Mode of the inherit_from directory if
74 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
75 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
78 if (fname
&& (inherit_from_dir
!= NULL
)
79 && lp_inherit_perms(SNUM(conn
))) {
82 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname
,
84 if (vfs_stat_smb_fname(conn
, inherit_from_dir
, &sbuf
) != 0) {
85 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname
,
86 inherit_from_dir
, strerror(errno
)));
87 return(0); /* *** shouldn't happen! *** */
90 /* Save for later - but explicitly remove setuid bit for safety. */
91 dir_mode
= sbuf
.st_ex_mode
& ~S_ISUID
;
92 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname
,(int)dir_mode
));
97 if (IS_DOS_DIR(dosmode
)) {
98 /* We never make directories read only for the owner as under DOS a user
99 can always create a file in a read-only directory. */
100 result
|= (S_IFDIR
| S_IWUSR
);
103 /* Inherit mode of parent directory. */
106 /* Provisionally add all 'x' bits */
107 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
109 /* Apply directory mask */
110 result
&= lp_dir_mask(SNUM(conn
));
111 /* Add in force bits */
112 result
|= lp_force_dir_mode(SNUM(conn
));
115 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
118 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
121 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
125 /* Inherit 666 component of parent directory mode */
126 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
128 /* Apply mode mask */
129 result
&= lp_create_mask(SNUM(conn
));
130 /* Add in force bits */
131 result
|= lp_force_create_mode(SNUM(conn
));
135 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname
,(int)result
));
139 /****************************************************************************
140 Change a unix mode to a dos mode.
141 ****************************************************************************/
143 static uint32
dos_mode_from_sbuf(connection_struct
*conn
, const char *path
, const SMB_STRUCT_STAT
*sbuf
)
146 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
148 if (ro_opts
== MAP_READONLY_YES
) {
149 /* Original Samba method - map inverse of user "w" bit. */
150 if ((sbuf
->st_ex_mode
& S_IWUSR
) == 0) {
153 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
154 struct smb_filename
*smb_fname
= NULL
;
157 status
= create_synthetic_smb_fname_split(talloc_tos(), path
,
159 if (NT_STATUS_IS_OK(status
)) {
160 /* Check actual permissions for read-only. */
161 if (!can_write_to_file(conn
, smb_fname
)) {
165 TALLOC_FREE(smb_fname
);
166 } /* Else never set the readonly bit. */
168 if (MAP_ARCHIVE(conn
) && ((sbuf
->st_ex_mode
& S_IXUSR
) != 0))
171 if (MAP_SYSTEM(conn
) && ((sbuf
->st_ex_mode
& S_IXGRP
) != 0))
174 if (MAP_HIDDEN(conn
) && ((sbuf
->st_ex_mode
& S_IXOTH
) != 0))
177 if (S_ISDIR(sbuf
->st_ex_mode
))
178 result
= aDIR
| (result
& aRONLY
);
180 result
|= set_sparse_flag(sbuf
);
181 result
|= set_link_read_only_flag(sbuf
);
183 DEBUG(8,("dos_mode_from_sbuf returning "));
185 if (result
& aHIDDEN
) DEBUG(8, ("h"));
186 if (result
& aRONLY
) DEBUG(8, ("r"));
187 if (result
& aSYSTEM
) DEBUG(8, ("s"));
188 if (result
& aDIR
) DEBUG(8, ("d"));
189 if (result
& aARCH
) DEBUG(8, ("a"));
195 /****************************************************************************
196 Get DOS attributes from an EA.
197 ****************************************************************************/
199 static bool get_ea_dos_attribute(connection_struct
*conn
, const char *path
, const SMB_STRUCT_STAT
*sbuf
, uint32
*pattr
)
203 unsigned int dosattr
;
205 if (!lp_store_dos_attributes(SNUM(conn
))) {
209 /* Don't reset pattr to zero as we may already have filename-based attributes we
212 sizeret
= SMB_VFS_GETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, sizeof(attrstr
));
216 || errno
== ENOTSUP
) {
220 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
221 path
, strerror(errno
) ));
222 set_store_dos_attributes(SNUM(conn
), False
);
226 /* Null terminate string. */
227 attrstr
[sizeret
] = 0;
228 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path
, attrstr
));
230 if (sizeret
< 2 || attrstr
[0] != '0' || attrstr
[1] != 'x' ||
231 sscanf(attrstr
, "%x", &dosattr
) != 1) {
232 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path
, attrstr
));
236 if (S_ISDIR(sbuf
->st_ex_mode
)) {
239 *pattr
= (uint32
)(dosattr
& SAMBA_ATTRIBUTES_MASK
);
241 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
243 if (dosattr
& aHIDDEN
) DEBUG(8, ("h"));
244 if (dosattr
& aRONLY
) DEBUG(8, ("r"));
245 if (dosattr
& aSYSTEM
) DEBUG(8, ("s"));
246 if (dosattr
& aDIR
) DEBUG(8, ("d"));
247 if (dosattr
& aARCH
) DEBUG(8, ("a"));
254 /****************************************************************************
255 Set DOS attributes in an EA.
256 ****************************************************************************/
258 static bool set_ea_dos_attribute(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
, uint32 dosmode
)
261 files_struct
*fsp
= NULL
;
264 if (!lp_store_dos_attributes(SNUM(conn
))) {
268 snprintf(attrstr
, sizeof(attrstr
)-1, "0x%x", dosmode
& SAMBA_ATTRIBUTES_MASK
);
269 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == -1) {
270 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
273 || errno
== ENOTSUP
) {
277 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
278 path
, strerror(errno
) ));
279 set_store_dos_attributes(SNUM(conn
), False
);
284 /* We want DOS semantics, ie allow non owner with write permission to change the
285 bits on a file. Just like file_ntimes below.
288 /* Check if we have write access. */
289 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
293 * We need to open the file with write access whilst
294 * still in our current user context. This ensures we
295 * are not violating security in doing the setxattr.
298 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL
, conn
, path
, sbuf
,
302 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == 0) {
306 close_file_fchmod(NULL
, fsp
);
309 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr
, path
));
313 /****************************************************************************
314 Change a unix mode to a dos mode for an ms dfs link.
315 ****************************************************************************/
317 uint32
dos_mode_msdfs(connection_struct
*conn
, const char *path
, const SMB_STRUCT_STAT
*psbuf
)
319 SMB_STRUCT_STAT sbuf
= *psbuf
;
322 DEBUG(8,("dos_mode_msdfs: %s\n", path
));
324 if (!VALID_STAT(sbuf
)) {
328 /* First do any modifications that depend on the path name. */
329 /* hide files with a name starting with a . */
330 if (lp_hide_dot_files(SNUM(conn
))) {
331 const char *p
= strrchr_m(path
,'/');
338 /* Only . and .. are not hidden. */
339 if (p
[0] == '.' && !((p
[1] == '\0') ||
340 (p
[1] == '.' && p
[2] == '\0'))) {
345 result
|= dos_mode_from_sbuf(conn
, path
, &sbuf
);
347 /* Optimization : Only call is_hidden_path if it's not already
349 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
353 DEBUG(8,("dos_mode_msdfs returning "));
355 if (result
& aHIDDEN
) DEBUG(8, ("h"));
356 if (result
& aRONLY
) DEBUG(8, ("r"));
357 if (result
& aSYSTEM
) DEBUG(8, ("s"));
358 if (result
& aDIR
) DEBUG(8, ("d"));
359 if (result
& aARCH
) DEBUG(8, ("a"));
360 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
367 #ifdef HAVE_STAT_DOS_FLAGS
368 /****************************************************************************
369 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
370 ****************************************************************************/
372 int dos_attributes_to_stat_dos_flags(uint32_t dosmode
)
374 uint32_t dos_stat_flags
= 0;
377 dos_stat_flags
|= UF_DOS_ARCHIVE
;
378 if (dosmode
& aHIDDEN
)
379 dos_stat_flags
|= UF_DOS_HIDDEN
;
380 if (dosmode
& aRONLY
)
381 dos_stat_flags
|= UF_DOS_RO
;
382 if (dosmode
& aSYSTEM
)
383 dos_stat_flags
|= UF_DOS_SYSTEM
;
384 if (dosmode
& FILE_ATTRIBUTE_NONINDEXED
)
385 dos_stat_flags
|= UF_DOS_NOINDEX
;
387 return dos_stat_flags
;
390 /****************************************************************************
391 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
392 ****************************************************************************/
394 static bool get_stat_dos_flags(connection_struct
*conn
,
396 const SMB_STRUCT_STAT
*sbuf
,
399 SMB_ASSERT(sbuf
&& VALID_STAT(*sbuf
));
402 if (!lp_store_dos_attributes(SNUM(conn
))) {
406 DEBUG(5, ("Getting stat dos attributes for %s.\n", fname
));
408 if (sbuf
->st_ex_flags
& UF_DOS_ARCHIVE
)
410 if (sbuf
->st_ex_flags
& UF_DOS_HIDDEN
)
412 if (sbuf
->st_ex_flags
& UF_DOS_RO
)
414 if (sbuf
->st_ex_flags
& UF_DOS_SYSTEM
)
416 if (sbuf
->st_ex_flags
& UF_DOS_NOINDEX
)
417 *dosmode
|= FILE_ATTRIBUTE_NONINDEXED
;
418 if (S_ISDIR(sbuf
->st_ex_mode
))
421 *dosmode
|= set_sparse_flag(sbuf
);
422 *dosmode
|= set_link_read_only_flag(sbuf
);
427 /****************************************************************************
428 Sets DOS attributes, stored in st_ex_flags of the inode.
429 ****************************************************************************/
431 static bool set_stat_dos_flags(connection_struct
*conn
,
432 const struct smb_filename
*smb_fname
,
434 bool *attributes_changed
)
436 uint32_t new_flags
= 0;
439 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
440 SMB_ASSERT(attributes_changed
);
442 *attributes_changed
= false;
444 if (!lp_store_dos_attributes(SNUM(conn
))) {
448 DEBUG(5, ("Setting stat dos attributes for %s.\n",
449 smb_fname_str_dbg(smb_fname
)));
451 new_flags
= (smb_fname
->st
.st_ex_flags
& ~UF_DOS_FLAGS
) |
452 dos_attributes_to_stat_dos_flags(dosmode
);
454 /* Return early if no flags changed. */
455 if (new_flags
== smb_fname
->st
.st_ex_flags
)
458 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags
,
459 smb_fname
->st
.st_ex_flags
));
461 /* Set new flags with chflags. */
462 error
= SMB_VFS_CHFLAGS(conn
, smb_fname
->base_name
, new_flags
);
464 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
465 "file %s! errno=%d\n", new_flags
,
466 smb_fname_str_dbg(smb_fname
), errno
));
470 *attributes_changed
= true;
473 #endif /* HAVE_STAT_DOS_FLAGS */
475 /****************************************************************************
476 Change a unix mode to a dos mode.
477 ****************************************************************************/
479 uint32
dos_mode(connection_struct
*conn
, const char *path
, const SMB_STRUCT_STAT
*psbuf
)
481 SMB_STRUCT_STAT sbuf
= *psbuf
;
483 bool offline
, used_stat_dos_flags
= false;
485 DEBUG(8,("dos_mode: %s\n", path
));
487 if (!VALID_STAT(sbuf
)) {
491 /* First do any modifications that depend on the path name. */
492 /* hide files with a name starting with a . */
493 if (lp_hide_dot_files(SNUM(conn
))) {
494 const char *p
= strrchr_m(path
,'/');
501 /* Only . and .. are not hidden. */
502 if (p
[0] == '.' && !((p
[1] == '\0') ||
503 (p
[1] == '.' && p
[2] == '\0'))) {
508 #ifdef HAVE_STAT_DOS_FLAGS
509 used_stat_dos_flags
= get_stat_dos_flags(conn
, path
, &sbuf
, &result
);
511 if (!used_stat_dos_flags
) {
512 /* Get the DOS attributes from an EA by preference. */
513 if (get_ea_dos_attribute(conn
, path
, &sbuf
, &result
)) {
514 result
|= set_sparse_flag(&sbuf
);
516 result
|= dos_mode_from_sbuf(conn
, path
, &sbuf
);
520 offline
= SMB_VFS_IS_OFFLINE(conn
, path
, &sbuf
);
521 if (S_ISREG(sbuf
.st_ex_mode
) && offline
) {
522 result
|= FILE_ATTRIBUTE_OFFLINE
;
525 /* Optimization : Only call is_hidden_path if it's not already
527 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
531 DEBUG(8,("dos_mode returning "));
533 if (result
& aHIDDEN
) DEBUG(8, ("h"));
534 if (result
& aRONLY
) DEBUG(8, ("r"));
535 if (result
& aSYSTEM
) DEBUG(8, ("s"));
536 if (result
& aDIR
) DEBUG(8, ("d"));
537 if (result
& aARCH
) DEBUG(8, ("a"));
538 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
545 /*******************************************************************
546 chmod a file - but preserve some bits.
547 ********************************************************************/
549 int file_set_dosmode(connection_struct
*conn
, struct smb_filename
*smb_fname
,
550 uint32 dosmode
, const char *parent_dir
, bool newfile
)
555 int ret
= -1, lret
= -1;
560 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
561 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
563 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
564 dosmode
, smb_fname_str_dbg(smb_fname
)));
566 if (!VALID_STAT(smb_fname
->st
)) {
567 if (SMB_VFS_STAT(conn
, smb_fname
))
571 unixmode
= smb_fname
->st
.st_ex_mode
;
573 get_acl_group_bits(conn
, smb_fname
->base_name
,
574 &smb_fname
->st
.st_ex_mode
);
576 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
581 status
= get_full_smb_filename(talloc_tos(), smb_fname
, &fname
);
582 if (!NT_STATUS_IS_OK(status
)) {
583 errno
= map_errno_from_nt_status(status
);
587 old_mode
= dos_mode(conn
, fname
, &smb_fname
->st
);
589 if (dosmode
& FILE_ATTRIBUTE_OFFLINE
) {
590 if (!(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
591 lret
= SMB_VFS_SET_OFFLINE(conn
, fname
);
593 DEBUG(0, ("set_dos_mode: client has asked to "
594 "set FILE_ATTRIBUTE_OFFLINE to "
595 "%s/%s but there was an error while "
596 "setting it or it is not "
597 "supported.\n", parent_dir
,
598 smb_fname_str_dbg(smb_fname
)));
603 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
604 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
606 if (old_mode
== dosmode
) {
607 smb_fname
->st
.st_ex_mode
= unixmode
;
611 #ifdef HAVE_STAT_DOS_FLAGS
613 bool attributes_changed
;
615 if (set_stat_dos_flags(conn
, smb_fname
, dosmode
,
616 &attributes_changed
))
618 if (!newfile
&& attributes_changed
) {
619 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
620 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
622 smb_fname
->st
.st_ex_mode
= unixmode
;
628 /* Store the DOS attributes in an EA by preference. */
629 if (set_ea_dos_attribute(conn
, fname
, &smb_fname
->st
, dosmode
)) {
631 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
632 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
634 smb_fname
->st
.st_ex_mode
= unixmode
;
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 */
648 /* possibly preserve the x bits */
649 if (!MAP_ARCHIVE(conn
))
651 if (!MAP_SYSTEM(conn
))
653 if (!MAP_HIDDEN(conn
))
656 unixmode
|= (smb_fname
->st
.st_ex_mode
& mask
);
658 /* if we previously had any r bits set then leave them alone */
659 if ((tmp
= smb_fname
->st
.st_ex_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
660 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
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
|= (smb_fname
->st
.st_ex_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
670 ret
= SMB_VFS_CHMOD(conn
, fname
, unixmode
);
672 if(!newfile
|| (lret
!= -1)) {
673 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
674 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
676 smb_fname
->st
.st_ex_mode
= unixmode
;
680 if((errno
!= EPERM
) && (errno
!= EACCES
))
683 if(!lp_dos_filemode(SNUM(conn
)))
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.
701 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL
, conn
, fname
,
702 &smb_fname
->st
, &fsp
)))
705 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
707 close_file_fchmod(NULL
, fsp
);
709 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
710 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
713 smb_fname
->st
.st_ex_mode
= unixmode
;
720 /*******************************************************************
721 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
723 *******************************************************************/
725 int file_ntimes(connection_struct
*conn
, const char *fname
,
726 struct smb_file_time
*ft
, const SMB_STRUCT_STAT
*psbuf
)
728 struct smb_filename
*smb_fname
= NULL
;
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
)) {
752 if(SMB_VFS_NTIMES(conn
, fname
, ft
) == 0) {
756 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
760 if(!lp_dos_filetimes(SNUM(conn
))) {
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
770 status
= create_synthetic_smb_fname_split(talloc_tos(), fname
, psbuf
,
773 if (!NT_STATUS_IS_OK(status
)) {
777 /* Check if we have write access. */
778 if (can_write_to_file(conn
, smb_fname
)) {
779 /* We are allowed to become root and change the filetime. */
781 ret
= SMB_VFS_NTIMES(conn
, fname
, ft
);
784 TALLOC_FREE(smb_fname
);
789 /******************************************************************
790 Force a "sticky" write time on a pathname. This will always be
791 returned on all future write time queries and set on close.
792 ******************************************************************/
794 bool set_sticky_write_time_path(connection_struct
*conn
, const char *fname
,
795 struct file_id fileid
, const struct timespec mtime
)
797 if (null_timespec(mtime
)) {
801 if (!set_sticky_write_time(fileid
, mtime
)) {
808 /******************************************************************
809 Force a "sticky" write time on an fsp. This will always be
810 returned on all future write time queries and set on close.
811 ******************************************************************/
813 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, const struct timespec mtime
)
815 fsp
->write_time_forced
= true;
816 TALLOC_FREE(fsp
->update_write_time_event
);
818 return set_sticky_write_time_path(fsp
->conn
, fsp
->fsp_name
,
819 fsp
->file_id
, mtime
);
822 /******************************************************************
823 Update a write time immediately, without the 2 second delay.
824 ******************************************************************/
826 bool update_write_time(struct files_struct
*fsp
)
828 if (!set_write_time(fsp
->file_id
, timespec_current())) {
832 notify_fname(fsp
->conn
, NOTIFY_ACTION_MODIFIED
,
833 FILE_NOTIFY_CHANGE_LAST_WRITE
, fsp
->fsp_name
);