Home | History | Annotate | Line # | Download | only in intrinsics
      1      1.1  mrg /* Implementation of the CHMOD intrinsic.
      2  1.1.1.3  mrg    Copyright (C) 2006-2022 Free Software Foundation, Inc.
      3      1.1  mrg    Contributed by Franois-Xavier Coudert <coudert (at) clipper.ens.fr>
      4      1.1  mrg 
      5      1.1  mrg This file is part of the GNU Fortran runtime library (libgfortran).
      6      1.1  mrg 
      7      1.1  mrg Libgfortran is free software; you can redistribute it and/or
      8      1.1  mrg modify it under the terms of the GNU General Public
      9      1.1  mrg License as published by the Free Software Foundation; either
     10      1.1  mrg version 3 of the License, or (at your option) any later version.
     11      1.1  mrg 
     12      1.1  mrg Libgfortran is distributed in the hope that it will be useful,
     13      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15      1.1  mrg GNU General Public License for more details.
     16      1.1  mrg 
     17      1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     18      1.1  mrg permissions described in the GCC Runtime Library Exception, version
     19      1.1  mrg 3.1, as published by the Free Software Foundation.
     20      1.1  mrg 
     21      1.1  mrg You should have received a copy of the GNU General Public License and
     22      1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     23      1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24      1.1  mrg <http://www.gnu.org/licenses/>.  */
     25      1.1  mrg 
     26      1.1  mrg #include "libgfortran.h"
     27      1.1  mrg 
     28      1.1  mrg #if defined(HAVE_SYS_STAT_H)
     29      1.1  mrg 
     30      1.1  mrg #include <sys/stat.h>	/* For stat, chmod and umask.  */
     31      1.1  mrg 
     32      1.1  mrg 
     33      1.1  mrg /* INTEGER FUNCTION CHMOD (NAME, MODE)
     34      1.1  mrg    CHARACTER(len=*), INTENT(IN) :: NAME, MODE
     35      1.1  mrg 
     36      1.1  mrg    Sets the file permission "chmod" using a mode string.
     37      1.1  mrg 
     38      1.1  mrg    For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those,
     39      1.1  mrg    only the user attributes are used.
     40      1.1  mrg 
     41      1.1  mrg    The mode string allows for the same arguments as POSIX's chmod utility.
     42      1.1  mrg    a) string containing an octal number.
     43      1.1  mrg    b) Comma separated list of clauses of the form:
     44      1.1  mrg       [<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...]
     45      1.1  mrg       <who> - 'u', 'g', 'o', 'a'
     46      1.1  mrg       <op>  - '+', '-', '='
     47      1.1  mrg       <perm> - 'r', 'w', 'x', 'X', 's', t'
     48      1.1  mrg    If <op> is not followed by a perm-list or permcopy, '-' and '+' do not
     49      1.1  mrg    change the mode while '=' clears all file mode bits. 'u' stands for the
     50      1.1  mrg    user permissions, 'g' for the group and 'o' for the permissions for others.
     51      1.1  mrg    'a' is equivalent to 'ugo'. '+' sets the given permission in addition to
     52      1.1  mrg    the ones of the file, '-' unsets the given permissions of the file, while
     53      1.1  mrg    '=' sets the file to that mode. 'r' sets the read, 'w' the write, and
     54      1.1  mrg    'x' the execute mode. 'X' sets the execute bit if the file is a directory
     55      1.1  mrg    or if the user, group or other executable bit is set. 't' sets the sticky
     56      1.1  mrg    bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit.
     57      1.1  mrg 
     58      1.1  mrg    Note that if <who> is omitted, the permissions are filtered by the umask.
     59      1.1  mrg 
     60      1.1  mrg    A return value of 0 indicates success, -1 an error of chmod() while 1
     61      1.1  mrg    indicates a mode parsing error.  */
     62      1.1  mrg 
     63      1.1  mrg 
     64      1.1  mrg static int
     65      1.1  mrg chmod_internal (char *file, char *mode, gfc_charlen_type mode_len)
     66      1.1  mrg {
     67      1.1  mrg   bool ugo[3];
     68      1.1  mrg   bool rwxXstugo[9];
     69      1.1  mrg   int set_mode, part;
     70      1.1  mrg   bool honor_umask, continue_clause = false;
     71      1.1  mrg #ifndef __MINGW32__
     72      1.1  mrg   bool is_dir;
     73      1.1  mrg #endif
     74  1.1.1.3  mrg #ifdef HAVE_UMASK
     75  1.1.1.3  mrg   mode_t mode_mask;
     76  1.1.1.3  mrg #endif
     77  1.1.1.3  mrg   mode_t file_mode, new_mode;
     78      1.1  mrg   struct stat stat_buf;
     79      1.1  mrg 
     80      1.1  mrg   if (mode_len == 0)
     81      1.1  mrg     return 1;
     82      1.1  mrg 
     83      1.1  mrg   if (mode[0] >= '0' && mode[0] <= '9')
     84      1.1  mrg     {
     85      1.1  mrg       unsigned fmode;
     86      1.1  mrg       if (sscanf (mode, "%o", &fmode) != 1)
     87      1.1  mrg 	return 1;
     88      1.1  mrg       return chmod (file, (mode_t) fmode);
     89      1.1  mrg     }
     90      1.1  mrg 
     91      1.1  mrg   /* Read the current file mode. */
     92      1.1  mrg   if (stat (file, &stat_buf))
     93      1.1  mrg     return 1;
     94      1.1  mrg 
     95      1.1  mrg   file_mode = stat_buf.st_mode & ~S_IFMT;
     96      1.1  mrg #ifndef __MINGW32__
     97      1.1  mrg   is_dir = stat_buf.st_mode & S_IFDIR;
     98      1.1  mrg #endif
     99      1.1  mrg 
    100      1.1  mrg #ifdef HAVE_UMASK
    101      1.1  mrg   /* Obtain the umask without distroying the setting.  */
    102      1.1  mrg   mode_mask = 0;
    103      1.1  mrg   mode_mask = umask (mode_mask);
    104      1.1  mrg   (void) umask (mode_mask);
    105      1.1  mrg #else
    106      1.1  mrg   honor_umask = false;
    107      1.1  mrg #endif
    108      1.1  mrg 
    109      1.1  mrg   for (gfc_charlen_type i = 0; i < mode_len; i++)
    110      1.1  mrg     {
    111      1.1  mrg       if (!continue_clause)
    112      1.1  mrg 	{
    113      1.1  mrg 	  ugo[0] = false;
    114      1.1  mrg 	  ugo[1] = false;
    115      1.1  mrg 	  ugo[2] = false;
    116      1.1  mrg #ifdef HAVE_UMASK
    117      1.1  mrg 	  honor_umask = true;
    118      1.1  mrg #endif
    119      1.1  mrg 	}
    120      1.1  mrg       continue_clause = false;
    121      1.1  mrg       rwxXstugo[0] = false;
    122      1.1  mrg       rwxXstugo[1] = false;
    123      1.1  mrg       rwxXstugo[2] = false;
    124      1.1  mrg       rwxXstugo[3] = false;
    125      1.1  mrg       rwxXstugo[4] = false;
    126      1.1  mrg       rwxXstugo[5] = false;
    127      1.1  mrg       rwxXstugo[6] = false;
    128      1.1  mrg       rwxXstugo[7] = false;
    129      1.1  mrg       rwxXstugo[8] = false;
    130      1.1  mrg       part = 0;
    131      1.1  mrg       set_mode = -1;
    132      1.1  mrg       for (; i < mode_len; i++)
    133      1.1  mrg 	{
    134      1.1  mrg 	  switch (mode[i])
    135      1.1  mrg 	    {
    136      1.1  mrg 	    /* User setting: a[ll]/u[ser]/g[roup]/o[ther].  */
    137      1.1  mrg 	    case 'a':
    138      1.1  mrg 	      if (part > 1)
    139      1.1  mrg 		return 1;
    140      1.1  mrg 	      ugo[0] = true;
    141      1.1  mrg 	      ugo[1] = true;
    142      1.1  mrg 	      ugo[2] = true;
    143      1.1  mrg 	      part = 1;
    144      1.1  mrg #ifdef HAVE_UMASK
    145      1.1  mrg 	      honor_umask = false;
    146      1.1  mrg #endif
    147      1.1  mrg 	      break;
    148      1.1  mrg 	    case 'u':
    149      1.1  mrg 	      if (part == 2)
    150      1.1  mrg 		{
    151      1.1  mrg 		  rwxXstugo[6] = true;
    152      1.1  mrg 		  part = 4;
    153      1.1  mrg 		  break;
    154      1.1  mrg 		}
    155      1.1  mrg 	      if (part > 1)
    156      1.1  mrg 		return 1;
    157      1.1  mrg 	      ugo[0] = true;
    158      1.1  mrg 	      part = 1;
    159      1.1  mrg #ifdef HAVE_UMASK
    160      1.1  mrg 	      honor_umask = false;
    161      1.1  mrg #endif
    162      1.1  mrg 	      break;
    163      1.1  mrg 	    case 'g':
    164      1.1  mrg 	      if (part == 2)
    165      1.1  mrg 		{
    166      1.1  mrg 		  rwxXstugo[7] = true;
    167      1.1  mrg 		  part = 4;
    168      1.1  mrg 		  break;
    169      1.1  mrg 		}
    170      1.1  mrg 	      if (part > 1)
    171      1.1  mrg 		return 1;
    172      1.1  mrg        	      ugo[1] = true;
    173      1.1  mrg 	      part = 1;
    174      1.1  mrg #ifdef HAVE_UMASK
    175      1.1  mrg 	      honor_umask = false;
    176      1.1  mrg #endif
    177      1.1  mrg 	      break;
    178      1.1  mrg 	    case 'o':
    179      1.1  mrg 	      if (part == 2)
    180      1.1  mrg 		{
    181      1.1  mrg 		  rwxXstugo[8] = true;
    182      1.1  mrg 		  part = 4;
    183      1.1  mrg 		  break;
    184      1.1  mrg 		}
    185      1.1  mrg 	      if (part > 1)
    186      1.1  mrg 		return 1;
    187      1.1  mrg 	      ugo[2] = true;
    188      1.1  mrg 	      part = 1;
    189      1.1  mrg #ifdef HAVE_UMASK
    190      1.1  mrg 	      honor_umask = false;
    191      1.1  mrg #endif
    192      1.1  mrg 	      break;
    193      1.1  mrg 
    194      1.1  mrg 	    /* Mode setting: =+-.  */
    195      1.1  mrg 	    case '=':
    196      1.1  mrg 	      if (part > 2)
    197      1.1  mrg 		{
    198      1.1  mrg 		  continue_clause = true;
    199      1.1  mrg 		  i--;
    200      1.1  mrg 		  part = 2;
    201      1.1  mrg 		  goto clause_done;
    202      1.1  mrg 		}
    203      1.1  mrg 	      set_mode = 1;
    204      1.1  mrg 	      part = 2;
    205      1.1  mrg 	      break;
    206      1.1  mrg 
    207      1.1  mrg 	    case '-':
    208      1.1  mrg 	      if (part > 2)
    209      1.1  mrg 		{
    210      1.1  mrg 		  continue_clause = true;
    211      1.1  mrg 		  i--;
    212      1.1  mrg 		  part = 2;
    213      1.1  mrg 		  goto clause_done;
    214      1.1  mrg 		}
    215      1.1  mrg 	      set_mode = 2;
    216      1.1  mrg 	      part = 2;
    217      1.1  mrg 	      break;
    218      1.1  mrg 
    219      1.1  mrg 	    case '+':
    220      1.1  mrg 	      if (part > 2)
    221      1.1  mrg 		{
    222      1.1  mrg 		  continue_clause = true;
    223      1.1  mrg 		  i--;
    224      1.1  mrg 		  part = 2;
    225      1.1  mrg 		  goto clause_done;
    226      1.1  mrg 		}
    227      1.1  mrg 	      set_mode = 3;
    228      1.1  mrg 	      part = 2;
    229      1.1  mrg 	      break;
    230      1.1  mrg 
    231      1.1  mrg 	    /* Permissions: rwxXst - for ugo see above.  */
    232      1.1  mrg 	    case 'r':
    233      1.1  mrg 	      if (part != 2 && part != 3)
    234      1.1  mrg 		return 1;
    235      1.1  mrg 	      rwxXstugo[0] = true;
    236      1.1  mrg 	      part = 3;
    237      1.1  mrg 	      break;
    238      1.1  mrg 
    239      1.1  mrg 	    case 'w':
    240      1.1  mrg 	      if (part != 2 && part != 3)
    241      1.1  mrg 		return 1;
    242      1.1  mrg 	      rwxXstugo[1] = true;
    243      1.1  mrg 	      part = 3;
    244      1.1  mrg 	      break;
    245      1.1  mrg 
    246      1.1  mrg 	    case 'x':
    247      1.1  mrg 	      if (part != 2 && part != 3)
    248      1.1  mrg 		return 1;
    249      1.1  mrg 	      rwxXstugo[2] = true;
    250      1.1  mrg 	      part = 3;
    251      1.1  mrg 	      break;
    252      1.1  mrg 
    253      1.1  mrg 	    case 'X':
    254      1.1  mrg 	      if (part != 2 && part != 3)
    255      1.1  mrg 		return 1;
    256      1.1  mrg 	      rwxXstugo[3] = true;
    257      1.1  mrg 	      part = 3;
    258      1.1  mrg 	      break;
    259      1.1  mrg 
    260      1.1  mrg 	    case 's':
    261      1.1  mrg 	      if (part != 2 && part != 3)
    262      1.1  mrg 		return 1;
    263      1.1  mrg 	      rwxXstugo[4] = true;
    264      1.1  mrg 	      part = 3;
    265      1.1  mrg 	      break;
    266      1.1  mrg 
    267      1.1  mrg 	    case 't':
    268      1.1  mrg 	      if (part != 2 && part != 3)
    269      1.1  mrg 		return 1;
    270      1.1  mrg 	      rwxXstugo[5] = true;
    271      1.1  mrg 	      part = 3;
    272      1.1  mrg 	      break;
    273      1.1  mrg 
    274  1.1.1.3  mrg 	    /* Trailing blanks are valid in Fortran.  */
    275      1.1  mrg 	    case ' ':
    276      1.1  mrg 	      for (i++; i < mode_len; i++)
    277      1.1  mrg 		if (mode[i] != ' ')
    278      1.1  mrg 		  break;
    279      1.1  mrg 	      if (i != mode_len)
    280      1.1  mrg 		return 1;
    281      1.1  mrg 	      goto clause_done;
    282      1.1  mrg 
    283      1.1  mrg 	    case ',':
    284      1.1  mrg 	      goto clause_done;
    285      1.1  mrg 
    286      1.1  mrg 	    default:
    287      1.1  mrg 	      return 1;
    288      1.1  mrg 	    }
    289      1.1  mrg 	}
    290      1.1  mrg 
    291      1.1  mrg clause_done:
    292      1.1  mrg       if (part < 2)
    293      1.1  mrg 	return 1;
    294      1.1  mrg 
    295      1.1  mrg       new_mode = 0;
    296      1.1  mrg 
    297      1.1  mrg #ifdef __MINGW32__
    298      1.1  mrg 
    299      1.1  mrg       /* Read. */
    300      1.1  mrg       if (rwxXstugo[0] && (ugo[0] || honor_umask))
    301      1.1  mrg 	new_mode |= _S_IREAD;
    302      1.1  mrg 
    303      1.1  mrg       /* Write. */
    304      1.1  mrg       if (rwxXstugo[1] && (ugo[0] || honor_umask))
    305      1.1  mrg 	new_mode |= _S_IWRITE;
    306      1.1  mrg 
    307      1.1  mrg #else
    308      1.1  mrg 
    309      1.1  mrg       /* Read. */
    310      1.1  mrg       if (rwxXstugo[0])
    311      1.1  mrg 	{
    312      1.1  mrg 	  if (ugo[0] || honor_umask)
    313      1.1  mrg 	    new_mode |= S_IRUSR;
    314      1.1  mrg 	  if (ugo[1] || honor_umask)
    315      1.1  mrg 	    new_mode |= S_IRGRP;
    316      1.1  mrg 	  if (ugo[2] || honor_umask)
    317      1.1  mrg 	    new_mode |= S_IROTH;
    318      1.1  mrg 	}
    319      1.1  mrg 
    320      1.1  mrg       /* Write.  */
    321      1.1  mrg       if (rwxXstugo[1])
    322      1.1  mrg 	{
    323      1.1  mrg 	  if (ugo[0] || honor_umask)
    324      1.1  mrg 	    new_mode |= S_IWUSR;
    325      1.1  mrg 	  if (ugo[1] || honor_umask)
    326      1.1  mrg 	    new_mode |= S_IWGRP;
    327      1.1  mrg 	  if (ugo[2] || honor_umask)
    328      1.1  mrg 	    new_mode |= S_IWOTH;
    329      1.1  mrg 	}
    330      1.1  mrg 
    331      1.1  mrg       /* Execute. */
    332      1.1  mrg       if (rwxXstugo[2])
    333      1.1  mrg 	{
    334      1.1  mrg 	  if (ugo[0] || honor_umask)
    335      1.1  mrg 	    new_mode |= S_IXUSR;
    336      1.1  mrg 	  if (ugo[1] || honor_umask)
    337      1.1  mrg 	    new_mode |= S_IXGRP;
    338      1.1  mrg 	  if (ugo[2] || honor_umask)
    339      1.1  mrg 	    new_mode |= S_IXOTH;
    340      1.1  mrg 	}
    341      1.1  mrg 
    342      1.1  mrg       /* 'X' execute.  */
    343      1.1  mrg       if (rwxXstugo[3]
    344      1.1  mrg 	  && (is_dir || (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
    345      1.1  mrg 	new_mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
    346      1.1  mrg 
    347      1.1  mrg       /* 's'.  */
    348      1.1  mrg       if (rwxXstugo[4])
    349      1.1  mrg 	{
    350      1.1  mrg 	  if (ugo[0] || honor_umask)
    351      1.1  mrg 	    new_mode |= S_ISUID;
    352      1.1  mrg 	  if (ugo[1] || honor_umask)
    353      1.1  mrg 	    new_mode |= S_ISGID;
    354      1.1  mrg 	}
    355      1.1  mrg 
    356      1.1  mrg       /* As original 'u'.  */
    357      1.1  mrg       if (rwxXstugo[6])
    358      1.1  mrg 	{
    359      1.1  mrg 	  if (ugo[1] || honor_umask)
    360      1.1  mrg 	    {
    361      1.1  mrg 	      if (file_mode & S_IRUSR)
    362      1.1  mrg 		new_mode |= S_IRGRP;
    363      1.1  mrg 	      if (file_mode & S_IWUSR)
    364      1.1  mrg 		new_mode |= S_IWGRP;
    365      1.1  mrg 	      if (file_mode & S_IXUSR)
    366      1.1  mrg 		new_mode |= S_IXGRP;
    367      1.1  mrg 	    }
    368      1.1  mrg 	  if (ugo[2] || honor_umask)
    369      1.1  mrg 	    {
    370      1.1  mrg 	      if (file_mode & S_IRUSR)
    371      1.1  mrg 		new_mode |= S_IROTH;
    372      1.1  mrg 	      if (file_mode & S_IWUSR)
    373      1.1  mrg 		new_mode |= S_IWOTH;
    374      1.1  mrg 	      if (file_mode & S_IXUSR)
    375      1.1  mrg 		new_mode |= S_IXOTH;
    376      1.1  mrg 	    }
    377      1.1  mrg 	}
    378      1.1  mrg 
    379      1.1  mrg       /* As original 'g'.  */
    380      1.1  mrg       if (rwxXstugo[7])
    381      1.1  mrg 	{
    382      1.1  mrg 	  if (ugo[0] || honor_umask)
    383      1.1  mrg 	    {
    384      1.1  mrg 	      if (file_mode & S_IRGRP)
    385      1.1  mrg 		new_mode |= S_IRUSR;
    386      1.1  mrg 	      if (file_mode & S_IWGRP)
    387      1.1  mrg 		new_mode |= S_IWUSR;
    388      1.1  mrg 	      if (file_mode & S_IXGRP)
    389      1.1  mrg 		new_mode |= S_IXUSR;
    390      1.1  mrg 	    }
    391      1.1  mrg 	  if (ugo[2] || honor_umask)
    392      1.1  mrg 	    {
    393      1.1  mrg 	      if (file_mode & S_IRGRP)
    394      1.1  mrg 		new_mode |= S_IROTH;
    395      1.1  mrg 	      if (file_mode & S_IWGRP)
    396      1.1  mrg 		new_mode |= S_IWOTH;
    397      1.1  mrg 	      if (file_mode & S_IXGRP)
    398      1.1  mrg 		new_mode |= S_IXOTH;
    399      1.1  mrg 	    }
    400      1.1  mrg 	}
    401      1.1  mrg 
    402      1.1  mrg       /* As original 'o'.  */
    403      1.1  mrg       if (rwxXstugo[8])
    404      1.1  mrg 	{
    405      1.1  mrg 	  if (ugo[0] || honor_umask)
    406      1.1  mrg 	    {
    407      1.1  mrg 	      if (file_mode & S_IROTH)
    408      1.1  mrg 		new_mode |= S_IRUSR;
    409      1.1  mrg 	      if (file_mode & S_IWOTH)
    410      1.1  mrg 		new_mode |= S_IWUSR;
    411      1.1  mrg 	      if (file_mode & S_IXOTH)
    412      1.1  mrg 		new_mode |= S_IXUSR;
    413      1.1  mrg 	    }
    414      1.1  mrg 	  if (ugo[1] || honor_umask)
    415      1.1  mrg 	    {
    416      1.1  mrg 	      if (file_mode & S_IROTH)
    417      1.1  mrg 		new_mode |= S_IRGRP;
    418      1.1  mrg 	      if (file_mode & S_IWOTH)
    419      1.1  mrg 		new_mode |= S_IWGRP;
    420      1.1  mrg 	      if (file_mode & S_IXOTH)
    421      1.1  mrg 		new_mode |= S_IXGRP;
    422      1.1  mrg 	    }
    423      1.1  mrg 	}
    424      1.1  mrg #endif  /* __MINGW32__ */
    425      1.1  mrg 
    426      1.1  mrg #ifdef HAVE_UMASK
    427      1.1  mrg     if (honor_umask)
    428      1.1  mrg       new_mode &= ~mode_mask;
    429      1.1  mrg #endif
    430      1.1  mrg 
    431      1.1  mrg     if (set_mode == 1)
    432      1.1  mrg       {
    433      1.1  mrg #ifdef __MINGW32__
    434      1.1  mrg 	if (ugo[0] || honor_umask)
    435      1.1  mrg 	  file_mode = (file_mode & ~(_S_IWRITE | _S_IREAD))
    436      1.1  mrg 		      | (new_mode & (_S_IWRITE | _S_IREAD));
    437      1.1  mrg #else
    438      1.1  mrg 	/* Set '='.  */
    439      1.1  mrg 	if ((ugo[0] || honor_umask) && !rwxXstugo[6])
    440      1.1  mrg 	  file_mode = (file_mode & ~(S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR))
    441      1.1  mrg 		      | (new_mode & (S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR));
    442      1.1  mrg 	if ((ugo[1] || honor_umask) && !rwxXstugo[7])
    443      1.1  mrg 	  file_mode = (file_mode & ~(S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP))
    444      1.1  mrg 		      | (new_mode & (S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP));
    445      1.1  mrg 	if ((ugo[2] || honor_umask) && !rwxXstugo[8])
    446      1.1  mrg 	  file_mode = (file_mode & ~(S_IROTH | S_IWOTH | S_IXOTH))
    447      1.1  mrg 		      | (new_mode & (S_IROTH | S_IWOTH | S_IXOTH));
    448      1.1  mrg #ifndef __VXWORKS__
    449      1.1  mrg 	if (is_dir && rwxXstugo[5])
    450      1.1  mrg 	  file_mode |= S_ISVTX;
    451      1.1  mrg 	else if (!is_dir)
    452      1.1  mrg 	  file_mode &= ~S_ISVTX;
    453      1.1  mrg #endif
    454      1.1  mrg #endif
    455      1.1  mrg       }
    456      1.1  mrg     else if (set_mode == 2)
    457      1.1  mrg       {
    458      1.1  mrg 	/* Clear '-'.  */
    459      1.1  mrg 	file_mode &= ~new_mode;
    460      1.1  mrg #if !defined( __MINGW32__) && !defined (__VXWORKS__)
    461      1.1  mrg 	if (rwxXstugo[5] || !is_dir)
    462      1.1  mrg 	  file_mode &= ~S_ISVTX;
    463      1.1  mrg #endif
    464      1.1  mrg       }
    465      1.1  mrg     else if (set_mode == 3)
    466      1.1  mrg       {
    467      1.1  mrg 	file_mode |= new_mode;
    468      1.1  mrg #if !defined (__MINGW32__) && !defined (__VXWORKS__)
    469      1.1  mrg 	if (rwxXstugo[5] && is_dir)
    470      1.1  mrg 	  file_mode |= S_ISVTX;
    471      1.1  mrg 	else if (!is_dir)
    472      1.1  mrg 	  file_mode &= ~S_ISVTX;
    473      1.1  mrg #endif
    474      1.1  mrg       }
    475      1.1  mrg   }
    476      1.1  mrg 
    477      1.1  mrg   return chmod (file, file_mode);
    478      1.1  mrg }
    479      1.1  mrg 
    480      1.1  mrg 
    481      1.1  mrg extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type);
    482      1.1  mrg export_proto(chmod_func);
    483      1.1  mrg 
    484      1.1  mrg int
    485      1.1  mrg chmod_func (char *name, char *mode, gfc_charlen_type name_len,
    486      1.1  mrg 	    gfc_charlen_type mode_len)
    487      1.1  mrg {
    488      1.1  mrg   char *cname = fc_strdup (name, name_len);
    489      1.1  mrg   int ret = chmod_internal (cname, mode, mode_len);
    490      1.1  mrg   free (cname);
    491      1.1  mrg   return ret;
    492      1.1  mrg }
    493      1.1  mrg 
    494      1.1  mrg 
    495      1.1  mrg extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4 *,
    496      1.1  mrg 			  gfc_charlen_type, gfc_charlen_type);
    497      1.1  mrg export_proto(chmod_i4_sub);
    498      1.1  mrg 
    499      1.1  mrg void
    500      1.1  mrg chmod_i4_sub (char *name, char *mode, GFC_INTEGER_4 * status,
    501      1.1  mrg 	      gfc_charlen_type name_len, gfc_charlen_type mode_len)
    502      1.1  mrg {
    503      1.1  mrg   int val;
    504      1.1  mrg 
    505      1.1  mrg   val = chmod_func (name, mode, name_len, mode_len);
    506      1.1  mrg   if (status)
    507      1.1  mrg     *status = val;
    508      1.1  mrg }
    509      1.1  mrg 
    510      1.1  mrg 
    511      1.1  mrg extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8 *,
    512      1.1  mrg 			  gfc_charlen_type, gfc_charlen_type);
    513      1.1  mrg export_proto(chmod_i8_sub);
    514      1.1  mrg 
    515      1.1  mrg void
    516      1.1  mrg chmod_i8_sub (char *name, char *mode, GFC_INTEGER_8 * status,
    517      1.1  mrg 	      gfc_charlen_type name_len, gfc_charlen_type mode_len)
    518      1.1  mrg {
    519      1.1  mrg   int val;
    520      1.1  mrg 
    521      1.1  mrg   val = chmod_func (name, mode, name_len, mode_len);
    522      1.1  mrg   if (status)
    523      1.1  mrg     *status = val;
    524      1.1  mrg }
    525      1.1  mrg 
    526      1.1  mrg #endif
    527