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_mask(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_mask(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 (dos_stat(fname,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 whilst adding in the new w bits, if the new mode is not rdonly */
183 if (!IS_DOS_READONLY(dosmode)) {
184 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
187 return(dos_chmod(fname,unixmode));
191 /*******************************************************************
192 Wrapper around dos_utime that possibly allows DOS semantics rather
194 *******************************************************************/
195 int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
197 extern struct current_user current_user;
203 if(dos_utime(fname, times) == 0)
206 if((errno != EPERM) && (errno != EACCES))
209 if(!lp_dos_filetimes(SNUM(conn)))
212 /* We have permission (given by the Samba admin) to
213 break POSIX semantics and allow a user to change
214 the time on a file they don't own but can write to
218 if(dos_stat(fname,&sb) != 0)
221 /* Check if we have write access. */
222 if (CAN_WRITE(conn)) {
223 if (((sb.st_mode & S_IWOTH) ||
225 ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
226 ((sb.st_mode & S_IWGRP) &&
227 in_group(sb.st_gid,current_user.gid,
228 current_user.ngroups,current_user.groups)))) {
229 /* We are allowed to become root and change the filetime. */
231 ret = dos_utime(fname, times);
232 unbecome_root(False);
239 /*******************************************************************
240 Change a filetime - possibly allowing DOS semantics.
241 *******************************************************************/
242 BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
244 struct utimbuf times;
246 if (null_mtime(mtime)) return(True);
248 times.modtime = times.actime = mtime;
250 if (file_utime(conn, fname, ×)) {
251 DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));