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)
30 #include <string.h> /* For memcpy. */
31 #include <sys/stat.h> /* For stat, chmod and umask. */
34 /* INTEGER FUNCTION CHMOD (NAME, MODE)
35 CHARACTER(len=*), INTENT(IN) :: NAME, MODE
37 Sets the file permission "chmod" using a mode string.
39 For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those,
40 only the user attributes are used.
42 The mode string allows for the same arguments as POSIX's chmod utility.
43 a) string containing an octal number.
44 b) Comma separated list of clauses of the form:
45 [<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...]
46 <who> - 'u', 'g', 'o', 'a'
48 <perm> - 'r', 'w', 'x', 'X', 's', t'
49 If <op> is not followed by a perm-list or permcopy, '-' and '+' do not
50 change the mode while '=' clears all file mode bits. 'u' stands for the
51 user permissions, 'g' for the group and 'o' for the permissions for others.
52 'a' is equivalent to 'ugo'. '+' sets the given permission in addition to
53 the ones of the file, '-' unsets the given permissions of the file, while
54 '=' sets the file to that mode. 'r' sets the read, 'w' the write, and
55 'x' the execute mode. 'X' sets the execute bit if the file is a directory
56 or if the user, group or other executable bit is set. 't' sets the sticky
57 bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit.
59 Note that if <who> is omitted, the permissions are filtered by the umask.
61 A return value of 0 indicates success, -1 an error of chmod() while 1
62 indicates a mode parsing error. */
64 extern int chmod_func (char *, char *, gfc_charlen_type
, gfc_charlen_type
);
65 export_proto(chmod_func
);
68 chmod_func (char *name
, char *mode
, gfc_charlen_type name_len
,
69 gfc_charlen_type mode_len
)
76 bool honor_umask
, continue_clause
= false;
80 mode_t mode_mask
, file_mode
, new_mode
;
83 /* Trim trailing spaces of the file name. */
84 while (name_len
> 0 && name
[name_len
- 1] == ' ')
87 /* Make a null terminated copy of the file name. */
88 file
= gfc_alloca (name_len
+ 1);
89 memcpy (file
, name
, name_len
);
90 file
[name_len
] = '\0';
95 if (mode
[0] >= '0' && mode
[0] <= '9')
99 if (sscanf (mode
, "%o", &fmode
) != 1)
101 file_mode
= (mode_t
) fmode
;
103 if (sscanf (mode
, "%o", &file_mode
) != 1)
106 return chmod (file
, file_mode
);
109 /* Read the current file mode. */
110 if (stat (file
, &stat_buf
))
113 file_mode
= stat_buf
.st_mode
& ~S_IFMT
;
115 is_dir
= stat_buf
.st_mode
& S_IFDIR
;
119 /* Obtain the umask without distroying the setting. */
121 mode_mask
= umask (mode_mask
);
122 (void) umask (mode_mask
);
127 for (i
= 0; i
< mode_len
; i
++)
129 if (!continue_clause
)
138 continue_clause
= false;
139 rwxXstugo
[0] = false;
140 rwxXstugo
[1] = false;
141 rwxXstugo
[2] = false;
142 rwxXstugo
[3] = false;
143 rwxXstugo
[4] = false;
144 rwxXstugo
[5] = false;
145 rwxXstugo
[6] = false;
146 rwxXstugo
[7] = false;
147 rwxXstugo
[8] = false;
150 for (; i
< mode_len
; i
++)
154 /* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */
212 /* Mode setting: =+-. */
216 continue_clause
= true;
228 continue_clause
= true;
240 continue_clause
= true;
249 /* Permissions: rwxXst - for ugo see above. */
251 if (part
!= 2 && part
!= 3)
258 if (part
!= 2 && part
!= 3)
265 if (part
!= 2 && part
!= 3)
272 if (part
!= 2 && part
!= 3)
279 if (part
!= 2 && part
!= 3)
286 if (part
!= 2 && part
!= 3)
292 /* Tailing blanks are valid in Fortran. */
294 for (i
++; i
< mode_len
; i
++)
318 if (rwxXstugo
[0] && (ugo
[0] || honor_umask
))
319 new_mode
|= _S_IREAD
;
322 if (rwxXstugo
[1] && (ugo
[0] || honor_umask
))
323 new_mode
|= _S_IWRITE
;
330 if (ugo
[0] || honor_umask
)
332 if (ugo
[1] || honor_umask
)
334 if (ugo
[2] || honor_umask
)
341 if (ugo
[0] || honor_umask
)
343 if (ugo
[1] || honor_umask
)
345 if (ugo
[2] || honor_umask
)
352 if (ugo
[0] || honor_umask
)
354 if (ugo
[1] || honor_umask
)
356 if (ugo
[2] || honor_umask
)
362 && (is_dir
|| (file_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))))
363 new_mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
368 if (ugo
[0] || honor_umask
)
370 if (ugo
[1] || honor_umask
)
374 /* As original 'u'. */
377 if (ugo
[1] || honor_umask
)
379 if (file_mode
& S_IRUSR
)
381 if (file_mode
& S_IWUSR
)
383 if (file_mode
& S_IXUSR
)
386 if (ugo
[2] || honor_umask
)
388 if (file_mode
& S_IRUSR
)
390 if (file_mode
& S_IWUSR
)
392 if (file_mode
& S_IXUSR
)
397 /* As original 'g'. */
400 if (ugo
[0] || honor_umask
)
402 if (file_mode
& S_IRGRP
)
404 if (file_mode
& S_IWGRP
)
406 if (file_mode
& S_IXGRP
)
409 if (ugo
[2] || honor_umask
)
411 if (file_mode
& S_IRGRP
)
413 if (file_mode
& S_IWGRP
)
415 if (file_mode
& S_IXGRP
)
420 /* As original 'o'. */
423 if (ugo
[0] || honor_umask
)
425 if (file_mode
& S_IROTH
)
427 if (file_mode
& S_IWOTH
)
429 if (file_mode
& S_IXOTH
)
432 if (ugo
[1] || honor_umask
)
434 if (file_mode
& S_IROTH
)
436 if (file_mode
& S_IWOTH
)
438 if (file_mode
& S_IXOTH
)
442 #endif /* __MINGW32__ */
446 new_mode
&= ~mode_mask
;
452 if (ugo
[0] || honor_umask
)
453 file_mode
= (file_mode
& ~(_S_IWRITE
| _S_IREAD
))
454 | (new_mode
& (_S_IWRITE
| _S_IREAD
));
457 if ((ugo
[0] || honor_umask
) && !rwxXstugo
[6])
458 file_mode
= (file_mode
& ~(S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
))
459 | (new_mode
& (S_ISUID
| S_IRUSR
| S_IWUSR
| S_IXUSR
));
460 if ((ugo
[1] || honor_umask
) && !rwxXstugo
[7])
461 file_mode
= (file_mode
& ~(S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
))
462 | (new_mode
& (S_ISGID
| S_IRGRP
| S_IWGRP
| S_IXGRP
));
463 if ((ugo
[2] || honor_umask
) && !rwxXstugo
[8])
464 file_mode
= (file_mode
& ~(S_IROTH
| S_IWOTH
| S_IXOTH
))
465 | (new_mode
& (S_IROTH
| S_IWOTH
| S_IXOTH
));
467 if (is_dir
&& rwxXstugo
[5])
468 file_mode
|= S_ISVTX
;
470 file_mode
&= ~S_ISVTX
;
474 else if (set_mode
== 2)
477 file_mode
&= ~new_mode
;
478 #if !defined( __MINGW32__) && !defined (__VXWORKS__)
479 if (rwxXstugo
[5] || !is_dir
)
480 file_mode
&= ~S_ISVTX
;
483 else if (set_mode
== 3)
485 file_mode
|= new_mode
;
486 #if !defined (__MINGW32__) && !defined (__VXWORKS__)
487 if (rwxXstugo
[5] && is_dir
)
488 file_mode
|= S_ISVTX
;
490 file_mode
&= ~S_ISVTX
;
495 return chmod (file
, file_mode
);
499 extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4
*,
500 gfc_charlen_type
, gfc_charlen_type
);
501 export_proto(chmod_i4_sub
);
504 chmod_i4_sub (char *name
, char *mode
, GFC_INTEGER_4
* status
,
505 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
509 val
= chmod_func (name
, mode
, name_len
, mode_len
);
515 extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8
*,
516 gfc_charlen_type
, gfc_charlen_type
);
517 export_proto(chmod_i8_sub
);
520 chmod_i8_sub (char *name
, char *mode
, GFC_INTEGER_8
* status
,
521 gfc_charlen_type name_len
, gfc_charlen_type mode_len
)
525 val
= chmod_func (name
, mode
, name_len
, mode_len
);