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,struct stat *sbuf)
81 extern struct current_user current_user;
83 DEBUG(8,("dos_mode: %s\n", path));
85 if (CAN_WRITE(conn) && !lp_alternate_permissions(SNUM(conn))) {
86 if (!((sbuf->st_mode & S_IWOTH) ||
88 ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) ||
89 ((sbuf->st_mode & S_IWGRP) &&
90 in_group(sbuf->st_gid,current_user.gid,
91 current_user.ngroups,current_user.groups))))
94 if ((sbuf->st_mode & S_IWUSR) == 0)
98 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
101 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
104 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
107 if (S_ISDIR(sbuf->st_mode))
108 result = aDIR | (result & aRONLY);
112 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
117 /* hide files with a name starting with a . */
118 if (lp_hide_dot_files(SNUM(conn)))
120 char *p = strrchr(path,'/');
126 if (p[0] == '.' && p[1] != '.' && p[1] != 0)
130 /* Optimization : Only call is_hidden_path if it's not already
132 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path))
137 DEBUG(8,("dos_mode returning "));
139 if (result & aHIDDEN) DEBUG(8, ("h"));
140 if (result & aRONLY ) DEBUG(8, ("r"));
141 if (result & aSYSTEM) DEBUG(8, ("s"));
142 if (result & aDIR ) DEBUG(8, ("d"));
143 if (result & aARCH ) DEBUG(8, ("a"));
150 /*******************************************************************
151 chmod a file - but preserve some bits
152 ********************************************************************/
153 int dos_chmod(connection_struct *conn,char *fname,int dosmode,struct stat *st)
162 if (sys_stat(fname,st)) return(-1);
165 if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
167 if (dos_mode(conn,fname,st) == dosmode) return(0);
169 unixmode = unix_mode(conn,dosmode);
171 /* preserve the s bits */
172 mask |= (S_ISUID | S_ISGID);
174 /* preserve the t bit */
179 /* possibly preserve the x bits */
180 if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR;
181 if (!MAP_SYSTEM(conn)) mask |= S_IXGRP;
182 if (!MAP_HIDDEN(conn)) mask |= S_IXOTH;
184 unixmode |= (st->st_mode & mask);
186 /* if we previously had any r bits set then leave them alone */
187 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
188 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
192 /* if we previously had any w bits set then leave them alone
193 if the new mode is not rdonly */
194 if (!IS_DOS_READONLY(dosmode) &&
195 (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
196 unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
200 return(sys_chmod(fname,unixmode));
204 /*******************************************************************
205 Wrapper around sys_utime that possibly allows DOS semantics rather
207 *******************************************************************/
208 int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
210 extern struct current_user current_user;
216 if(sys_utime(fname, times) == 0)
219 if((errno != EPERM) && (errno != EACCES))
222 if(!lp_dos_filetimes(SNUM(conn)))
225 /* We have permission (given by the Samba admin) to
226 break POSIX semantics and allow a user to change
227 the time on a file they don't own but can write to
231 if(sys_stat(fname,&sb) != 0)
234 /* Check if we have write access. */
235 if (CAN_WRITE(conn)) {
236 if (((sb.st_mode & S_IWOTH) ||
238 ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
239 ((sb.st_mode & S_IWGRP) &&
240 in_group(sb.st_gid,current_user.gid,
241 current_user.ngroups,current_user.groups)))) {
242 /* We are allowed to become root and change the filetime. */
244 ret = sys_utime(fname, times);
245 unbecome_root(False);
252 /*******************************************************************
253 Change a filetime - possibly allowing DOS semantics.
254 *******************************************************************/
255 BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
257 struct utimbuf times;
259 if (null_mtime(mtime)) return(True);
261 times.modtime = times.actime = mtime;
263 if (file_utime(conn, fname, ×)) {
264 DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));