1 /* Implementation of the CHMOD intrinsic.
2 Copyright (C) 2006-2018 Free Software Foundation, Inc.
3 Contributed by François-Xavier Coudert <coudert@clipper.ens.fr>
5 This file is part of the GNU Fortran runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
12 Libgfortran 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 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "libgfortran.h"
28 #if defined(HAVE_SYS_STAT_H)
30 #include <sys/stat.h> /* For stat, chmod and umask. */
33 /* INTEGER FUNCTION CHMOD (NAME, MODE)
34 CHARACTER(len=*), INTENT(IN) :: NAME, MODE
36 Sets the file permission "chmod" using a mode string.
38 For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those,
39 only the user attributes are used.
41 The mode string allows for the same arguments as POSIX's chmod utility.
42 a) string containing an octal number.
43 b) Comma separated list of clauses of the form:
44 [<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...]
45 <who> - 'u', 'g', 'o', 'a'
47 <perm> - 'r', 'w', 'x', 'X', 's', t'
48 If <op> is not followed by a perm-list or permcopy, '-' and '+' do not
49 change the mode while '=' clears all file mode bits. 'u' stands for the
50 user permissions, 'g' for the group and 'o' for the permissions for others.
51 'a' is equivalent to 'ugo'. '+' sets the given permission in addition to
52 the ones of the file, '-' unsets the given permissions of the file, while
53 '=' sets the file to that mode. 'r' sets the read, 'w' the write, and
54 'x' the execute mode. 'X' sets the execute bit if the file is a directory
55 or if the user, group or other executable bit is set. 't' sets the sticky
56 bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit.
58 Note that if <who> is omitted, the permissions are filtered by the umask.
60 A return value of 0 indicates success, -1 an error of chmod() while 1
61 indicates a mode parsing error. */
65 chmod_internal (char *file
, char *mode
, gfc_charlen_type mode_len
)
70 bool honor_umask
, continue_clause
= false;
74 mode_t mode_mask
, file_mode
, new_mode
;
80 if (mode
[0] >= '0' && mode
[0] <= '9')
83 if (sscanf (mode
, "%o", &fmode
) != 1)
85 return chmod (file
, (mode_t
) fmode
);
88 /* Read the current file mode. */
89 if (stat (file
, &stat_buf
))
92 file_mode
= stat_buf
.st_mode
& ~S_IFMT
;
94 is_dir
= stat_buf
.st_mode
& S_IFDIR
;
98 /* Obtain the umask without distroying the setting. */
100 mode_mask
= umask (mode_mask
);
101 (void) umask (mode_mask
);
106 for (gfc_charlen_type i
= 0; i
< mode_len
; i
++)
108 if (!continue_clause
)
117 continue_clause
= false;
118 rwxXstugo
[0] = false;
119 rwxXstugo
[1] = false;
120 rwxXstugo
[2] = false;
121 rwxXstugo
[3] = false;
122 rwxXstugo
[4] = false;
123 rwxXstugo
[5] = false;
124 rwxXstugo
[6] = false;
125 rwxXstugo
[7] = false;
126 rwxXstugo
[8] = false;
129 for (; i
< mode_len
; i
++)
133 /* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */
191 /* Mode setting: =+-. */
195 continue_clause
= true;
207 continue_clause
= true;
219 continue_clause
= true;
228 /* Permissions: rwxXst - for ugo see above. */
230 if (part
!= 2 && part
!= 3)
237 if (part
!= 2 && part
!= 3)
244 if (part
!= 2 && part
!= 3)
251 if (part
!= 2 && part
!= 3)
258 if (part
!= 2 && part
!= 3)
265 if (part
!= 2 && part
!= 3)
271 /* Tailing blanks are valid in Fortran. */
273 for (i
++; i
< mode_len
; i
++)
297 if (rwxXstugo
[0] && (ugo
[0] || honor_umask
))
298 new_mode
|= _S_IREAD
;
301 if (rwxXstugo
[1] && (ugo
[0] || honor_umask
))
302 new_mode
|= _S_IWRITE
;
309 if (ugo
[0] || honor_umask
)
311 if (ugo
[1] || honor_umask
)
313 if (ugo
[2] || honor_umask
)
320 if (ugo
[0] || honor_umask
)
322 if (ugo
[1] || honor_umask
)
324 if (ugo
[2] || honor_umask
)
331 if (ugo
[0] || honor_umask
)
333 if (ugo
[1] || honor_umask
)
335 if (ugo
[2] || honor_umask
)
341 && (is_dir
|| (file_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))))
342 new_mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
347 if (ugo
[0] || honor_umask
)
349 if (ugo
[1] || honor_umask
)
353 /* As original 'u'. */
356 if (ugo
[1] || honor_umask
)
358 if (file_mode
& S_IRUSR
)
360 if (file_mode
& S_IWUSR
)
362 if (file_mode
& S_IXUSR
)
365 if (ugo
[2] || honor_umask
)
367 if (file_mode
& S_IRUSR
)
369 if (file_mode
& S_IWUSR
)
371 if (file_mode
& S_IXUSR
)
376 /* As original 'g'. */
379 if (ugo
[0] || honor_umask
)
381 if (file_mode
& S_IRGRP
)
383 if (file_mode
& S_IWGRP
)
385 if (file_mode
& S_IXGRP
)
388 if (ugo
[2] || honor_umask
)
390 if (file_mode
& S_IRGRP
)
392 if (file_mode
& S_IWGRP
)
394 if (file_mode
& S_IXGRP
)
399 /* As original 'o'. */
402 if (ugo
[0] || honor_umask
)
404 if (file_mode
& S_IROTH
)
406 if (file_mode
& S_IWOTH
)
408 if (file_mode
& S_IXOTH
)
411 if (ugo
[1] || honor_umask
)
413 if (file_mode
& S_IROTH
)
415 if (file_mode
& S_IWOTH
)
417 if (file_mode
& S_IXOTH
)
421 #endif /* __MINGW32__ */
425 new_mode
&= ~mode_mask
;
431 if (ugo
[0] || honor_umask
)
432 file_mode
= (file_mode
& ~(_S_IWRITE
| _S_IREAD
))
433 | (new_mode
& (_S_IWRITE
| _S_IREAD
));
436 if ((ugo
[0] || honor_umask
) && !rwxXstugo
[6])
437 file_mode
= (file_mode
& ~(S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
))
438 | (new_mode
& (S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
));
439 if ((ugo
[1] || honor_umask
) && !rwxXstugo
[7])
440 file_mode
= (file_mode
& ~(S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
))
441 | (new_mode
& (S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
));
442 if ((ugo
[2] || honor_umask
) && !rwxXstugo
[8])
443 file_mode
= (file_mode
& ~(S_IROTH
| S_IWOTH
| S_IXOTH
))
444 | (new_mode
& (S_IROTH
| S_IWOTH
| S_IXOTH
));
446 if (is_dir
&& rwxXstugo
[5])
447 file_mode
|= S_ISVTX
;
449 file_mode
&= ~S_ISVTX
;
453 else if (set_mode
== 2)
456 file_mode
&= ~new_mode
;
457 #if !defined( __MINGW32__) && !defined (__VXWORKS__)
458 if (rwxXstugo
[5] || !is_dir
)
459 file_mode
&= ~S_ISVTX
;
462 else if (set_mode
== 3)
464 file_mode
|= new_mode
;
465 #if !defined (__MINGW32__) && !defined (__VXWORKS__)
466 if (rwxXstugo
[5] && is_dir
)
467 file_mode
|= S_ISVTX
;
469 file_mode
&= ~S_ISVTX
;
474 return chmod (file
, file_mode
);
478 extern int chmod_func (char *, char *, gfc_charlen_type
, gfc_charlen_type
);
479 export_proto(chmod_func
);
482 chmod_func (char *name
, char *mode
, gfc_charlen_type name_len
,
483 gfc_charlen_type mode_len
)
485 char *cname
= fc_strdup (name
, name_len
);
486 int ret
= chmod_internal (cname
, mode
, mode_len
);
492 extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4
*,
493 gfc_charlen_type
, gfc_charlen_type
);
494 export_proto(chmod_i4_sub
);
497 chmod_i4_sub (char *name
, char *mode
, GFC_INTEGER_4
* status
,
498 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
502 val
= chmod_func (name
, mode
, name_len
, mode_len
);
508 extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8
*,
509 gfc_charlen_type
, gfc_charlen_type
);
510 export_proto(chmod_i8_sub
);
513 chmod_i8_sub (char *name
, char *mode
, GFC_INTEGER_8
* status
,
514 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
518 val
= chmod_func (name
, mode
, name_len
, mode_len
);