1 /* Implementation of the CHMOD intrinsic.
2 Copyright (C) 2006-2016 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 <string.h> /* For memcpy. */
31 #include <stdlib.h> /* For free. */
32 #include <sys/stat.h> /* For stat, chmod and umask. */
35 /* INTEGER FUNCTION CHMOD (NAME, MODE)
36 CHARACTER(len=*), INTENT(IN) :: NAME, MODE
38 Sets the file permission "chmod" using a mode string.
40 For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those,
41 only the user attributes are used.
43 The mode string allows for the same arguments as POSIX's chmod utility.
44 a) string containing an octal number.
45 b) Comma separated list of clauses of the form:
46 [<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...]
47 <who> - 'u', 'g', 'o', 'a'
49 <perm> - 'r', 'w', 'x', 'X', 's', t'
50 If <op> is not followed by a perm-list or permcopy, '-' and '+' do not
51 change the mode while '=' clears all file mode bits. 'u' stands for the
52 user permissions, 'g' for the group and 'o' for the permissions for others.
53 'a' is equivalent to 'ugo'. '+' sets the given permission in addition to
54 the ones of the file, '-' unsets the given permissions of the file, while
55 '=' sets the file to that mode. 'r' sets the read, 'w' the write, and
56 'x' the execute mode. 'X' sets the execute bit if the file is a directory
57 or if the user, group or other executable bit is set. 't' sets the sticky
58 bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit.
60 Note that if <who> is omitted, the permissions are filtered by the umask.
62 A return value of 0 indicates success, -1 an error of chmod() while 1
63 indicates a mode parsing error. */
67 chmod_internal (char *file
, char *mode
, gfc_charlen_type mode_len
)
73 bool honor_umask
, continue_clause
= false;
77 mode_t mode_mask
, file_mode
, new_mode
;
83 if (mode
[0] >= '0' && mode
[0] <= '9')
87 if (sscanf (mode
, "%o", &fmode
) != 1)
89 file_mode
= (mode_t
) fmode
;
91 if (sscanf (mode
, "%o", &file_mode
) != 1)
94 return chmod (file
, file_mode
);
97 /* Read the current file mode. */
98 if (stat (file
, &stat_buf
))
101 file_mode
= stat_buf
.st_mode
& ~S_IFMT
;
103 is_dir
= stat_buf
.st_mode
& S_IFDIR
;
107 /* Obtain the umask without distroying the setting. */
109 mode_mask
= umask (mode_mask
);
110 (void) umask (mode_mask
);
115 for (i
= 0; i
< mode_len
; i
++)
117 if (!continue_clause
)
126 continue_clause
= false;
127 rwxXstugo
[0] = false;
128 rwxXstugo
[1] = false;
129 rwxXstugo
[2] = false;
130 rwxXstugo
[3] = false;
131 rwxXstugo
[4] = false;
132 rwxXstugo
[5] = false;
133 rwxXstugo
[6] = false;
134 rwxXstugo
[7] = false;
135 rwxXstugo
[8] = false;
138 for (; i
< mode_len
; i
++)
142 /* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */
200 /* Mode setting: =+-. */
204 continue_clause
= true;
216 continue_clause
= true;
228 continue_clause
= true;
237 /* Permissions: rwxXst - for ugo see above. */
239 if (part
!= 2 && part
!= 3)
246 if (part
!= 2 && part
!= 3)
253 if (part
!= 2 && part
!= 3)
260 if (part
!= 2 && part
!= 3)
267 if (part
!= 2 && part
!= 3)
274 if (part
!= 2 && part
!= 3)
280 /* Tailing blanks are valid in Fortran. */
282 for (i
++; i
< mode_len
; i
++)
306 if (rwxXstugo
[0] && (ugo
[0] || honor_umask
))
307 new_mode
|= _S_IREAD
;
310 if (rwxXstugo
[1] && (ugo
[0] || honor_umask
))
311 new_mode
|= _S_IWRITE
;
318 if (ugo
[0] || honor_umask
)
320 if (ugo
[1] || honor_umask
)
322 if (ugo
[2] || honor_umask
)
329 if (ugo
[0] || honor_umask
)
331 if (ugo
[1] || honor_umask
)
333 if (ugo
[2] || honor_umask
)
340 if (ugo
[0] || honor_umask
)
342 if (ugo
[1] || honor_umask
)
344 if (ugo
[2] || honor_umask
)
350 && (is_dir
|| (file_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))))
351 new_mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
356 if (ugo
[0] || honor_umask
)
358 if (ugo
[1] || honor_umask
)
362 /* As original 'u'. */
365 if (ugo
[1] || honor_umask
)
367 if (file_mode
& S_IRUSR
)
369 if (file_mode
& S_IWUSR
)
371 if (file_mode
& S_IXUSR
)
374 if (ugo
[2] || honor_umask
)
376 if (file_mode
& S_IRUSR
)
378 if (file_mode
& S_IWUSR
)
380 if (file_mode
& S_IXUSR
)
385 /* As original 'g'. */
388 if (ugo
[0] || honor_umask
)
390 if (file_mode
& S_IRGRP
)
392 if (file_mode
& S_IWGRP
)
394 if (file_mode
& S_IXGRP
)
397 if (ugo
[2] || honor_umask
)
399 if (file_mode
& S_IRGRP
)
401 if (file_mode
& S_IWGRP
)
403 if (file_mode
& S_IXGRP
)
408 /* As original 'o'. */
411 if (ugo
[0] || honor_umask
)
413 if (file_mode
& S_IROTH
)
415 if (file_mode
& S_IWOTH
)
417 if (file_mode
& S_IXOTH
)
420 if (ugo
[1] || honor_umask
)
422 if (file_mode
& S_IROTH
)
424 if (file_mode
& S_IWOTH
)
426 if (file_mode
& S_IXOTH
)
430 #endif /* __MINGW32__ */
434 new_mode
&= ~mode_mask
;
440 if (ugo
[0] || honor_umask
)
441 file_mode
= (file_mode
& ~(_S_IWRITE
| _S_IREAD
))
442 | (new_mode
& (_S_IWRITE
| _S_IREAD
));
445 if ((ugo
[0] || honor_umask
) && !rwxXstugo
[6])
446 file_mode
= (file_mode
& ~(S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
))
447 | (new_mode
& (S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
));
448 if ((ugo
[1] || honor_umask
) && !rwxXstugo
[7])
449 file_mode
= (file_mode
& ~(S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
))
450 | (new_mode
& (S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
));
451 if ((ugo
[2] || honor_umask
) && !rwxXstugo
[8])
452 file_mode
= (file_mode
& ~(S_IROTH
| S_IWOTH
| S_IXOTH
))
453 | (new_mode
& (S_IROTH
| S_IWOTH
| S_IXOTH
));
455 if (is_dir
&& rwxXstugo
[5])
456 file_mode
|= S_ISVTX
;
458 file_mode
&= ~S_ISVTX
;
462 else if (set_mode
== 2)
465 file_mode
&= ~new_mode
;
466 #if !defined( __MINGW32__) && !defined (__VXWORKS__)
467 if (rwxXstugo
[5] || !is_dir
)
468 file_mode
&= ~S_ISVTX
;
471 else if (set_mode
== 3)
473 file_mode
|= new_mode
;
474 #if !defined (__MINGW32__) && !defined (__VXWORKS__)
475 if (rwxXstugo
[5] && is_dir
)
476 file_mode
|= S_ISVTX
;
478 file_mode
&= ~S_ISVTX
;
483 return chmod (file
, file_mode
);
487 extern int chmod_func (char *, char *, gfc_charlen_type
, gfc_charlen_type
);
488 export_proto(chmod_func
);
491 chmod_func (char *name
, char *mode
, gfc_charlen_type name_len
,
492 gfc_charlen_type mode_len
)
494 char *cname
= fc_strdup (name
, name_len
);
495 int ret
= chmod_internal (cname
, mode
, mode_len
);
501 extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4
*,
502 gfc_charlen_type
, gfc_charlen_type
);
503 export_proto(chmod_i4_sub
);
506 chmod_i4_sub (char *name
, char *mode
, GFC_INTEGER_4
* status
,
507 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
511 val
= chmod_func (name
, mode
, name_len
, mode_len
);
517 extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8
*,
518 gfc_charlen_type
, gfc_charlen_type
);
519 export_proto(chmod_i8_sub
);
522 chmod_i8_sub (char *name
, char *mode
, GFC_INTEGER_8
* status
,
523 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
527 val
= chmod_func (name
, mode
, name_len
, mode_len
);