Home | History | Annotate | Line # | Download | only in intrinsics
chmod.c revision 1.1
      1  1.1  mrg /* Implementation of the CHMOD intrinsic.
      2  1.1  mrg    Copyright (C) 2006-2019 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  mrg   mode_t mode_mask, file_mode, new_mode;
     75  1.1  mrg   struct stat stat_buf;
     76  1.1  mrg 
     77  1.1  mrg   if (mode_len == 0)
     78  1.1  mrg     return 1;
     79  1.1  mrg 
     80  1.1  mrg   if (mode[0] >= '0' && mode[0] <= '9')
     81  1.1  mrg     {
     82  1.1  mrg       unsigned fmode;
     83  1.1  mrg       if (sscanf (mode, "%o", &fmode) != 1)
     84  1.1  mrg 	return 1;
     85  1.1  mrg       return chmod (file, (mode_t) fmode);
     86  1.1  mrg     }
     87  1.1  mrg 
     88  1.1  mrg   /* Read the current file mode. */
     89  1.1  mrg   if (stat (file, &stat_buf))
     90  1.1  mrg     return 1;
     91  1.1  mrg 
     92  1.1  mrg   file_mode = stat_buf.st_mode & ~S_IFMT;
     93  1.1  mrg #ifndef __MINGW32__
     94  1.1  mrg   is_dir = stat_buf.st_mode & S_IFDIR;
     95  1.1  mrg #endif
     96  1.1  mrg 
     97  1.1  mrg #ifdef HAVE_UMASK
     98  1.1  mrg   /* Obtain the umask without distroying the setting.  */
     99  1.1  mrg   mode_mask = 0;
    100  1.1  mrg   mode_mask = umask (mode_mask);
    101  1.1  mrg   (void) umask (mode_mask);
    102  1.1  mrg #else
    103  1.1  mrg   honor_umask = false;
    104  1.1  mrg #endif
    105  1.1  mrg 
    106  1.1  mrg   for (gfc_charlen_type i = 0; i < mode_len; i++)
    107  1.1  mrg     {
    108  1.1  mrg       if (!continue_clause)
    109  1.1  mrg 	{
    110  1.1  mrg 	  ugo[0] = false;
    111  1.1  mrg 	  ugo[1] = false;
    112  1.1  mrg 	  ugo[2] = false;
    113  1.1  mrg #ifdef HAVE_UMASK
    114  1.1  mrg 	  honor_umask = true;
    115  1.1  mrg #endif
    116  1.1  mrg 	}
    117  1.1  mrg       continue_clause = false;
    118  1.1  mrg       rwxXstugo[0] = false;
    119  1.1  mrg       rwxXstugo[1] = false;
    120  1.1  mrg       rwxXstugo[2] = false;
    121  1.1  mrg       rwxXstugo[3] = false;
    122  1.1  mrg       rwxXstugo[4] = false;
    123  1.1  mrg       rwxXstugo[5] = false;
    124  1.1  mrg       rwxXstugo[6] = false;
    125  1.1  mrg       rwxXstugo[7] = false;
    126  1.1  mrg       rwxXstugo[8] = false;
    127  1.1  mrg       part = 0;
    128  1.1  mrg       set_mode = -1;
    129  1.1  mrg       for (; i < mode_len; i++)
    130  1.1  mrg 	{
    131  1.1  mrg 	  switch (mode[i])
    132  1.1  mrg 	    {
    133  1.1  mrg 	    /* User setting: a[ll]/u[ser]/g[roup]/o[ther].  */
    134  1.1  mrg 	    case 'a':
    135  1.1  mrg 	      if (part > 1)
    136  1.1  mrg 		return 1;
    137  1.1  mrg 	      ugo[0] = true;
    138  1.1  mrg 	      ugo[1] = true;
    139  1.1  mrg 	      ugo[2] = true;
    140  1.1  mrg 	      part = 1;
    141  1.1  mrg #ifdef HAVE_UMASK
    142  1.1  mrg 	      honor_umask = false;
    143  1.1  mrg #endif
    144  1.1  mrg 	      break;
    145  1.1  mrg 	    case 'u':
    146  1.1  mrg 	      if (part == 2)
    147  1.1  mrg 		{
    148  1.1  mrg 		  rwxXstugo[6] = true;
    149  1.1  mrg 		  part = 4;
    150  1.1  mrg 		  break;
    151  1.1  mrg 		}
    152  1.1  mrg 	      if (part > 1)
    153  1.1  mrg 		return 1;
    154  1.1  mrg 	      ugo[0] = true;
    155  1.1  mrg 	      part = 1;
    156  1.1  mrg #ifdef HAVE_UMASK
    157  1.1  mrg 	      honor_umask = false;
    158  1.1  mrg #endif
    159  1.1  mrg 	      break;
    160  1.1  mrg 	    case 'g':
    161  1.1  mrg 	      if (part == 2)
    162  1.1  mrg 		{
    163  1.1  mrg 		  rwxXstugo[7] = true;
    164  1.1  mrg 		  part = 4;
    165  1.1  mrg 		  break;
    166  1.1  mrg 		}
    167  1.1  mrg 	      if (part > 1)
    168  1.1  mrg 		return 1;
    169  1.1  mrg        	      ugo[1] = true;
    170  1.1  mrg 	      part = 1;
    171  1.1  mrg #ifdef HAVE_UMASK
    172  1.1  mrg 	      honor_umask = false;
    173  1.1  mrg #endif
    174  1.1  mrg 	      break;
    175  1.1  mrg 	    case 'o':
    176  1.1  mrg 	      if (part == 2)
    177  1.1  mrg 		{
    178  1.1  mrg 		  rwxXstugo[8] = true;
    179  1.1  mrg 		  part = 4;
    180  1.1  mrg 		  break;
    181  1.1  mrg 		}
    182  1.1  mrg 	      if (part > 1)
    183  1.1  mrg 		return 1;
    184  1.1  mrg 	      ugo[2] = true;
    185  1.1  mrg 	      part = 1;
    186  1.1  mrg #ifdef HAVE_UMASK
    187  1.1  mrg 	      honor_umask = false;
    188  1.1  mrg #endif
    189  1.1  mrg 	      break;
    190  1.1  mrg 
    191  1.1  mrg 	    /* Mode setting: =+-.  */
    192  1.1  mrg 	    case '=':
    193  1.1  mrg 	      if (part > 2)
    194  1.1  mrg 		{
    195  1.1  mrg 		  continue_clause = true;
    196  1.1  mrg 		  i--;
    197  1.1  mrg 		  part = 2;
    198  1.1  mrg 		  goto clause_done;
    199  1.1  mrg 		}
    200  1.1  mrg 	      set_mode = 1;
    201  1.1  mrg 	      part = 2;
    202  1.1  mrg 	      break;
    203  1.1  mrg 
    204  1.1  mrg 	    case '-':
    205  1.1  mrg 	      if (part > 2)
    206  1.1  mrg 		{
    207  1.1  mrg 		  continue_clause = true;
    208  1.1  mrg 		  i--;
    209  1.1  mrg 		  part = 2;
    210  1.1  mrg 		  goto clause_done;
    211  1.1  mrg 		}
    212  1.1  mrg 	      set_mode = 2;
    213  1.1  mrg 	      part = 2;
    214  1.1  mrg 	      break;
    215  1.1  mrg 
    216  1.1  mrg 	    case '+':
    217  1.1  mrg 	      if (part > 2)
    218  1.1  mrg 		{
    219  1.1  mrg 		  continue_clause = true;
    220  1.1  mrg 		  i--;
    221  1.1  mrg 		  part = 2;
    222  1.1  mrg 		  goto clause_done;
    223  1.1  mrg 		}
    224  1.1  mrg 	      set_mode = 3;
    225  1.1  mrg 	      part = 2;
    226  1.1  mrg 	      break;
    227  1.1  mrg 
    228  1.1  mrg 	    /* Permissions: rwxXst - for ugo see above.  */
    229  1.1  mrg 	    case 'r':
    230  1.1  mrg 	      if (part != 2 && part != 3)
    231  1.1  mrg 		return 1;
    232  1.1  mrg 	      rwxXstugo[0] = true;
    233  1.1  mrg 	      part = 3;
    234  1.1  mrg 	      break;
    235  1.1  mrg 
    236  1.1  mrg 	    case 'w':
    237  1.1  mrg 	      if (part != 2 && part != 3)
    238  1.1  mrg 		return 1;
    239  1.1  mrg 	      rwxXstugo[1] = true;
    240  1.1  mrg 	      part = 3;
    241  1.1  mrg 	      break;
    242  1.1  mrg 
    243  1.1  mrg 	    case 'x':
    244  1.1  mrg 	      if (part != 2 && part != 3)
    245  1.1  mrg 		return 1;
    246  1.1  mrg 	      rwxXstugo[2] = true;
    247  1.1  mrg 	      part = 3;
    248  1.1  mrg 	      break;
    249  1.1  mrg 
    250  1.1  mrg 	    case 'X':
    251  1.1  mrg 	      if (part != 2 && part != 3)
    252  1.1  mrg 		return 1;
    253  1.1  mrg 	      rwxXstugo[3] = true;
    254  1.1  mrg 	      part = 3;
    255  1.1  mrg 	      break;
    256  1.1  mrg 
    257  1.1  mrg 	    case 's':
    258  1.1  mrg 	      if (part != 2 && part != 3)
    259  1.1  mrg 		return 1;
    260  1.1  mrg 	      rwxXstugo[4] = true;
    261  1.1  mrg 	      part = 3;
    262  1.1  mrg 	      break;
    263  1.1  mrg 
    264  1.1  mrg 	    case 't':
    265  1.1  mrg 	      if (part != 2 && part != 3)
    266  1.1  mrg 		return 1;
    267  1.1  mrg 	      rwxXstugo[5] = true;
    268  1.1  mrg 	      part = 3;
    269  1.1  mrg 	      break;
    270  1.1  mrg 
    271  1.1  mrg 	    /* Tailing blanks are valid in Fortran.  */
    272  1.1  mrg 	    case ' ':
    273  1.1  mrg 	      for (i++; i < mode_len; i++)
    274  1.1  mrg 		if (mode[i] != ' ')
    275  1.1  mrg 		  break;
    276  1.1  mrg 	      if (i != mode_len)
    277  1.1  mrg 		return 1;
    278  1.1  mrg 	      goto clause_done;
    279  1.1  mrg 
    280  1.1  mrg 	    case ',':
    281  1.1  mrg 	      goto clause_done;
    282  1.1  mrg 
    283  1.1  mrg 	    default:
    284  1.1  mrg 	      return 1;
    285  1.1  mrg 	    }
    286  1.1  mrg 	}
    287  1.1  mrg 
    288  1.1  mrg clause_done:
    289  1.1  mrg       if (part < 2)
    290  1.1  mrg 	return 1;
    291  1.1  mrg 
    292  1.1  mrg       new_mode = 0;
    293  1.1  mrg 
    294  1.1  mrg #ifdef __MINGW32__
    295  1.1  mrg 
    296  1.1  mrg       /* Read. */
    297  1.1  mrg       if (rwxXstugo[0] && (ugo[0] || honor_umask))
    298  1.1  mrg 	new_mode |= _S_IREAD;
    299  1.1  mrg 
    300  1.1  mrg       /* Write. */
    301  1.1  mrg       if (rwxXstugo[1] && (ugo[0] || honor_umask))
    302  1.1  mrg 	new_mode |= _S_IWRITE;
    303  1.1  mrg 
    304  1.1  mrg #else
    305  1.1  mrg 
    306  1.1  mrg       /* Read. */
    307  1.1  mrg       if (rwxXstugo[0])
    308  1.1  mrg 	{
    309  1.1  mrg 	  if (ugo[0] || honor_umask)
    310  1.1  mrg 	    new_mode |= S_IRUSR;
    311  1.1  mrg 	  if (ugo[1] || honor_umask)
    312  1.1  mrg 	    new_mode |= S_IRGRP;
    313  1.1  mrg 	  if (ugo[2] || honor_umask)
    314  1.1  mrg 	    new_mode |= S_IROTH;
    315  1.1  mrg 	}
    316  1.1  mrg 
    317  1.1  mrg       /* Write.  */
    318  1.1  mrg       if (rwxXstugo[1])
    319  1.1  mrg 	{
    320  1.1  mrg 	  if (ugo[0] || honor_umask)
    321  1.1  mrg 	    new_mode |= S_IWUSR;
    322  1.1  mrg 	  if (ugo[1] || honor_umask)
    323  1.1  mrg 	    new_mode |= S_IWGRP;
    324  1.1  mrg 	  if (ugo[2] || honor_umask)
    325  1.1  mrg 	    new_mode |= S_IWOTH;
    326  1.1  mrg 	}
    327  1.1  mrg 
    328  1.1  mrg       /* Execute. */
    329  1.1  mrg       if (rwxXstugo[2])
    330  1.1  mrg 	{
    331  1.1  mrg 	  if (ugo[0] || honor_umask)
    332  1.1  mrg 	    new_mode |= S_IXUSR;
    333  1.1  mrg 	  if (ugo[1] || honor_umask)
    334  1.1  mrg 	    new_mode |= S_IXGRP;
    335  1.1  mrg 	  if (ugo[2] || honor_umask)
    336  1.1  mrg 	    new_mode |= S_IXOTH;
    337  1.1  mrg 	}
    338  1.1  mrg 
    339  1.1  mrg       /* 'X' execute.  */
    340  1.1  mrg       if (rwxXstugo[3]
    341  1.1  mrg 	  && (is_dir || (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
    342  1.1  mrg 	new_mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
    343  1.1  mrg 
    344  1.1  mrg       /* 's'.  */
    345  1.1  mrg       if (rwxXstugo[4])
    346  1.1  mrg 	{
    347  1.1  mrg 	  if (ugo[0] || honor_umask)
    348  1.1  mrg 	    new_mode |= S_ISUID;
    349  1.1  mrg 	  if (ugo[1] || honor_umask)
    350  1.1  mrg 	    new_mode |= S_ISGID;
    351  1.1  mrg 	}
    352  1.1  mrg 
    353  1.1  mrg       /* As original 'u'.  */
    354  1.1  mrg       if (rwxXstugo[6])
    355  1.1  mrg 	{
    356  1.1  mrg 	  if (ugo[1] || honor_umask)
    357  1.1  mrg 	    {
    358  1.1  mrg 	      if (file_mode & S_IRUSR)
    359  1.1  mrg 		new_mode |= S_IRGRP;
    360  1.1  mrg 	      if (file_mode & S_IWUSR)
    361  1.1  mrg 		new_mode |= S_IWGRP;
    362  1.1  mrg 	      if (file_mode & S_IXUSR)
    363  1.1  mrg 		new_mode |= S_IXGRP;
    364  1.1  mrg 	    }
    365  1.1  mrg 	  if (ugo[2] || honor_umask)
    366  1.1  mrg 	    {
    367  1.1  mrg 	      if (file_mode & S_IRUSR)
    368  1.1  mrg 		new_mode |= S_IROTH;
    369  1.1  mrg 	      if (file_mode & S_IWUSR)
    370  1.1  mrg 		new_mode |= S_IWOTH;
    371  1.1  mrg 	      if (file_mode & S_IXUSR)
    372  1.1  mrg 		new_mode |= S_IXOTH;
    373  1.1  mrg 	    }
    374  1.1  mrg 	}
    375  1.1  mrg 
    376  1.1  mrg       /* As original 'g'.  */
    377  1.1  mrg       if (rwxXstugo[7])
    378  1.1  mrg 	{
    379  1.1  mrg 	  if (ugo[0] || honor_umask)
    380  1.1  mrg 	    {
    381  1.1  mrg 	      if (file_mode & S_IRGRP)
    382  1.1  mrg 		new_mode |= S_IRUSR;
    383  1.1  mrg 	      if (file_mode & S_IWGRP)
    384  1.1  mrg 		new_mode |= S_IWUSR;
    385  1.1  mrg 	      if (file_mode & S_IXGRP)
    386  1.1  mrg 		new_mode |= S_IXUSR;
    387  1.1  mrg 	    }
    388  1.1  mrg 	  if (ugo[2] || honor_umask)
    389  1.1  mrg 	    {
    390  1.1  mrg 	      if (file_mode & S_IRGRP)
    391  1.1  mrg 		new_mode |= S_IROTH;
    392  1.1  mrg 	      if (file_mode & S_IWGRP)
    393  1.1  mrg 		new_mode |= S_IWOTH;
    394  1.1  mrg 	      if (file_mode & S_IXGRP)
    395  1.1  mrg 		new_mode |= S_IXOTH;
    396  1.1  mrg 	    }
    397  1.1  mrg 	}
    398  1.1  mrg 
    399  1.1  mrg       /* As original 'o'.  */
    400  1.1  mrg       if (rwxXstugo[8])
    401  1.1  mrg 	{
    402  1.1  mrg 	  if (ugo[0] || honor_umask)
    403  1.1  mrg 	    {
    404  1.1  mrg 	      if (file_mode & S_IROTH)
    405  1.1  mrg 		new_mode |= S_IRUSR;
    406  1.1  mrg 	      if (file_mode & S_IWOTH)
    407  1.1  mrg 		new_mode |= S_IWUSR;
    408  1.1  mrg 	      if (file_mode & S_IXOTH)
    409  1.1  mrg 		new_mode |= S_IXUSR;
    410  1.1  mrg 	    }
    411  1.1  mrg 	  if (ugo[1] || honor_umask)
    412  1.1  mrg 	    {
    413  1.1  mrg 	      if (file_mode & S_IROTH)
    414  1.1  mrg 		new_mode |= S_IRGRP;
    415  1.1  mrg 	      if (file_mode & S_IWOTH)
    416  1.1  mrg 		new_mode |= S_IWGRP;
    417  1.1  mrg 	      if (file_mode & S_IXOTH)
    418  1.1  mrg 		new_mode |= S_IXGRP;
    419  1.1  mrg 	    }
    420  1.1  mrg 	}
    421  1.1  mrg #endif  /* __MINGW32__ */
    422  1.1  mrg 
    423  1.1  mrg #ifdef HAVE_UMASK
    424  1.1  mrg     if (honor_umask)
    425  1.1  mrg       new_mode &= ~mode_mask;
    426  1.1  mrg #endif
    427  1.1  mrg 
    428  1.1  mrg     if (set_mode == 1)
    429  1.1  mrg       {
    430  1.1  mrg #ifdef __MINGW32__
    431  1.1  mrg 	if (ugo[0] || honor_umask)
    432  1.1  mrg 	  file_mode = (file_mode & ~(_S_IWRITE | _S_IREAD))
    433  1.1  mrg 		      | (new_mode & (_S_IWRITE | _S_IREAD));
    434  1.1  mrg #else
    435  1.1  mrg 	/* Set '='.  */
    436  1.1  mrg 	if ((ugo[0] || honor_umask) && !rwxXstugo[6])
    437  1.1  mrg 	  file_mode = (file_mode & ~(S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR))
    438  1.1  mrg 		      | (new_mode & (S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR));
    439  1.1  mrg 	if ((ugo[1] || honor_umask) && !rwxXstugo[7])
    440  1.1  mrg 	  file_mode = (file_mode & ~(S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP))
    441  1.1  mrg 		      | (new_mode & (S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP));
    442  1.1  mrg 	if ((ugo[2] || honor_umask) && !rwxXstugo[8])
    443  1.1  mrg 	  file_mode = (file_mode & ~(S_IROTH | S_IWOTH | S_IXOTH))
    444  1.1  mrg 		      | (new_mode & (S_IROTH | S_IWOTH | S_IXOTH));
    445  1.1  mrg #ifndef __VXWORKS__
    446  1.1  mrg 	if (is_dir && rwxXstugo[5])
    447  1.1  mrg 	  file_mode |= S_ISVTX;
    448  1.1  mrg 	else if (!is_dir)
    449  1.1  mrg 	  file_mode &= ~S_ISVTX;
    450  1.1  mrg #endif
    451  1.1  mrg #endif
    452  1.1  mrg       }
    453  1.1  mrg     else if (set_mode == 2)
    454  1.1  mrg       {
    455  1.1  mrg 	/* Clear '-'.  */
    456  1.1  mrg 	file_mode &= ~new_mode;
    457  1.1  mrg #if !defined( __MINGW32__) && !defined (__VXWORKS__)
    458  1.1  mrg 	if (rwxXstugo[5] || !is_dir)
    459  1.1  mrg 	  file_mode &= ~S_ISVTX;
    460  1.1  mrg #endif
    461  1.1  mrg       }
    462  1.1  mrg     else if (set_mode == 3)
    463  1.1  mrg       {
    464  1.1  mrg 	file_mode |= new_mode;
    465  1.1  mrg #if !defined (__MINGW32__) && !defined (__VXWORKS__)
    466  1.1  mrg 	if (rwxXstugo[5] && is_dir)
    467  1.1  mrg 	  file_mode |= S_ISVTX;
    468  1.1  mrg 	else if (!is_dir)
    469  1.1  mrg 	  file_mode &= ~S_ISVTX;
    470  1.1  mrg #endif
    471  1.1  mrg       }
    472  1.1  mrg   }
    473  1.1  mrg 
    474  1.1  mrg   return chmod (file, file_mode);
    475  1.1  mrg }
    476  1.1  mrg 
    477  1.1  mrg 
    478  1.1  mrg extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type);
    479  1.1  mrg export_proto(chmod_func);
    480  1.1  mrg 
    481  1.1  mrg int
    482  1.1  mrg chmod_func (char *name, char *mode, gfc_charlen_type name_len,
    483  1.1  mrg 	    gfc_charlen_type mode_len)
    484  1.1  mrg {
    485  1.1  mrg   char *cname = fc_strdup (name, name_len);
    486  1.1  mrg   int ret = chmod_internal (cname, mode, mode_len);
    487  1.1  mrg   free (cname);
    488  1.1  mrg   return ret;
    489  1.1  mrg }
    490  1.1  mrg 
    491  1.1  mrg 
    492  1.1  mrg extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4 *,
    493  1.1  mrg 			  gfc_charlen_type, gfc_charlen_type);
    494  1.1  mrg export_proto(chmod_i4_sub);
    495  1.1  mrg 
    496  1.1  mrg void
    497  1.1  mrg chmod_i4_sub (char *name, char *mode, GFC_INTEGER_4 * status,
    498  1.1  mrg 	      gfc_charlen_type name_len, gfc_charlen_type mode_len)
    499  1.1  mrg {
    500  1.1  mrg   int val;
    501  1.1  mrg 
    502  1.1  mrg   val = chmod_func (name, mode, name_len, mode_len);
    503  1.1  mrg   if (status)
    504  1.1  mrg     *status = val;
    505  1.1  mrg }
    506  1.1  mrg 
    507  1.1  mrg 
    508  1.1  mrg extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8 *,
    509  1.1  mrg 			  gfc_charlen_type, gfc_charlen_type);
    510  1.1  mrg export_proto(chmod_i8_sub);
    511  1.1  mrg 
    512  1.1  mrg void
    513  1.1  mrg chmod_i8_sub (char *name, char *mode, GFC_INTEGER_8 * status,
    514  1.1  mrg 	      gfc_charlen_type name_len, gfc_charlen_type mode_len)
    515  1.1  mrg {
    516  1.1  mrg   int val;
    517  1.1  mrg 
    518  1.1  mrg   val = chmod_func (name, mode, name_len, mode_len);
    519  1.1  mrg   if (status)
    520  1.1  mrg     *status = val;
    521  1.1  mrg }
    522  1.1  mrg 
    523  1.1  mrg #endif
    524