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_size
> sbuf
->st_blocks
* (SMB_OFF_T
)STAT_ST_BLOCKSIZE
) {
27 return FILE_ATTRIBUTE_SPARSE
;
33 /****************************************************************************
34 Change a dos mode to a unix mode.
35 Base permission for files:
36 if creating file and inheriting (i.e. parent_dir != NULL)
37 apply read/write bits from parent directory.
39 everybody gets read bit set
40 dos readonly is represented in unix by removing everyone's write bit
41 dos archive is represented in unix by the user's execute bit
42 dos system is represented in unix by the group's execute bit
43 dos hidden is represented in unix by the other's execute bit
45 Then apply create mask,
48 Base permission for directories:
49 dos directory is represented in unix by unix's dir bit and the exec bit
51 Then apply create mask,
54 ****************************************************************************/
56 mode_t
unix_mode(connection_struct
*conn
, int dosmode
, const char *fname
,
57 const char *inherit_from_dir
)
59 mode_t result
= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
60 mode_t dir_mode
= 0; /* Mode of the inherit_from directory if
63 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
64 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
67 if (fname
&& (inherit_from_dir
!= NULL
)
68 && lp_inherit_perms(SNUM(conn
))) {
71 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname
,
73 if (SMB_VFS_STAT(conn
, inherit_from_dir
, &sbuf
) != 0) {
74 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname
,
75 inherit_from_dir
, strerror(errno
)));
76 return(0); /* *** shouldn't happen! *** */
79 /* Save for later - but explicitly remove setuid bit for safety. */
80 dir_mode
= sbuf
.st_mode
& ~S_ISUID
;
81 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname
,(int)dir_mode
));
86 if (IS_DOS_DIR(dosmode
)) {
87 /* We never make directories read only for the owner as under DOS a user
88 can always create a file in a read-only directory. */
89 result
|= (S_IFDIR
| S_IWUSR
);
92 /* Inherit mode of parent directory. */
95 /* Provisionally add all 'x' bits */
96 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
98 /* Apply directory mask */
99 result
&= lp_dir_mask(SNUM(conn
));
100 /* Add in force bits */
101 result
|= lp_force_dir_mode(SNUM(conn
));
104 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
107 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
110 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
114 /* Inherit 666 component of parent directory mode */
115 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
117 /* Apply mode mask */
118 result
&= lp_create_mask(SNUM(conn
));
119 /* Add in force bits */
120 result
|= lp_force_create_mode(SNUM(conn
));
124 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname
,(int)result
));
128 /****************************************************************************
129 Change a unix mode to a dos mode.
130 ****************************************************************************/
132 static uint32
dos_mode_from_sbuf(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
)
135 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
137 if (ro_opts
== MAP_READONLY_YES
) {
138 /* Original Samba method - map inverse of user "w" bit. */
139 if ((sbuf
->st_mode
& S_IWUSR
) == 0) {
142 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
143 /* Check actual permissions for read-only. */
144 if (!can_write_to_file(conn
, path
, sbuf
)) {
147 } /* Else never set the readonly bit. */
149 if (MAP_ARCHIVE(conn
) && ((sbuf
->st_mode
& S_IXUSR
) != 0))
152 if (MAP_SYSTEM(conn
) && ((sbuf
->st_mode
& S_IXGRP
) != 0))
155 if (MAP_HIDDEN(conn
) && ((sbuf
->st_mode
& S_IXOTH
) != 0))
158 if (S_ISDIR(sbuf
->st_mode
))
159 result
= aDIR
| (result
& aRONLY
);
161 result
|= set_sparse_flag(sbuf
);
165 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
170 DEBUG(8,("dos_mode_from_sbuf returning "));
172 if (result
& aHIDDEN
) DEBUG(8, ("h"));
173 if (result
& aRONLY
) DEBUG(8, ("r"));
174 if (result
& aSYSTEM
) DEBUG(8, ("s"));
175 if (result
& aDIR
) DEBUG(8, ("d"));
176 if (result
& aARCH
) DEBUG(8, ("a"));
182 /****************************************************************************
183 Get DOS attributes from an EA.
184 ****************************************************************************/
186 static bool get_ea_dos_attribute(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
, uint32
*pattr
)
190 unsigned int dosattr
;
192 if (!lp_store_dos_attributes(SNUM(conn
))) {
196 /* Don't reset pattr to zero as we may already have filename-based attributes we
199 sizeret
= SMB_VFS_GETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, sizeof(attrstr
));
203 || errno
== ENOTSUP
) {
207 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
208 path
, strerror(errno
) ));
209 set_store_dos_attributes(SNUM(conn
), False
);
213 /* Null terminate string. */
214 attrstr
[sizeret
] = 0;
215 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path
, attrstr
));
217 if (sizeret
< 2 || attrstr
[0] != '0' || attrstr
[1] != 'x' ||
218 sscanf(attrstr
, "%x", &dosattr
) != 1) {
219 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path
, attrstr
));
223 if (S_ISDIR(sbuf
->st_mode
)) {
226 *pattr
= (uint32
)(dosattr
& SAMBA_ATTRIBUTES_MASK
);
228 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
230 if (dosattr
& aHIDDEN
) DEBUG(8, ("h"));
231 if (dosattr
& aRONLY
) DEBUG(8, ("r"));
232 if (dosattr
& aSYSTEM
) DEBUG(8, ("s"));
233 if (dosattr
& aDIR
) DEBUG(8, ("d"));
234 if (dosattr
& aARCH
) DEBUG(8, ("a"));
241 /****************************************************************************
242 Set DOS attributes in an EA.
243 ****************************************************************************/
245 static bool set_ea_dos_attribute(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
, uint32 dosmode
)
248 files_struct
*fsp
= NULL
;
251 if (!lp_store_dos_attributes(SNUM(conn
))) {
255 snprintf(attrstr
, sizeof(attrstr
)-1, "0x%x", dosmode
& SAMBA_ATTRIBUTES_MASK
);
256 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == -1) {
257 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
260 || errno
== ENOTSUP
) {
264 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
265 path
, strerror(errno
) ));
266 set_store_dos_attributes(SNUM(conn
), False
);
271 /* We want DOS semantics, ie allow non owner with write permission to change the
272 bits on a file. Just like file_ntimes below.
275 /* Check if we have write access. */
276 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
280 * We need to open the file with write access whilst
281 * still in our current user context. This ensures we
282 * are not violating security in doing the setxattr.
285 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
,path
,sbuf
,&fsp
)))
288 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == 0) {
292 close_file_fchmod(fsp
);
295 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr
, path
));
299 /****************************************************************************
300 Change a unix mode to a dos mode for an ms dfs link.
301 ****************************************************************************/
303 uint32
dos_mode_msdfs(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
)
307 DEBUG(8,("dos_mode_msdfs: %s\n", path
));
309 if (!VALID_STAT(*sbuf
)) {
313 /* First do any modifications that depend on the path name. */
314 /* hide files with a name starting with a . */
315 if (lp_hide_dot_files(SNUM(conn
))) {
316 const char *p
= strrchr_m(path
,'/');
323 if (p
[0] == '.' && p
[1] != '.' && p
[1] != 0) {
328 result
|= dos_mode_from_sbuf(conn
, path
, sbuf
);
330 /* Optimization : Only call is_hidden_path if it's not already
332 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
336 DEBUG(8,("dos_mode_msdfs returning "));
338 if (result
& aHIDDEN
) DEBUG(8, ("h"));
339 if (result
& aRONLY
) DEBUG(8, ("r"));
340 if (result
& aSYSTEM
) DEBUG(8, ("s"));
341 if (result
& aDIR
) DEBUG(8, ("d"));
342 if (result
& aARCH
) DEBUG(8, ("a"));
343 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
350 /****************************************************************************
351 Change a unix mode to a dos mode.
352 ****************************************************************************/
354 uint32
dos_mode(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
)
359 DEBUG(8,("dos_mode: %s\n", path
));
361 if (!VALID_STAT(*sbuf
)) {
365 /* First do any modifications that depend on the path name. */
366 /* hide files with a name starting with a . */
367 if (lp_hide_dot_files(SNUM(conn
))) {
368 const char *p
= strrchr_m(path
,'/');
375 if (p
[0] == '.' && p
[1] != '.' && p
[1] != 0) {
380 /* Get the DOS attributes from an EA by preference. */
381 if (get_ea_dos_attribute(conn
, path
, sbuf
, &result
)) {
382 result
|= set_sparse_flag(sbuf
);
384 result
|= dos_mode_from_sbuf(conn
, path
, sbuf
);
388 offline
= SMB_VFS_IS_OFFLINE(conn
, path
, sbuf
);
389 if (S_ISREG(sbuf
->st_mode
) && offline
) {
390 result
|= FILE_ATTRIBUTE_OFFLINE
;
393 /* Optimization : Only call is_hidden_path if it's not already
395 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
399 DEBUG(8,("dos_mode returning "));
401 if (result
& aHIDDEN
) DEBUG(8, ("h"));
402 if (result
& aRONLY
) DEBUG(8, ("r"));
403 if (result
& aSYSTEM
) DEBUG(8, ("s"));
404 if (result
& aDIR
) DEBUG(8, ("d"));
405 if (result
& aARCH
) DEBUG(8, ("a"));
406 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
413 /*******************************************************************
414 chmod a file - but preserve some bits.
415 ********************************************************************/
417 int file_set_dosmode(connection_struct
*conn
, const char *fname
,
418 uint32 dosmode
, SMB_STRUCT_STAT
*st
,
419 const char *parent_dir
,
426 int ret
= -1, lret
= -1;
429 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
430 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
432 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode
, fname
));
435 SET_STAT_INVALID(st1
);
439 if (!VALID_STAT(*st
)) {
440 if (SMB_VFS_STAT(conn
,fname
,st
))
444 unixmode
= st
->st_mode
;
446 get_acl_group_bits(conn
, fname
, &st
->st_mode
);
448 if (S_ISDIR(st
->st_mode
))
453 old_mode
= dos_mode(conn
,fname
,st
);
455 if (dosmode
& FILE_ATTRIBUTE_OFFLINE
) {
456 if (!(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
457 lret
= SMB_VFS_SET_OFFLINE(conn
, fname
);
459 DEBUG(0, ("set_dos_mode: client has asked to set "
460 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
461 "an error while setting it or it is not supported.\n",
467 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
468 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
470 if (old_mode
== dosmode
) {
471 st
->st_mode
= unixmode
;
475 /* Store the DOS attributes in an EA by preference. */
476 if (set_ea_dos_attribute(conn
, fname
, st
, dosmode
)) {
478 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
479 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
481 st
->st_mode
= unixmode
;
485 unixmode
= unix_mode(conn
,dosmode
,fname
, parent_dir
);
487 /* preserve the s bits */
488 mask
|= (S_ISUID
| S_ISGID
);
490 /* preserve the t bit */
495 /* possibly preserve the x bits */
496 if (!MAP_ARCHIVE(conn
))
498 if (!MAP_SYSTEM(conn
))
500 if (!MAP_HIDDEN(conn
))
503 unixmode
|= (st
->st_mode
& mask
);
505 /* if we previously had any r bits set then leave them alone */
506 if ((tmp
= st
->st_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
507 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
511 /* if we previously had any w bits set then leave them alone
512 whilst adding in the new w bits, if the new mode is not rdonly */
513 if (!IS_DOS_READONLY(dosmode
)) {
514 unixmode
|= (st
->st_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
517 ret
= SMB_VFS_CHMOD(conn
, fname
, unixmode
);
519 if(!newfile
|| (lret
!= -1)) {
520 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
521 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
523 st
->st_mode
= unixmode
;
527 if((errno
!= EPERM
) && (errno
!= EACCES
))
530 if(!lp_dos_filemode(SNUM(conn
)))
533 /* We want DOS semantics, ie allow non owner with write permission to change the
534 bits on a file. Just like file_ntimes below.
537 /* Check if we have write access. */
538 if (CAN_WRITE(conn
)) {
540 * We need to open the file with write access whilst
541 * still in our current user context. This ensures we
542 * are not violating security in doing the fchmod.
543 * This file open does *not* break any oplocks we are
544 * holding. We need to review this.... may need to
545 * break batch oplocks open by others. JRA.
548 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
,fname
,st
,&fsp
)))
551 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
553 close_file_fchmod(fsp
);
555 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
556 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
559 st
->st_mode
= unixmode
;
566 /*******************************************************************
567 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
569 *******************************************************************/
571 int file_ntimes(connection_struct
*conn
, const char *fname
, const struct timespec ts
[2])
573 SMB_STRUCT_STAT sbuf
;
579 DEBUG(6, ("file_ntime: actime: %s",
580 time_to_asc(convert_timespec_to_time_t(ts
[0]))));
581 DEBUG(6, ("file_ntime: modtime: %s",
582 time_to_asc(convert_timespec_to_time_t(ts
[1]))));
584 /* Don't update the time on read-only shares */
585 /* We need this as set_filetime (which can be called on
586 close and other paths) can end up calling this function
587 without the NEED_WRITE protection. Found by :
588 Leo Weppelman <leo@wau.mis.ah.nl>
591 if (!CAN_WRITE(conn
)) {
595 if(SMB_VFS_NTIMES(conn
, fname
, ts
) == 0) {
599 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
603 if(!lp_dos_filetimes(SNUM(conn
))) {
607 /* We have permission (given by the Samba admin) to
608 break POSIX semantics and allow a user to change
609 the time on a file they don't own but can write to
613 /* Check if we have write access. */
614 if (can_write_to_file(conn
, fname
, &sbuf
)) {
615 /* We are allowed to become root and change the filetime. */
617 ret
= SMB_VFS_NTIMES(conn
, fname
, ts
);
624 /******************************************************************
625 Force a "sticky" write time on a pathname. This will always be
626 returned on all future write time queries and set on close.
627 ******************************************************************/
629 bool set_sticky_write_time_path(connection_struct
*conn
, const char *fname
,
630 struct file_id fileid
, const struct timespec mtime
)
632 if (null_timespec(mtime
)) {
636 if (!set_sticky_write_time(fileid
, mtime
)) {
643 /******************************************************************
644 Force a "sticky" write time on an fsp. This will always be
645 returned on all future write time queries and set on close.
646 ******************************************************************/
648 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, const struct timespec mtime
)
650 fsp
->write_time_forced
= true;
651 TALLOC_FREE(fsp
->update_write_time_event
);
653 return set_sticky_write_time_path(fsp
->conn
, fsp
->fsp_name
,
654 fsp
->file_id
, mtime
);
657 /******************************************************************
658 Update a write time immediately, without the 2 second delay.
659 ******************************************************************/
661 bool update_write_time(struct files_struct
*fsp
)
663 if (!set_write_time(fsp
->file_id
, timespec_current())) {
667 notify_fname(fsp
->conn
, NOTIFY_ACTION_MODIFIED
,
668 FILE_NOTIFY_CHANGE_LAST_WRITE
, fsp
->fsp_name
);