1 /* Implementation of the CHMOD intrinsic.
2 Copyright (C) 2006-2017 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
)
71 bool honor_umask
, continue_clause
= false;
75 mode_t mode_mask
, file_mode
, new_mode
;
81 if (mode
[0] >= '0' && mode
[0] <= '9')
84 if (sscanf (mode
, "%o", &fmode
) != 1)
86 return chmod (file
, (mode_t
) fmode
);
89 /* Read the current file mode. */
90 if (stat (file
, &stat_buf
))
93 file_mode
= stat_buf
.st_mode
& ~S_IFMT
;
95 is_dir
= stat_buf
.st_mode
& S_IFDIR
;
99 /* Obtain the umask without distroying the setting. */
101 mode_mask
= umask (mode_mask
);
102 (void) umask (mode_mask
);
107 for (i
= 0; i
< mode_len
; i
++)
109 if (!continue_clause
)
118 continue_clause
= false;
119 rwxXstugo
[0] = false;
120 rwxXstugo
[1] = false;
121 rwxXstugo
[2] = false;
122 rwxXstugo
[3] = false;
123 rwxXstugo
[4] = false;
124 rwxXstugo
[5] = false;
125 rwxXstugo
[6] = false;
126 rwxXstugo
[7] = false;
127 rwxXstugo
[8] = false;
130 for (; i
< mode_len
; i
++)
134 /* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */
192 /* Mode setting: =+-. */
196 continue_clause
= true;
208 continue_clause
= true;
220 continue_clause
= true;
229 /* Permissions: rwxXst - for ugo see above. */
231 if (part
!= 2 && part
!= 3)
238 if (part
!= 2 && part
!= 3)
245 if (part
!= 2 && part
!= 3)
252 if (part
!= 2 && part
!= 3)
259 if (part
!= 2 && part
!= 3)
266 if (part
!= 2 && part
!= 3)
272 /* Tailing blanks are valid in Fortran. */
274 for (i
++; i
< mode_len
; i
++)
298 if (rwxXstugo
[0] && (ugo
[0] || honor_umask
))
299 new_mode
|= _S_IREAD
;
302 if (rwxXstugo
[1] && (ugo
[0] || honor_umask
))
303 new_mode
|= _S_IWRITE
;
310 if (ugo
[0] || honor_umask
)
312 if (ugo
[1] || honor_umask
)
314 if (ugo
[2] || honor_umask
)
321 if (ugo
[0] || honor_umask
)
323 if (ugo
[1] || honor_umask
)
325 if (ugo
[2] || honor_umask
)
332 if (ugo
[0] || honor_umask
)
334 if (ugo
[1] || honor_umask
)
336 if (ugo
[2] || honor_umask
)
342 && (is_dir
|| (file_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))))
343 new_mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
348 if (ugo
[0] || honor_umask
)
350 if (ugo
[1] || honor_umask
)
354 /* As original 'u'. */
357 if (ugo
[1] || honor_umask
)
359 if (file_mode
& S_IRUSR
)
361 if (file_mode
& S_IWUSR
)
363 if (file_mode
& S_IXUSR
)
366 if (ugo
[2] || honor_umask
)
368 if (file_mode
& S_IRUSR
)
370 if (file_mode
& S_IWUSR
)
372 if (file_mode
& S_IXUSR
)
377 /* As original 'g'. */
380 if (ugo
[0] || honor_umask
)
382 if (file_mode
& S_IRGRP
)
384 if (file_mode
& S_IWGRP
)
386 if (file_mode
& S_IXGRP
)
389 if (ugo
[2] || honor_umask
)
391 if (file_mode
& S_IRGRP
)
393 if (file_mode
& S_IWGRP
)
395 if (file_mode
& S_IXGRP
)
400 /* As original 'o'. */
403 if (ugo
[0] || honor_umask
)
405 if (file_mode
& S_IROTH
)
407 if (file_mode
& S_IWOTH
)
409 if (file_mode
& S_IXOTH
)
412 if (ugo
[1] || honor_umask
)
414 if (file_mode
& S_IROTH
)
416 if (file_mode
& S_IWOTH
)
418 if (file_mode
& S_IXOTH
)
422 #endif /* __MINGW32__ */
426 new_mode
&= ~mode_mask
;
432 if (ugo
[0] || honor_umask
)
433 file_mode
= (file_mode
& ~(_S_IWRITE
| _S_IREAD
))
434 | (new_mode
& (_S_IWRITE
| _S_IREAD
));
437 if ((ugo
[0] || honor_umask
) && !rwxXstugo
[6])
438 file_mode
= (file_mode
& ~(S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
))
439 | (new_mode
& (S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
));
440 if ((ugo
[1] || honor_umask
) && !rwxXstugo
[7])
441 file_mode
= (file_mode
& ~(S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
))
442 | (new_mode
& (S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
));
443 if ((ugo
[2] || honor_umask
) && !rwxXstugo
[8])
444 file_mode
= (file_mode
& ~(S_IROTH
| S_IWOTH
| S_IXOTH
))
445 | (new_mode
& (S_IROTH
| S_IWOTH
| S_IXOTH
));
447 if (is_dir
&& rwxXstugo
[5])
448 file_mode
|= S_ISVTX
;
450 file_mode
&= ~S_ISVTX
;
454 else if (set_mode
== 2)
457 file_mode
&= ~new_mode
;
458 #if !defined( __MINGW32__) && !defined (__VXWORKS__)
459 if (rwxXstugo
[5] || !is_dir
)
460 file_mode
&= ~S_ISVTX
;
463 else if (set_mode
== 3)
465 file_mode
|= new_mode
;
466 #if !defined (__MINGW32__) && !defined (__VXWORKS__)
467 if (rwxXstugo
[5] && is_dir
)
468 file_mode
|= S_ISVTX
;
470 file_mode
&= ~S_ISVTX
;
475 return chmod (file
, file_mode
);
479 extern int chmod_func (char *, char *, gfc_charlen_type
, gfc_charlen_type
);
480 export_proto(chmod_func
);
483 chmod_func (char *name
, char *mode
, gfc_charlen_type name_len
,
484 gfc_charlen_type mode_len
)
486 char *cname
= fc_strdup (name
, name_len
);
487 int ret
= chmod_internal (cname
, mode
, mode_len
);
493 extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4
*,
494 gfc_charlen_type
, gfc_charlen_type
);
495 export_proto(chmod_i4_sub
);
498 chmod_i4_sub (char *name
, char *mode
, GFC_INTEGER_4
* status
,
499 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
503 val
= chmod_func (name
, mode
, name_len
, mode_len
);
509 extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8
*,
510 gfc_charlen_type
, gfc_charlen_type
);
511 export_proto(chmod_i8_sub
);
514 chmod_i8_sub (char *name
, char *mode
, GFC_INTEGER_8
* status
,
515 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
519 val
= chmod_func (name
, mode
, name_len
, mode_len
);