xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/intrinsics/chmod.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg /* Implementation of the CHMOD intrinsic.
2*4c3eb207Smrg    Copyright (C) 2006-2020 Free Software Foundation, Inc.
3627f7eb2Smrg    Contributed by François-Xavier Coudert <coudert@clipper.ens.fr>
4627f7eb2Smrg 
5627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6627f7eb2Smrg 
7627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or
8627f7eb2Smrg modify it under the terms of the GNU General Public
9627f7eb2Smrg License as published by the Free Software Foundation; either
10627f7eb2Smrg version 3 of the License, or (at your option) any later version.
11627f7eb2Smrg 
12627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
13627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15627f7eb2Smrg GNU General Public License for more details.
16627f7eb2Smrg 
17627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg 3.1, as published by the Free Software Foundation.
20627f7eb2Smrg 
21627f7eb2Smrg You should have received a copy of the GNU General Public License and
22627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
25627f7eb2Smrg 
26627f7eb2Smrg #include "libgfortran.h"
27627f7eb2Smrg 
28627f7eb2Smrg #if defined(HAVE_SYS_STAT_H)
29627f7eb2Smrg 
30627f7eb2Smrg #include <sys/stat.h>	/* For stat, chmod and umask.  */
31627f7eb2Smrg 
32627f7eb2Smrg 
33627f7eb2Smrg /* INTEGER FUNCTION CHMOD (NAME, MODE)
34627f7eb2Smrg    CHARACTER(len=*), INTENT(IN) :: NAME, MODE
35627f7eb2Smrg 
36627f7eb2Smrg    Sets the file permission "chmod" using a mode string.
37627f7eb2Smrg 
38627f7eb2Smrg    For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those,
39627f7eb2Smrg    only the user attributes are used.
40627f7eb2Smrg 
41627f7eb2Smrg    The mode string allows for the same arguments as POSIX's chmod utility.
42627f7eb2Smrg    a) string containing an octal number.
43627f7eb2Smrg    b) Comma separated list of clauses of the form:
44627f7eb2Smrg       [<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...]
45627f7eb2Smrg       <who> - 'u', 'g', 'o', 'a'
46627f7eb2Smrg       <op>  - '+', '-', '='
47627f7eb2Smrg       <perm> - 'r', 'w', 'x', 'X', 's', t'
48627f7eb2Smrg    If <op> is not followed by a perm-list or permcopy, '-' and '+' do not
49627f7eb2Smrg    change the mode while '=' clears all file mode bits. 'u' stands for the
50627f7eb2Smrg    user permissions, 'g' for the group and 'o' for the permissions for others.
51627f7eb2Smrg    'a' is equivalent to 'ugo'. '+' sets the given permission in addition to
52627f7eb2Smrg    the ones of the file, '-' unsets the given permissions of the file, while
53627f7eb2Smrg    '=' sets the file to that mode. 'r' sets the read, 'w' the write, and
54627f7eb2Smrg    'x' the execute mode. 'X' sets the execute bit if the file is a directory
55627f7eb2Smrg    or if the user, group or other executable bit is set. 't' sets the sticky
56627f7eb2Smrg    bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit.
57627f7eb2Smrg 
58627f7eb2Smrg    Note that if <who> is omitted, the permissions are filtered by the umask.
59627f7eb2Smrg 
60627f7eb2Smrg    A return value of 0 indicates success, -1 an error of chmod() while 1
61627f7eb2Smrg    indicates a mode parsing error.  */
62627f7eb2Smrg 
63627f7eb2Smrg 
64627f7eb2Smrg static int
chmod_internal(char * file,char * mode,gfc_charlen_type mode_len)65627f7eb2Smrg chmod_internal (char *file, char *mode, gfc_charlen_type mode_len)
66627f7eb2Smrg {
67627f7eb2Smrg   bool ugo[3];
68627f7eb2Smrg   bool rwxXstugo[9];
69627f7eb2Smrg   int set_mode, part;
70627f7eb2Smrg   bool honor_umask, continue_clause = false;
71627f7eb2Smrg #ifndef __MINGW32__
72627f7eb2Smrg   bool is_dir;
73627f7eb2Smrg #endif
74627f7eb2Smrg   mode_t mode_mask, file_mode, new_mode;
75627f7eb2Smrg   struct stat stat_buf;
76627f7eb2Smrg 
77627f7eb2Smrg   if (mode_len == 0)
78627f7eb2Smrg     return 1;
79627f7eb2Smrg 
80627f7eb2Smrg   if (mode[0] >= '0' && mode[0] <= '9')
81627f7eb2Smrg     {
82627f7eb2Smrg       unsigned fmode;
83627f7eb2Smrg       if (sscanf (mode, "%o", &fmode) != 1)
84627f7eb2Smrg 	return 1;
85627f7eb2Smrg       return chmod (file, (mode_t) fmode);
86627f7eb2Smrg     }
87627f7eb2Smrg 
88627f7eb2Smrg   /* Read the current file mode. */
89627f7eb2Smrg   if (stat (file, &stat_buf))
90627f7eb2Smrg     return 1;
91627f7eb2Smrg 
92627f7eb2Smrg   file_mode = stat_buf.st_mode & ~S_IFMT;
93627f7eb2Smrg #ifndef __MINGW32__
94627f7eb2Smrg   is_dir = stat_buf.st_mode & S_IFDIR;
95627f7eb2Smrg #endif
96627f7eb2Smrg 
97627f7eb2Smrg #ifdef HAVE_UMASK
98627f7eb2Smrg   /* Obtain the umask without distroying the setting.  */
99627f7eb2Smrg   mode_mask = 0;
100627f7eb2Smrg   mode_mask = umask (mode_mask);
101627f7eb2Smrg   (void) umask (mode_mask);
102627f7eb2Smrg #else
103627f7eb2Smrg   honor_umask = false;
104627f7eb2Smrg #endif
105627f7eb2Smrg 
106627f7eb2Smrg   for (gfc_charlen_type i = 0; i < mode_len; i++)
107627f7eb2Smrg     {
108627f7eb2Smrg       if (!continue_clause)
109627f7eb2Smrg 	{
110627f7eb2Smrg 	  ugo[0] = false;
111627f7eb2Smrg 	  ugo[1] = false;
112627f7eb2Smrg 	  ugo[2] = false;
113627f7eb2Smrg #ifdef HAVE_UMASK
114627f7eb2Smrg 	  honor_umask = true;
115627f7eb2Smrg #endif
116627f7eb2Smrg 	}
117627f7eb2Smrg       continue_clause = false;
118627f7eb2Smrg       rwxXstugo[0] = false;
119627f7eb2Smrg       rwxXstugo[1] = false;
120627f7eb2Smrg       rwxXstugo[2] = false;
121627f7eb2Smrg       rwxXstugo[3] = false;
122627f7eb2Smrg       rwxXstugo[4] = false;
123627f7eb2Smrg       rwxXstugo[5] = false;
124627f7eb2Smrg       rwxXstugo[6] = false;
125627f7eb2Smrg       rwxXstugo[7] = false;
126627f7eb2Smrg       rwxXstugo[8] = false;
127627f7eb2Smrg       part = 0;
128627f7eb2Smrg       set_mode = -1;
129627f7eb2Smrg       for (; i < mode_len; i++)
130627f7eb2Smrg 	{
131627f7eb2Smrg 	  switch (mode[i])
132627f7eb2Smrg 	    {
133627f7eb2Smrg 	    /* User setting: a[ll]/u[ser]/g[roup]/o[ther].  */
134627f7eb2Smrg 	    case 'a':
135627f7eb2Smrg 	      if (part > 1)
136627f7eb2Smrg 		return 1;
137627f7eb2Smrg 	      ugo[0] = true;
138627f7eb2Smrg 	      ugo[1] = true;
139627f7eb2Smrg 	      ugo[2] = true;
140627f7eb2Smrg 	      part = 1;
141627f7eb2Smrg #ifdef HAVE_UMASK
142627f7eb2Smrg 	      honor_umask = false;
143627f7eb2Smrg #endif
144627f7eb2Smrg 	      break;
145627f7eb2Smrg 	    case 'u':
146627f7eb2Smrg 	      if (part == 2)
147627f7eb2Smrg 		{
148627f7eb2Smrg 		  rwxXstugo[6] = true;
149627f7eb2Smrg 		  part = 4;
150627f7eb2Smrg 		  break;
151627f7eb2Smrg 		}
152627f7eb2Smrg 	      if (part > 1)
153627f7eb2Smrg 		return 1;
154627f7eb2Smrg 	      ugo[0] = true;
155627f7eb2Smrg 	      part = 1;
156627f7eb2Smrg #ifdef HAVE_UMASK
157627f7eb2Smrg 	      honor_umask = false;
158627f7eb2Smrg #endif
159627f7eb2Smrg 	      break;
160627f7eb2Smrg 	    case 'g':
161627f7eb2Smrg 	      if (part == 2)
162627f7eb2Smrg 		{
163627f7eb2Smrg 		  rwxXstugo[7] = true;
164627f7eb2Smrg 		  part = 4;
165627f7eb2Smrg 		  break;
166627f7eb2Smrg 		}
167627f7eb2Smrg 	      if (part > 1)
168627f7eb2Smrg 		return 1;
169627f7eb2Smrg        	      ugo[1] = true;
170627f7eb2Smrg 	      part = 1;
171627f7eb2Smrg #ifdef HAVE_UMASK
172627f7eb2Smrg 	      honor_umask = false;
173627f7eb2Smrg #endif
174627f7eb2Smrg 	      break;
175627f7eb2Smrg 	    case 'o':
176627f7eb2Smrg 	      if (part == 2)
177627f7eb2Smrg 		{
178627f7eb2Smrg 		  rwxXstugo[8] = true;
179627f7eb2Smrg 		  part = 4;
180627f7eb2Smrg 		  break;
181627f7eb2Smrg 		}
182627f7eb2Smrg 	      if (part > 1)
183627f7eb2Smrg 		return 1;
184627f7eb2Smrg 	      ugo[2] = true;
185627f7eb2Smrg 	      part = 1;
186627f7eb2Smrg #ifdef HAVE_UMASK
187627f7eb2Smrg 	      honor_umask = false;
188627f7eb2Smrg #endif
189627f7eb2Smrg 	      break;
190627f7eb2Smrg 
191627f7eb2Smrg 	    /* Mode setting: =+-.  */
192627f7eb2Smrg 	    case '=':
193627f7eb2Smrg 	      if (part > 2)
194627f7eb2Smrg 		{
195627f7eb2Smrg 		  continue_clause = true;
196627f7eb2Smrg 		  i--;
197627f7eb2Smrg 		  part = 2;
198627f7eb2Smrg 		  goto clause_done;
199627f7eb2Smrg 		}
200627f7eb2Smrg 	      set_mode = 1;
201627f7eb2Smrg 	      part = 2;
202627f7eb2Smrg 	      break;
203627f7eb2Smrg 
204627f7eb2Smrg 	    case '-':
205627f7eb2Smrg 	      if (part > 2)
206627f7eb2Smrg 		{
207627f7eb2Smrg 		  continue_clause = true;
208627f7eb2Smrg 		  i--;
209627f7eb2Smrg 		  part = 2;
210627f7eb2Smrg 		  goto clause_done;
211627f7eb2Smrg 		}
212627f7eb2Smrg 	      set_mode = 2;
213627f7eb2Smrg 	      part = 2;
214627f7eb2Smrg 	      break;
215627f7eb2Smrg 
216627f7eb2Smrg 	    case '+':
217627f7eb2Smrg 	      if (part > 2)
218627f7eb2Smrg 		{
219627f7eb2Smrg 		  continue_clause = true;
220627f7eb2Smrg 		  i--;
221627f7eb2Smrg 		  part = 2;
222627f7eb2Smrg 		  goto clause_done;
223627f7eb2Smrg 		}
224627f7eb2Smrg 	      set_mode = 3;
225627f7eb2Smrg 	      part = 2;
226627f7eb2Smrg 	      break;
227627f7eb2Smrg 
228627f7eb2Smrg 	    /* Permissions: rwxXst - for ugo see above.  */
229627f7eb2Smrg 	    case 'r':
230627f7eb2Smrg 	      if (part != 2 && part != 3)
231627f7eb2Smrg 		return 1;
232627f7eb2Smrg 	      rwxXstugo[0] = true;
233627f7eb2Smrg 	      part = 3;
234627f7eb2Smrg 	      break;
235627f7eb2Smrg 
236627f7eb2Smrg 	    case 'w':
237627f7eb2Smrg 	      if (part != 2 && part != 3)
238627f7eb2Smrg 		return 1;
239627f7eb2Smrg 	      rwxXstugo[1] = true;
240627f7eb2Smrg 	      part = 3;
241627f7eb2Smrg 	      break;
242627f7eb2Smrg 
243627f7eb2Smrg 	    case 'x':
244627f7eb2Smrg 	      if (part != 2 && part != 3)
245627f7eb2Smrg 		return 1;
246627f7eb2Smrg 	      rwxXstugo[2] = true;
247627f7eb2Smrg 	      part = 3;
248627f7eb2Smrg 	      break;
249627f7eb2Smrg 
250627f7eb2Smrg 	    case 'X':
251627f7eb2Smrg 	      if (part != 2 && part != 3)
252627f7eb2Smrg 		return 1;
253627f7eb2Smrg 	      rwxXstugo[3] = true;
254627f7eb2Smrg 	      part = 3;
255627f7eb2Smrg 	      break;
256627f7eb2Smrg 
257627f7eb2Smrg 	    case 's':
258627f7eb2Smrg 	      if (part != 2 && part != 3)
259627f7eb2Smrg 		return 1;
260627f7eb2Smrg 	      rwxXstugo[4] = true;
261627f7eb2Smrg 	      part = 3;
262627f7eb2Smrg 	      break;
263627f7eb2Smrg 
264627f7eb2Smrg 	    case 't':
265627f7eb2Smrg 	      if (part != 2 && part != 3)
266627f7eb2Smrg 		return 1;
267627f7eb2Smrg 	      rwxXstugo[5] = true;
268627f7eb2Smrg 	      part = 3;
269627f7eb2Smrg 	      break;
270627f7eb2Smrg 
271627f7eb2Smrg 	    /* Tailing blanks are valid in Fortran.  */
272627f7eb2Smrg 	    case ' ':
273627f7eb2Smrg 	      for (i++; i < mode_len; i++)
274627f7eb2Smrg 		if (mode[i] != ' ')
275627f7eb2Smrg 		  break;
276627f7eb2Smrg 	      if (i != mode_len)
277627f7eb2Smrg 		return 1;
278627f7eb2Smrg 	      goto clause_done;
279627f7eb2Smrg 
280627f7eb2Smrg 	    case ',':
281627f7eb2Smrg 	      goto clause_done;
282627f7eb2Smrg 
283627f7eb2Smrg 	    default:
284627f7eb2Smrg 	      return 1;
285627f7eb2Smrg 	    }
286627f7eb2Smrg 	}
287627f7eb2Smrg 
288627f7eb2Smrg clause_done:
289627f7eb2Smrg       if (part < 2)
290627f7eb2Smrg 	return 1;
291627f7eb2Smrg 
292627f7eb2Smrg       new_mode = 0;
293627f7eb2Smrg 
294627f7eb2Smrg #ifdef __MINGW32__
295627f7eb2Smrg 
296627f7eb2Smrg       /* Read. */
297627f7eb2Smrg       if (rwxXstugo[0] && (ugo[0] || honor_umask))
298627f7eb2Smrg 	new_mode |= _S_IREAD;
299627f7eb2Smrg 
300627f7eb2Smrg       /* Write. */
301627f7eb2Smrg       if (rwxXstugo[1] && (ugo[0] || honor_umask))
302627f7eb2Smrg 	new_mode |= _S_IWRITE;
303627f7eb2Smrg 
304627f7eb2Smrg #else
305627f7eb2Smrg 
306627f7eb2Smrg       /* Read. */
307627f7eb2Smrg       if (rwxXstugo[0])
308627f7eb2Smrg 	{
309627f7eb2Smrg 	  if (ugo[0] || honor_umask)
310627f7eb2Smrg 	    new_mode |= S_IRUSR;
311627f7eb2Smrg 	  if (ugo[1] || honor_umask)
312627f7eb2Smrg 	    new_mode |= S_IRGRP;
313627f7eb2Smrg 	  if (ugo[2] || honor_umask)
314627f7eb2Smrg 	    new_mode |= S_IROTH;
315627f7eb2Smrg 	}
316627f7eb2Smrg 
317627f7eb2Smrg       /* Write.  */
318627f7eb2Smrg       if (rwxXstugo[1])
319627f7eb2Smrg 	{
320627f7eb2Smrg 	  if (ugo[0] || honor_umask)
321627f7eb2Smrg 	    new_mode |= S_IWUSR;
322627f7eb2Smrg 	  if (ugo[1] || honor_umask)
323627f7eb2Smrg 	    new_mode |= S_IWGRP;
324627f7eb2Smrg 	  if (ugo[2] || honor_umask)
325627f7eb2Smrg 	    new_mode |= S_IWOTH;
326627f7eb2Smrg 	}
327627f7eb2Smrg 
328627f7eb2Smrg       /* Execute. */
329627f7eb2Smrg       if (rwxXstugo[2])
330627f7eb2Smrg 	{
331627f7eb2Smrg 	  if (ugo[0] || honor_umask)
332627f7eb2Smrg 	    new_mode |= S_IXUSR;
333627f7eb2Smrg 	  if (ugo[1] || honor_umask)
334627f7eb2Smrg 	    new_mode |= S_IXGRP;
335627f7eb2Smrg 	  if (ugo[2] || honor_umask)
336627f7eb2Smrg 	    new_mode |= S_IXOTH;
337627f7eb2Smrg 	}
338627f7eb2Smrg 
339627f7eb2Smrg       /* 'X' execute.  */
340627f7eb2Smrg       if (rwxXstugo[3]
341627f7eb2Smrg 	  && (is_dir || (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
342627f7eb2Smrg 	new_mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
343627f7eb2Smrg 
344627f7eb2Smrg       /* 's'.  */
345627f7eb2Smrg       if (rwxXstugo[4])
346627f7eb2Smrg 	{
347627f7eb2Smrg 	  if (ugo[0] || honor_umask)
348627f7eb2Smrg 	    new_mode |= S_ISUID;
349627f7eb2Smrg 	  if (ugo[1] || honor_umask)
350627f7eb2Smrg 	    new_mode |= S_ISGID;
351627f7eb2Smrg 	}
352627f7eb2Smrg 
353627f7eb2Smrg       /* As original 'u'.  */
354627f7eb2Smrg       if (rwxXstugo[6])
355627f7eb2Smrg 	{
356627f7eb2Smrg 	  if (ugo[1] || honor_umask)
357627f7eb2Smrg 	    {
358627f7eb2Smrg 	      if (file_mode & S_IRUSR)
359627f7eb2Smrg 		new_mode |= S_IRGRP;
360627f7eb2Smrg 	      if (file_mode & S_IWUSR)
361627f7eb2Smrg 		new_mode |= S_IWGRP;
362627f7eb2Smrg 	      if (file_mode & S_IXUSR)
363627f7eb2Smrg 		new_mode |= S_IXGRP;
364627f7eb2Smrg 	    }
365627f7eb2Smrg 	  if (ugo[2] || honor_umask)
366627f7eb2Smrg 	    {
367627f7eb2Smrg 	      if (file_mode & S_IRUSR)
368627f7eb2Smrg 		new_mode |= S_IROTH;
369627f7eb2Smrg 	      if (file_mode & S_IWUSR)
370627f7eb2Smrg 		new_mode |= S_IWOTH;
371627f7eb2Smrg 	      if (file_mode & S_IXUSR)
372627f7eb2Smrg 		new_mode |= S_IXOTH;
373627f7eb2Smrg 	    }
374627f7eb2Smrg 	}
375627f7eb2Smrg 
376627f7eb2Smrg       /* As original 'g'.  */
377627f7eb2Smrg       if (rwxXstugo[7])
378627f7eb2Smrg 	{
379627f7eb2Smrg 	  if (ugo[0] || honor_umask)
380627f7eb2Smrg 	    {
381627f7eb2Smrg 	      if (file_mode & S_IRGRP)
382627f7eb2Smrg 		new_mode |= S_IRUSR;
383627f7eb2Smrg 	      if (file_mode & S_IWGRP)
384627f7eb2Smrg 		new_mode |= S_IWUSR;
385627f7eb2Smrg 	      if (file_mode & S_IXGRP)
386627f7eb2Smrg 		new_mode |= S_IXUSR;
387627f7eb2Smrg 	    }
388627f7eb2Smrg 	  if (ugo[2] || honor_umask)
389627f7eb2Smrg 	    {
390627f7eb2Smrg 	      if (file_mode & S_IRGRP)
391627f7eb2Smrg 		new_mode |= S_IROTH;
392627f7eb2Smrg 	      if (file_mode & S_IWGRP)
393627f7eb2Smrg 		new_mode |= S_IWOTH;
394627f7eb2Smrg 	      if (file_mode & S_IXGRP)
395627f7eb2Smrg 		new_mode |= S_IXOTH;
396627f7eb2Smrg 	    }
397627f7eb2Smrg 	}
398627f7eb2Smrg 
399627f7eb2Smrg       /* As original 'o'.  */
400627f7eb2Smrg       if (rwxXstugo[8])
401627f7eb2Smrg 	{
402627f7eb2Smrg 	  if (ugo[0] || honor_umask)
403627f7eb2Smrg 	    {
404627f7eb2Smrg 	      if (file_mode & S_IROTH)
405627f7eb2Smrg 		new_mode |= S_IRUSR;
406627f7eb2Smrg 	      if (file_mode & S_IWOTH)
407627f7eb2Smrg 		new_mode |= S_IWUSR;
408627f7eb2Smrg 	      if (file_mode & S_IXOTH)
409627f7eb2Smrg 		new_mode |= S_IXUSR;
410627f7eb2Smrg 	    }
411627f7eb2Smrg 	  if (ugo[1] || honor_umask)
412627f7eb2Smrg 	    {
413627f7eb2Smrg 	      if (file_mode & S_IROTH)
414627f7eb2Smrg 		new_mode |= S_IRGRP;
415627f7eb2Smrg 	      if (file_mode & S_IWOTH)
416627f7eb2Smrg 		new_mode |= S_IWGRP;
417627f7eb2Smrg 	      if (file_mode & S_IXOTH)
418627f7eb2Smrg 		new_mode |= S_IXGRP;
419627f7eb2Smrg 	    }
420627f7eb2Smrg 	}
421627f7eb2Smrg #endif  /* __MINGW32__ */
422627f7eb2Smrg 
423627f7eb2Smrg #ifdef HAVE_UMASK
424627f7eb2Smrg     if (honor_umask)
425627f7eb2Smrg       new_mode &= ~mode_mask;
426627f7eb2Smrg #endif
427627f7eb2Smrg 
428627f7eb2Smrg     if (set_mode == 1)
429627f7eb2Smrg       {
430627f7eb2Smrg #ifdef __MINGW32__
431627f7eb2Smrg 	if (ugo[0] || honor_umask)
432627f7eb2Smrg 	  file_mode = (file_mode & ~(_S_IWRITE | _S_IREAD))
433627f7eb2Smrg 		      | (new_mode & (_S_IWRITE | _S_IREAD));
434627f7eb2Smrg #else
435627f7eb2Smrg 	/* Set '='.  */
436627f7eb2Smrg 	if ((ugo[0] || honor_umask) && !rwxXstugo[6])
437627f7eb2Smrg 	  file_mode = (file_mode & ~(S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR))
438627f7eb2Smrg 		      | (new_mode & (S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR));
439627f7eb2Smrg 	if ((ugo[1] || honor_umask) && !rwxXstugo[7])
440627f7eb2Smrg 	  file_mode = (file_mode & ~(S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP))
441627f7eb2Smrg 		      | (new_mode & (S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP));
442627f7eb2Smrg 	if ((ugo[2] || honor_umask) && !rwxXstugo[8])
443627f7eb2Smrg 	  file_mode = (file_mode & ~(S_IROTH | S_IWOTH | S_IXOTH))
444627f7eb2Smrg 		      | (new_mode & (S_IROTH | S_IWOTH | S_IXOTH));
445627f7eb2Smrg #ifndef __VXWORKS__
446627f7eb2Smrg 	if (is_dir && rwxXstugo[5])
447627f7eb2Smrg 	  file_mode |= S_ISVTX;
448627f7eb2Smrg 	else if (!is_dir)
449627f7eb2Smrg 	  file_mode &= ~S_ISVTX;
450627f7eb2Smrg #endif
451627f7eb2Smrg #endif
452627f7eb2Smrg       }
453627f7eb2Smrg     else if (set_mode == 2)
454627f7eb2Smrg       {
455627f7eb2Smrg 	/* Clear '-'.  */
456627f7eb2Smrg 	file_mode &= ~new_mode;
457627f7eb2Smrg #if !defined( __MINGW32__) && !defined (__VXWORKS__)
458627f7eb2Smrg 	if (rwxXstugo[5] || !is_dir)
459627f7eb2Smrg 	  file_mode &= ~S_ISVTX;
460627f7eb2Smrg #endif
461627f7eb2Smrg       }
462627f7eb2Smrg     else if (set_mode == 3)
463627f7eb2Smrg       {
464627f7eb2Smrg 	file_mode |= new_mode;
465627f7eb2Smrg #if !defined (__MINGW32__) && !defined (__VXWORKS__)
466627f7eb2Smrg 	if (rwxXstugo[5] && is_dir)
467627f7eb2Smrg 	  file_mode |= S_ISVTX;
468627f7eb2Smrg 	else if (!is_dir)
469627f7eb2Smrg 	  file_mode &= ~S_ISVTX;
470627f7eb2Smrg #endif
471627f7eb2Smrg       }
472627f7eb2Smrg   }
473627f7eb2Smrg 
474627f7eb2Smrg   return chmod (file, file_mode);
475627f7eb2Smrg }
476627f7eb2Smrg 
477627f7eb2Smrg 
478627f7eb2Smrg extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type);
479627f7eb2Smrg export_proto(chmod_func);
480627f7eb2Smrg 
481627f7eb2Smrg int
chmod_func(char * name,char * mode,gfc_charlen_type name_len,gfc_charlen_type mode_len)482627f7eb2Smrg chmod_func (char *name, char *mode, gfc_charlen_type name_len,
483627f7eb2Smrg 	    gfc_charlen_type mode_len)
484627f7eb2Smrg {
485627f7eb2Smrg   char *cname = fc_strdup (name, name_len);
486627f7eb2Smrg   int ret = chmod_internal (cname, mode, mode_len);
487627f7eb2Smrg   free (cname);
488627f7eb2Smrg   return ret;
489627f7eb2Smrg }
490627f7eb2Smrg 
491627f7eb2Smrg 
492627f7eb2Smrg extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4 *,
493627f7eb2Smrg 			  gfc_charlen_type, gfc_charlen_type);
494627f7eb2Smrg export_proto(chmod_i4_sub);
495627f7eb2Smrg 
496627f7eb2Smrg void
chmod_i4_sub(char * name,char * mode,GFC_INTEGER_4 * status,gfc_charlen_type name_len,gfc_charlen_type mode_len)497627f7eb2Smrg chmod_i4_sub (char *name, char *mode, GFC_INTEGER_4 * status,
498627f7eb2Smrg 	      gfc_charlen_type name_len, gfc_charlen_type mode_len)
499627f7eb2Smrg {
500627f7eb2Smrg   int val;
501627f7eb2Smrg 
502627f7eb2Smrg   val = chmod_func (name, mode, name_len, mode_len);
503627f7eb2Smrg   if (status)
504627f7eb2Smrg     *status = val;
505627f7eb2Smrg }
506627f7eb2Smrg 
507627f7eb2Smrg 
508627f7eb2Smrg extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8 *,
509627f7eb2Smrg 			  gfc_charlen_type, gfc_charlen_type);
510627f7eb2Smrg export_proto(chmod_i8_sub);
511627f7eb2Smrg 
512627f7eb2Smrg void
chmod_i8_sub(char * name,char * mode,GFC_INTEGER_8 * status,gfc_charlen_type name_len,gfc_charlen_type mode_len)513627f7eb2Smrg chmod_i8_sub (char *name, char *mode, GFC_INTEGER_8 * status,
514627f7eb2Smrg 	      gfc_charlen_type name_len, gfc_charlen_type mode_len)
515627f7eb2Smrg {
516627f7eb2Smrg   int val;
517627f7eb2Smrg 
518627f7eb2Smrg   val = chmod_func (name, mode, name_len, mode_len);
519627f7eb2Smrg   if (status)
520627f7eb2Smrg     *status = val;
521627f7eb2Smrg }
522627f7eb2Smrg 
523627f7eb2Smrg #endif
524