2 Unix SMB/Netbios implementation.
4 dos mode handling functions
5 Copyright (C) Andrew Tridgell 1992-1998
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 extern int DEBUGLEVEL;
26 /****************************************************************************
27 change a dos mode to a unix mode
28 base permission for files:
29 everybody gets read bit set
30 dos readonly is represented in unix by removing everyone's write bit
31 dos archive is represented in unix by the user's execute bit
32 dos system is represented in unix by the group's execute bit
33 dos hidden is represented in unix by the other's execute bit
34 Then apply create mask,
36 base permission for directories:
37 dos directory is represented in unix by unix's dir bit and the exec bit
38 Then apply create mask,
40 ****************************************************************************/
41 mode_t unix_mode(connection_struct *conn,int dosmode)
43 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
45 if ( !IS_DOS_READONLY(dosmode) )
46 result |= (S_IWUSR | S_IWGRP | S_IWOTH);
48 if (IS_DOS_DIR(dosmode)) {
49 /* We never make directories read only for the owner as under DOS a user
50 can always create a file in a read-only directory. */
51 result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
52 /* Apply directory mask */
53 result &= lp_dir_mode(SNUM(conn));
54 /* Add in force bits */
55 result |= lp_force_dir_mode(SNUM(conn));
57 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
60 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
63 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
67 result &= lp_create_mode(SNUM(conn));
68 /* Add in force bits */
69 result |= lp_force_create_mode(SNUM(conn));
75 /****************************************************************************
76 change a unix mode to a dos mode
77 ****************************************************************************/
78 int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
82 DEBUG(8,("dos_mode: %s\n", path));
84 if ((sbuf->st_mode & S_IWUSR) == 0)
87 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
90 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
93 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
96 if (S_ISDIR(sbuf->st_mode))
97 result = aDIR | (result & aRONLY);
101 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
106 /* hide files with a name starting with a . */
107 if (lp_hide_dot_files(SNUM(conn)))
109 char *p = strrchr(path,'/');
115 if (p[0] == '.' && p[1] != '.' && p[1] != 0)
119 /* Optimization : Only call is_hidden_path if it's not already
121 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path))
126 DEBUG(8,("dos_mode returning "));
128 if (result & aHIDDEN) DEBUG(8, ("h"));
129 if (result & aRONLY ) DEBUG(8, ("r"));
130 if (result & aSYSTEM) DEBUG(8, ("s"));
131 if (result & aDIR ) DEBUG(8, ("d"));
132 if (result & aARCH ) DEBUG(8, ("a"));
139 /*******************************************************************
140 chmod a file - but preserve some bits
141 ********************************************************************/
142 int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st)
151 if (conn->vfs_ops.stat(dos_to_unix(fname,False),st)) return(-1);
154 if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
156 if (dos_mode(conn,fname,st) == dosmode) return(0);
158 unixmode = unix_mode(conn,dosmode);
160 /* preserve the s bits */
161 mask |= (S_ISUID | S_ISGID);
163 /* preserve the t bit */
168 /* possibly preserve the x bits */
169 if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR;
170 if (!MAP_SYSTEM(conn)) mask |= S_IXGRP;
171 if (!MAP_HIDDEN(conn)) mask |= S_IXOTH;
173 unixmode |= (st->st_mode & mask);
175 /* if we previously had any r bits set then leave them alone */
176 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
177 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
181 /* if we previously had any w bits set then leave them alone
182 if the new mode is not rdonly */
183 if (!IS_DOS_READONLY(dosmode) &&
184 (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
185 unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
189 return(conn->vfs_ops.chmod(fname,unixmode));
193 /*******************************************************************
194 Wrapper around dos_utime that possibly allows DOS semantics rather
196 *******************************************************************/
197 int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
199 extern struct current_user current_user;
205 if(conn->vfs_ops.utime(dos_to_unix(fname, False), times) == 0)
208 if((errno != EPERM) && (errno != EACCES))
211 if(!lp_dos_filetimes(SNUM(conn)))
214 /* We have permission (given by the Samba admin) to
215 break POSIX semantics and allow a user to change
216 the time on a file they don't own but can write to
220 if(conn->vfs_ops.stat(dos_to_unix(fname,False),&sb) != 0)
223 /* Check if we have write access. */
224 if (CAN_WRITE(conn)) {
225 if (((sb.st_mode & S_IWOTH) ||
227 ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
228 ((sb.st_mode & S_IWGRP) &&
229 in_group(sb.st_gid,current_user.gid,
230 current_user.ngroups,current_user.groups)))) {
231 /* We are allowed to become root and change the filetime. */
233 ret = conn->vfs_ops.utime(dos_to_unix(fname, False), times);
234 unbecome_root(False);
241 /*******************************************************************
242 Change a filetime - possibly allowing DOS semantics.
243 *******************************************************************/
244 BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
246 struct utimbuf times;
248 if (null_mtime(mtime)) return(True);
250 times.modtime = times.actime = mtime;
252 if (file_utime(conn, fname, ×)) {
253 DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));