1 /* Implementation of the CHMOD intrinsic.
2 Copyright (C) 2006-2013 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)
31 #include <string.h> /* For memcpy. */
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. */
65 extern int chmod_func (char *, char *, gfc_charlen_type
, gfc_charlen_type
);
66 export_proto(chmod_func
);
69 chmod_func (char *name
, char *mode
, gfc_charlen_type name_len
,
70 gfc_charlen_type mode_len
)
77 bool honor_umask
, continue_clause
= false;
81 mode_t mode_mask
, file_mode
, new_mode
;
84 /* Trim trailing spaces of the file name. */
85 while (name_len
> 0 && name
[name_len
- 1] == ' ')
88 /* Make a null terminated copy of the file name. */
89 file
= gfc_alloca (name_len
+ 1);
90 memcpy (file
, name
, name_len
);
91 file
[name_len
] = '\0';
96 if (mode
[0] >= '0' && mode
[0] <= '9')
100 if (sscanf (mode
, "%o", &fmode
) != 1)
102 file_mode
= (mode_t
) fmode
;
104 if (sscanf (mode
, "%o", &file_mode
) != 1)
107 return chmod (file
, file_mode
);
110 /* Read the current file mode. */
111 if (stat (file
, &stat_buf
))
114 file_mode
= stat_buf
.st_mode
& ~S_IFMT
;
116 is_dir
= stat_buf
.st_mode
& S_IFDIR
;
120 /* Obtain the umask without distroying the setting. */
122 mode_mask
= umask (mode_mask
);
123 (void) umask (mode_mask
);
128 for (i
= 0; i
< mode_len
; i
++)
130 if (!continue_clause
)
139 continue_clause
= false;
140 rwxXstugo
[0] = false;
141 rwxXstugo
[1] = false;
142 rwxXstugo
[2] = false;
143 rwxXstugo
[3] = false;
144 rwxXstugo
[4] = false;
145 rwxXstugo
[5] = false;
146 rwxXstugo
[6] = false;
147 rwxXstugo
[7] = false;
148 rwxXstugo
[8] = false;
151 for (; i
< mode_len
; i
++)
155 /* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */
213 /* Mode setting: =+-. */
217 continue_clause
= true;
229 continue_clause
= true;
241 continue_clause
= true;
250 /* Permissions: rwxXst - for ugo see above. */
252 if (part
!= 2 && part
!= 3)
259 if (part
!= 2 && part
!= 3)
266 if (part
!= 2 && part
!= 3)
273 if (part
!= 2 && part
!= 3)
280 if (part
!= 2 && part
!= 3)
287 if (part
!= 2 && part
!= 3)
293 /* Tailing blanks are valid in Fortran. */
295 for (i
++; i
< mode_len
; i
++)
319 if (rwxXstugo
[0] && (ugo
[0] || honor_umask
))
320 new_mode
|= _S_IREAD
;
323 if (rwxXstugo
[1] && (ugo
[0] || honor_umask
))
324 new_mode
|= _S_IWRITE
;
331 if (ugo
[0] || honor_umask
)
333 if (ugo
[1] || honor_umask
)
335 if (ugo
[2] || honor_umask
)
342 if (ugo
[0] || honor_umask
)
344 if (ugo
[1] || honor_umask
)
346 if (ugo
[2] || honor_umask
)
353 if (ugo
[0] || honor_umask
)
355 if (ugo
[1] || honor_umask
)
357 if (ugo
[2] || honor_umask
)
363 && (is_dir
|| (file_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))))
364 new_mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
369 if (ugo
[0] || honor_umask
)
371 if (ugo
[1] || honor_umask
)
375 /* As original 'u'. */
378 if (ugo
[1] || honor_umask
)
380 if (file_mode
& S_IRUSR
)
382 if (file_mode
& S_IWUSR
)
384 if (file_mode
& S_IXUSR
)
387 if (ugo
[2] || honor_umask
)
389 if (file_mode
& S_IRUSR
)
391 if (file_mode
& S_IWUSR
)
393 if (file_mode
& S_IXUSR
)
398 /* As original 'g'. */
401 if (ugo
[0] || honor_umask
)
403 if (file_mode
& S_IRGRP
)
405 if (file_mode
& S_IWGRP
)
407 if (file_mode
& S_IXGRP
)
410 if (ugo
[2] || honor_umask
)
412 if (file_mode
& S_IRGRP
)
414 if (file_mode
& S_IWGRP
)
416 if (file_mode
& S_IXGRP
)
421 /* As original 'o'. */
424 if (ugo
[0] || honor_umask
)
426 if (file_mode
& S_IROTH
)
428 if (file_mode
& S_IWOTH
)
430 if (file_mode
& S_IXOTH
)
433 if (ugo
[1] || honor_umask
)
435 if (file_mode
& S_IROTH
)
437 if (file_mode
& S_IWOTH
)
439 if (file_mode
& S_IXOTH
)
443 #endif /* __MINGW32__ */
447 new_mode
&= ~mode_mask
;
453 if (ugo
[0] || honor_umask
)
454 file_mode
= (file_mode
& ~(_S_IWRITE
| _S_IREAD
))
455 | (new_mode
& (_S_IWRITE
| _S_IREAD
));
458 if ((ugo
[0] || honor_umask
) && !rwxXstugo
[6])
459 file_mode
= (file_mode
& ~(S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
))
460 | (new_mode
& (S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
));
461 if ((ugo
[1] || honor_umask
) && !rwxXstugo
[7])
462 file_mode
= (file_mode
& ~(S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
))
463 | (new_mode
& (S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
));
464 if ((ugo
[2] || honor_umask
) && !rwxXstugo
[8])
465 file_mode
= (file_mode
& ~(S_IROTH
| S_IWOTH
| S_IXOTH
))
466 | (new_mode
& (S_IROTH
| S_IWOTH
| S_IXOTH
));
468 if (is_dir
&& rwxXstugo
[5])
469 file_mode
|= S_ISVTX
;
471 file_mode
&= ~S_ISVTX
;
475 else if (set_mode
== 2)
478 file_mode
&= ~new_mode
;
479 #if !defined( __MINGW32__) && !defined (__VXWORKS__)
480 if (rwxXstugo
[5] || !is_dir
)
481 file_mode
&= ~S_ISVTX
;
484 else if (set_mode
== 3)
486 file_mode
|= new_mode
;
487 #if !defined (__MINGW32__) && !defined (__VXWORKS__)
488 if (rwxXstugo
[5] && is_dir
)
489 file_mode
|= S_ISVTX
;
491 file_mode
&= ~S_ISVTX
;
496 return chmod (file
, file_mode
);
500 extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4
*,
501 gfc_charlen_type
, gfc_charlen_type
);
502 export_proto(chmod_i4_sub
);
505 chmod_i4_sub (char *name
, char *mode
, GFC_INTEGER_4
* status
,
506 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
510 val
= chmod_func (name
, mode
, name_len
, mode_len
);
516 extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8
*,
517 gfc_charlen_type
, gfc_charlen_type
);
518 export_proto(chmod_i8_sub
);
521 chmod_i8_sub (char *name
, char *mode
, GFC_INTEGER_8
* status
,
522 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
526 val
= chmod_func (name
, mode
, name_len
, mode_len
);