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,
68 const struct smb_filename *smb_fname,
69 const char *inherit_from_dir)
71 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
72 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
75 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
76 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
79 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
80 struct smb_filename *smb_fname_parent = NULL;
83 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
84 smb_fname_str_dbg(smb_fname),
87 status = create_synthetic_smb_fname(talloc_tos(),
88 inherit_from_dir, NULL,
89 NULL, &smb_fname_parent);
90 if (!NT_STATUS_IS_OK(status)) {
91 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
92 smb_fname_str_dbg(smb_fname),
93 inherit_from_dir, nt_errstr(status)));
97 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
98 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
99 smb_fname_str_dbg(smb_fname),
100 inherit_from_dir, strerror(errno)));
101 TALLOC_FREE(smb_fname_parent);
102 return(0); /* *** shouldn't happen! *** */
105 /* Save for later - but explicitly remove setuid bit for safety. */
106 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
107 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
108 smb_fname_str_dbg(smb_fname), (int)dir_mode));
111 TALLOC_FREE(smb_fname_parent);
114 if (IS_DOS_DIR(dosmode)) {
115 /* We never make directories read only for the owner as under DOS a user
116 can always create a file in a read-only directory. */
117 result |= (S_IFDIR | S_IWUSR);
120 /* Inherit mode of parent directory. */
123 /* Provisionally add all 'x' bits */
124 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
126 /* Apply directory mask */
127 result &= lp_dir_mask(SNUM(conn));
128 /* Add in force bits */
129 result |= lp_force_dir_mode(SNUM(conn));
132 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
135 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
138 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
142 /* Inherit 666 component of parent directory mode */
143 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
145 /* Apply mode mask */
146 result &= lp_create_mask(SNUM(conn));
147 /* Add in force bits */
148 result |= lp_force_create_mode(SNUM(conn));
152 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
157 /****************************************************************************
158 Change a unix mode to a dos mode.
159 ****************************************************************************/
161 static uint32 dos_mode_from_sbuf(connection_struct *conn,
162 const struct smb_filename *smb_fname)
165 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
167 if (ro_opts == MAP_READONLY_YES) {
168 /* Original Samba method - map inverse of user "w" bit. */
169 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
172 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
173 /* Check actual permissions for read-only. */
174 if (!can_write_to_file(conn, smb_fname)) {
177 } /* Else never set the readonly bit. */
179 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
182 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
185 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
188 if (S_ISDIR(smb_fname->st.st_ex_mode))
189 result = aDIR | (result & aRONLY);
191 result |= set_sparse_flag(&smb_fname->st);
192 result |= set_link_read_only_flag(&smb_fname->st);
194 DEBUG(8,("dos_mode_from_sbuf returning "));
196 if (result & aHIDDEN) DEBUG(8, ("h"));
197 if (result & aRONLY ) DEBUG(8, ("r"));
198 if (result & aSYSTEM) DEBUG(8, ("s"));
199 if (result & aDIR ) DEBUG(8, ("d"));
200 if (result & aARCH ) DEBUG(8, ("a"));
206 /****************************************************************************
207 Get DOS attributes from an EA.
208 ****************************************************************************/
210 static bool get_ea_dos_attribute(connection_struct *conn,
211 const struct smb_filename *smb_fname,
216 unsigned int dosattr;
218 if (!lp_store_dos_attributes(SNUM(conn))) {
222 /* Don't reset pattr to zero as we may already have filename-based attributes we
225 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
226 SAMBA_XATTR_DOS_ATTRIB, attrstr,
231 || errno == ENOTSUP) {
235 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute "
236 "from EA on file %s: Error = %s\n",
237 smb_fname_str_dbg(smb_fname),
239 set_store_dos_attributes(SNUM(conn), False);
243 /* Null terminate string. */
244 attrstr[sizeret] = 0;
245 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n",
246 smb_fname_str_dbg(smb_fname), attrstr));
248 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
249 sscanf(attrstr, "%x", &dosattr) != 1) {
250 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on "
251 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
256 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
259 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
261 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
263 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
264 if (dosattr & aRONLY ) DEBUG(8, ("r"));
265 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
266 if (dosattr & aDIR ) DEBUG(8, ("d"));
267 if (dosattr & aARCH ) DEBUG(8, ("a"));
274 /****************************************************************************
275 Set DOS attributes in an EA.
276 ****************************************************************************/
278 static bool set_ea_dos_attribute(connection_struct *conn,
279 struct smb_filename *smb_fname,
283 files_struct *fsp = NULL;
286 if (!lp_store_dos_attributes(SNUM(conn))) {
290 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
291 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
292 SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr),
294 if((errno != EPERM) && (errno != EACCES)) {
297 || errno == ENOTSUP) {
301 DEBUG(1,("set_ea_dos_attributes: Cannot set "
302 "attribute EA on file %s: Error = %s\n",
303 smb_fname_str_dbg(smb_fname),
305 set_store_dos_attributes(SNUM(conn), False);
310 /* We want DOS semantics, ie allow non owner with write permission to change the
311 bits on a file. Just like file_ntimes below.
314 /* Check if we have write access. */
315 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
319 * We need to open the file with write access whilst
320 * still in our current user context. This ensures we
321 * are not violating security in doing the setxattr.
324 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
328 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
329 SAMBA_XATTR_DOS_ATTRIB, attrstr,
330 strlen(attrstr), 0) == 0) {
334 close_file_fchmod(NULL, fsp);
337 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr,
338 smb_fname_str_dbg(smb_fname)));
342 /****************************************************************************
343 Change a unix mode to a dos mode for an ms dfs link.
344 ****************************************************************************/
346 uint32 dos_mode_msdfs(connection_struct *conn,
347 const struct smb_filename *smb_fname)
351 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
353 if (!VALID_STAT(smb_fname->st)) {
357 /* First do any modifications that depend on the path name. */
358 /* hide files with a name starting with a . */
359 if (lp_hide_dot_files(SNUM(conn))) {
360 const char *p = strrchr_m(smb_fname->base_name, '/');
364 p = smb_fname->base_name;
367 /* Only . and .. are not hidden. */
368 if (p[0] == '.' && !((p[1] == '\0') ||
369 (p[1] == '.' && p[2] == '\0'))) {
374 result |= dos_mode_from_sbuf(conn, smb_fname);
376 /* Optimization : Only call is_hidden_path if it's not already
378 if (!(result & aHIDDEN) &&
379 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
383 DEBUG(8,("dos_mode_msdfs returning "));
385 if (result & aHIDDEN) DEBUG(8, ("h"));
386 if (result & aRONLY ) DEBUG(8, ("r"));
387 if (result & aSYSTEM) DEBUG(8, ("s"));
388 if (result & aDIR ) DEBUG(8, ("d"));
389 if (result & aARCH ) DEBUG(8, ("a"));
390 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
397 #ifdef HAVE_STAT_DOS_FLAGS
398 /****************************************************************************
399 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
400 ****************************************************************************/
402 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
404 uint32_t dos_stat_flags = 0;
407 dos_stat_flags |= UF_DOS_ARCHIVE;
408 if (dosmode & aHIDDEN)
409 dos_stat_flags |= UF_DOS_HIDDEN;
410 if (dosmode & aRONLY)
411 dos_stat_flags |= UF_DOS_RO;
412 if (dosmode & aSYSTEM)
413 dos_stat_flags |= UF_DOS_SYSTEM;
414 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
415 dos_stat_flags |= UF_DOS_NOINDEX;
417 return dos_stat_flags;
420 /****************************************************************************
421 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
422 ****************************************************************************/
424 static bool get_stat_dos_flags(connection_struct *conn,
425 const struct smb_filename *smb_fname,
428 SMB_ASSERT(VALID_STAT(smb_fname->st));
431 if (!lp_store_dos_attributes(SNUM(conn))) {
435 DEBUG(5, ("Getting stat dos attributes for %s.\n",
436 smb_fname_str_dbg(smb_fname)));
438 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
440 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
442 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
444 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
446 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
447 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
448 if (S_ISDIR(smb_fname->st.st_ex_mode))
451 *dosmode |= set_sparse_flag(&smb_fname->st);
452 *dosmode |= set_link_read_only_flag(&smb_fname->st);
457 /****************************************************************************
458 Sets DOS attributes, stored in st_ex_flags of the inode.
459 ****************************************************************************/
461 static bool set_stat_dos_flags(connection_struct *conn,
462 const struct smb_filename *smb_fname,
464 bool *attributes_changed)
466 uint32_t new_flags = 0;
469 SMB_ASSERT(VALID_STAT(smb_fname->st));
470 SMB_ASSERT(attributes_changed);
472 *attributes_changed = false;
474 if (!lp_store_dos_attributes(SNUM(conn))) {
478 DEBUG(5, ("Setting stat dos attributes for %s.\n",
479 smb_fname_str_dbg(smb_fname)));
481 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
482 dos_attributes_to_stat_dos_flags(dosmode);
484 /* Return early if no flags changed. */
485 if (new_flags == smb_fname->st.st_ex_flags)
488 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
489 smb_fname->st.st_ex_flags));
491 /* Set new flags with chflags. */
492 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
494 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
495 "file %s! errno=%d\n", new_flags,
496 smb_fname_str_dbg(smb_fname), errno));
500 *attributes_changed = true;
503 #endif /* HAVE_STAT_DOS_FLAGS */
505 /****************************************************************************
506 Change a unix mode to a dos mode.
507 ****************************************************************************/
509 uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname)
511 SMB_STRUCT_STAT sbuf;
513 bool offline, used_stat_dos_flags = false;
515 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
517 if (!VALID_STAT(smb_fname->st)) {
521 /* First do any modifications that depend on the path name. */
522 /* hide files with a name starting with a . */
523 if (lp_hide_dot_files(SNUM(conn))) {
524 const char *p = strrchr_m(smb_fname->base_name,'/');
528 p = smb_fname->base_name;
531 /* Only . and .. are not hidden. */
532 if (p[0] == '.' && !((p[1] == '\0') ||
533 (p[1] == '.' && p[2] == '\0'))) {
538 #ifdef HAVE_STAT_DOS_FLAGS
539 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
541 if (!used_stat_dos_flags) {
542 /* Get the DOS attributes from an EA by preference. */
543 if (get_ea_dos_attribute(conn, smb_fname, &result)) {
544 result |= set_sparse_flag(&smb_fname->st);
546 result |= dos_mode_from_sbuf(conn, smb_fname);
550 sbuf = smb_fname->st;
551 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &sbuf);
552 if (S_ISREG(sbuf.st_ex_mode) && offline) {
553 result |= FILE_ATTRIBUTE_OFFLINE;
556 /* Optimization : Only call is_hidden_path if it's not already
558 if (!(result & aHIDDEN) &&
559 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
563 DEBUG(8,("dos_mode returning "));
565 if (result & aHIDDEN) DEBUG(8, ("h"));
566 if (result & aRONLY ) DEBUG(8, ("r"));
567 if (result & aSYSTEM) DEBUG(8, ("s"));
568 if (result & aDIR ) DEBUG(8, ("d"));
569 if (result & aARCH ) DEBUG(8, ("a"));
570 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
577 /*******************************************************************
578 chmod a file - but preserve some bits.
579 ********************************************************************/
581 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
582 uint32 dosmode, const char *parent_dir, bool newfile)
587 int ret = -1, lret = -1;
590 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
591 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
593 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
594 dosmode, smb_fname_str_dbg(smb_fname)));
596 if (!VALID_STAT(smb_fname->st)) {
597 if (SMB_VFS_STAT(conn, smb_fname))
601 unixmode = smb_fname->st.st_ex_mode;
603 get_acl_group_bits(conn, smb_fname->base_name,
604 &smb_fname->st.st_ex_mode);
606 if (S_ISDIR(smb_fname->st.st_ex_mode))
611 old_mode = dos_mode(conn, smb_fname);
613 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
614 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
615 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name);
617 DEBUG(0, ("set_dos_mode: client has asked to "
618 "set FILE_ATTRIBUTE_OFFLINE to "
619 "%s/%s but there was an error while "
620 "setting it or it is not "
621 "supported.\n", parent_dir,
622 smb_fname_str_dbg(smb_fname)));
627 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
628 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
630 if (old_mode == dosmode) {
631 smb_fname->st.st_ex_mode = unixmode;
635 #ifdef HAVE_STAT_DOS_FLAGS
637 bool attributes_changed;
639 if (set_stat_dos_flags(conn, smb_fname, dosmode,
640 &attributes_changed))
642 if (!newfile && attributes_changed) {
643 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
644 FILE_NOTIFY_CHANGE_ATTRIBUTES,
645 smb_fname->base_name);
647 smb_fname->st.st_ex_mode = unixmode;
652 /* Store the DOS attributes in an EA by preference. */
653 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
655 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
656 FILE_NOTIFY_CHANGE_ATTRIBUTES,
657 smb_fname->base_name);
659 smb_fname->st.st_ex_mode = unixmode;
663 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
665 /* preserve the s bits */
666 mask |= (S_ISUID | S_ISGID);
668 /* preserve the t bit */
673 /* possibly preserve the x bits */
674 if (!MAP_ARCHIVE(conn))
676 if (!MAP_SYSTEM(conn))
678 if (!MAP_HIDDEN(conn))
681 unixmode |= (smb_fname->st.st_ex_mode & mask);
683 /* if we previously had any r bits set then leave them alone */
684 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
685 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
689 /* if we previously had any w bits set then leave them alone
690 whilst adding in the new w bits, if the new mode is not rdonly */
691 if (!IS_DOS_READONLY(dosmode)) {
692 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
695 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
697 if(!newfile || (lret != -1)) {
698 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
699 FILE_NOTIFY_CHANGE_ATTRIBUTES,
700 smb_fname->base_name);
702 smb_fname->st.st_ex_mode = unixmode;
706 if((errno != EPERM) && (errno != EACCES))
709 if(!lp_dos_filemode(SNUM(conn)))
712 /* We want DOS semantics, ie allow non owner with write permission to change the
713 bits on a file. Just like file_ntimes below.
716 /* Check if we have write access. */
717 if (CAN_WRITE(conn)) {
719 * We need to open the file with write access whilst
720 * still in our current user context. This ensures we
721 * are not violating security in doing the fchmod.
722 * This file open does *not* break any oplocks we are
723 * holding. We need to review this.... may need to
724 * break batch oplocks open by others. JRA.
727 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
731 ret = SMB_VFS_FCHMOD(fsp, unixmode);
733 close_file_fchmod(NULL, fsp);
735 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
736 FILE_NOTIFY_CHANGE_ATTRIBUTES,
737 smb_fname->base_name);
740 smb_fname->st.st_ex_mode = unixmode;
747 /*******************************************************************
748 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
750 *******************************************************************/
752 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
753 struct smb_file_time *ft)
759 DEBUG(6, ("file_ntime: actime: %s",
760 time_to_asc(convert_timespec_to_time_t(ft->atime))));
761 DEBUG(6, ("file_ntime: modtime: %s",
762 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
763 DEBUG(6, ("file_ntime: ctime: %s",
764 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
765 DEBUG(6, ("file_ntime: createtime: %s",
766 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
768 /* Don't update the time on read-only shares */
769 /* We need this as set_filetime (which can be called on
770 close and other paths) can end up calling this function
771 without the NEED_WRITE protection. Found by :
772 Leo Weppelman <leo@wau.mis.ah.nl>
775 if (!CAN_WRITE(conn)) {
779 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
783 if((errno != EPERM) && (errno != EACCES)) {
787 if(!lp_dos_filetimes(SNUM(conn))) {
791 /* We have permission (given by the Samba admin) to
792 break POSIX semantics and allow a user to change
793 the time on a file they don't own but can write to
797 /* Check if we have write access. */
798 if (can_write_to_file(conn, smb_fname)) {
799 /* We are allowed to become root and change the filetime. */
801 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
808 /******************************************************************
809 Force a "sticky" write time on a pathname. This will always be
810 returned on all future write time queries and set on close.
811 ******************************************************************/
813 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
815 if (null_timespec(mtime)) {
819 if (!set_sticky_write_time(fileid, mtime)) {
826 /******************************************************************
827 Force a "sticky" write time on an fsp. This will always be
828 returned on all future write time queries and set on close.
829 ******************************************************************/
831 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
833 fsp->write_time_forced = true;
834 TALLOC_FREE(fsp->update_write_time_event);
836 return set_sticky_write_time_path(fsp->file_id, mtime);
839 /******************************************************************
840 Update a write time immediately, without the 2 second delay.
841 ******************************************************************/
843 bool update_write_time(struct files_struct *fsp)
845 if (!set_write_time(fsp->file_id, timespec_current())) {
849 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
850 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name);
855 /******************************************************************
856 Set a create time EA.
857 ******************************************************************/
859 NTSTATUS set_create_timespec_ea(connection_struct *conn,
860 struct files_struct *fsp,
861 const struct smb_filename *smb_fname,
862 struct timespec create_time)
867 if (!lp_store_create_time(SNUM(conn))) {
871 put_long_date_timespec(buf, create_time);
872 if (fsp && fsp->fh->fd != -1) {
873 ret = SMB_VFS_FSETXATTR(fsp,
874 SAMBA_XATTR_DOSTIMESTAMPS,
879 ret = SMB_VFS_SETXATTR(conn,
880 smb_fname->base_name,
881 SAMBA_XATTR_DOSTIMESTAMPS,
888 map_nt_error_from_unix(errno);
890 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
891 smb_fname_str_dbg(smb_fname)));
895 /******************************************************************
896 Returns an EA create timespec, or a zero timespec if fail.
897 ******************************************************************/
899 static struct timespec get_create_timespec_ea(connection_struct *conn,
900 struct files_struct *fsp,
901 const struct smb_filename *smb_fname)
909 if (!lp_store_create_time(SNUM(conn))) {
913 if (fsp && fsp->fh->fd != -1) {
914 ret = SMB_VFS_FGETXATTR(fsp,
915 SAMBA_XATTR_DOSTIMESTAMPS,
919 ret = SMB_VFS_GETXATTR(conn,
920 smb_fname->base_name,
921 SAMBA_XATTR_DOSTIMESTAMPS,
925 if (ret == sizeof(buf)) {
926 return interpret_long_date(buf);
932 /******************************************************************
933 Return a create time - looks at EA.
934 ******************************************************************/
936 struct timespec get_create_timespec(connection_struct *conn,
937 struct files_struct *fsp,
938 const struct smb_filename *smb_fname)
940 struct timespec ts = get_create_timespec_ea(conn, fsp, smb_fname);
942 if (!null_timespec(ts)) {
945 return smb_fname->st.st_ex_btime;
949 /******************************************************************
950 Return a change time (may look at EA in future).
951 ******************************************************************/
953 struct timespec get_change_timespec(connection_struct *conn,
954 struct files_struct *fsp,
955 const struct smb_filename *smb_fname)
957 return smb_fname->st.st_ex_mtime;