delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/03/01/15:26:50

Date: Sat, 01 Mar 2003 17:52:43 +0000
From: "Richard Dawe" <rich AT phekda DOT freeserve DOT co DOT uk>
Sender: rich AT phekda DOT freeserve DOT co DOT uk
To: djgpp-workers AT delorie DOT com
X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: fchmod, revision 5 [PATCH]
Message-Id: <E18pB7S-0000nr-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Here is revision 5 of the patch to add fchmod to DJGPP. The only
change over the previous revision is the handling of pipes.
It now returns -1 and errno == EINVAL for pipes. Pipes are:

* file descriptors with the pipe flag set in their fd_props;
* a standard handle (stdin, stdout, stderr) which has been redirected.

Still needs testing with Windows 2000/XP... (I don't have either
of these OSes.)

Bye, Rich =]


Index: include/sys/stat.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/stat.h,v
retrieving revision 1.8
diff -p -c -3 -r1.8 stat.h
*** include/sys/stat.h	4 Feb 2003 20:25:54 -0000	1.8
--- include/sys/stat.h	1 Mar 2003 17:45:26 -0000
*************** struct stat {
*** 63,68 ****
--- 63,69 ----
  };
  
  int	chmod(const char *_path, mode_t _mode);
+ int	fchmod(int _fildes, mode_t _mode);
  int	fstat(int _fildes, struct stat *_buf);
  int	mkdir(const char *_path, mode_t _mode);
  int	mkfifo(const char *_path, mode_t _mode);
Index: include/sys/fsext.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/fsext.h,v
retrieving revision 1.9
diff -p -c -3 -r1.9 fsext.h
*** include/sys/fsext.h	24 Feb 2003 21:05:16 -0000	1.9
--- include/sys/fsext.h	1 Mar 2003 17:45:32 -0000
*************** typedef enum {
*** 45,51 ****
    __FSEXT_symlink,
    __FSEXT_fchown,
    __FSEXT_chmod,
!   __FSEXT_chown
  } __FSEXT_Fnumber;
  
  /* _ready gets passed a fd and should return a mask of these,
--- 45,52 ----
    __FSEXT_symlink,
    __FSEXT_fchown,
    __FSEXT_chmod,
!   __FSEXT_chown,
!   __FSEXT_fchmod
  } __FSEXT_Fnumber;
  
  /* _ready gets passed a fd and should return a mask of these,
Index: src/libc/posix/sys/stat/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/makefile,v
retrieving revision 1.4
diff -p -c -3 -r1.4 makefile
*** src/libc/posix/sys/stat/makefile	17 Oct 2002 23:00:25 -0000	1.4
--- src/libc/posix/sys/stat/makefile	1 Mar 2003 17:45:32 -0000
***************
*** 1,9 ****
--- 1,11 ----
+ # Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
  TOP=../../..
  
  SRC += chmod.c
+ SRC += fchmod.c
  SRC += filelen.c
  SRC += fixpath.c
  SRC += fstat.c
Index: src/libc/posix/sys/stat/chmod.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/chmod.txh,v
retrieving revision 1.4
diff -p -c -3 -r1.4 chmod.txh
*** src/libc/posix/sys/stat/chmod.txh	24 Feb 2003 21:05:46 -0000	1.4
--- src/libc/posix/sys/stat/chmod.txh	1 Mar 2003 17:45:37 -0000
*************** the following:
*** 18,32 ****
  
  @item S_IRUSR
  
! Make the file readable
  
  @item S_IWUSR
  
! Make the file writable
  
  @end table
  
! Other @code{S_I*} values could be included, but they will be ignored.
  
  This function can be hooked by File System Extensions
  (@pxref{File System Extensions}).
--- 18,58 ----
  
  @item S_IRUSR
  
! Make the file readable for the owner.
  
  @item S_IWUSR
  
! Make the file writable for the owner.
! 
! @item S_IRGRP
! 
! Make the file readable for the group.
! 
! @item S_IWGRP
! 
! Make the file writeable for the group.
! 
! @item S_IROTH
! 
! Make the file readable for the world.
! 
! @item S_IWOTH
! 
! Make the file writeable for the world.
  
  @end table
  
! Some @code{S_I*} constants are ignored for regular files:
! 
! @itemize @bullet
! @item
! @code{S_I*GRP} and @code{S_I*OTH} are ignored, because DOS/Windows
! has no concept of ownership, so all files are considered to belong
! to the user;
! 
! @item
! @code{S_IR*} are ignored, because files are always readable on DOS/Windows.
! @end itemize
  
  This function can be hooked by File System Extensions
  (@pxref{File System Extensions}).
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.144
diff -p -c -3 -r1.144 wc204.txi
*** src/docs/kb/wc204.txi	1 Mar 2003 14:38:26 -0000	1.144
--- src/docs/kb/wc204.txi	1 Mar 2003 17:45:47 -0000
*************** will inline to a single instruction when
*** 897,903 ****
  @code{chmod} and @code{chown} can now be hooked by File System Extensions.
  
  @findex isatty AT r{, and invalid file descriptors}
- 
  The function @code{isatty} now checks whether the file descriptor
  passed to it is a valid.  If not, it will fail and set @code{errno}
  to @code{EBADF}.
--- 897,902 ----
*************** to @code{EBADF}.
*** 905,907 ****
--- 904,909 ----
  @findex perror
  The function @code{perror} no longer prints a colon and blank if called
  with a null pointer or a pointer to a null string.
+ 
+ @findex fchmod
+ The function @code{fchmod} was added.
Index: tests/libc/posix/sys/stat/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/posix/sys/stat/makefile,v
retrieving revision 1.4
diff -p -c -3 -r1.4 makefile
*** tests/libc/posix/sys/stat/makefile	22 Aug 2000 18:57:32 -0000	1.4
--- tests/libc/posix/sys/stat/makefile	1 Mar 2003 17:45:52 -0000
*************** SRC += stat.c
*** 9,13 ****
--- 9,14 ----
  SRC += stat1.c
  SRC += svsf.c
  SRC += symstat.c
+ SRC += t-fchmod.c
  
  include $(TOP)/../makefile.inc
Index: src/libc/fsext/fse_zero.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/fsext/fse_zero.c,v
retrieving revision 1.4
diff -p -c -3 -r1.4 fse_zero.c
*** src/libc/fsext/fse_zero.c	24 Feb 2003 21:07:26 -0000	1.4
--- src/libc/fsext/fse_zero.c	1 Mar 2003 17:46:01 -0000
*************** dev_fsext (__FSEXT_Fnumber n, int *rv, v
*** 576,581 ****
--- 576,601 ----
      *rv   = -1;
      break;
  
+   case __FSEXT_fchmod:
+     fd    = va_arg(args, int);
+     mode  = va_arg(args, mode_t);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Get context */
+     data = (DEV_DATA *) __FSEXT_get_data(fd);
+     if (data == NULL) {
+       errno = EBADF;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* The zero device cannot have its mode changed. */
+     errno = EPERM;
+     *rv   = -1;
+     break;
+ 
    case __FSEXT_chown:
      filename = va_arg(args, char *);
      owner    = va_arg(args, uid_t);
Index: tests/libc/fsext/tzero.c
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/fsext/tzero.c,v
retrieving revision 1.3
diff -p -c -3 -r1.3 tzero.c
*** tests/libc/fsext/tzero.c	24 Feb 2003 21:07:26 -0000	1.3
--- tests/libc/fsext/tzero.c	1 Mar 2003 17:46:02 -0000
*************** main (int argc, char *argv[])
*** 431,436 ****
--- 431,455 ----
  
    close(fd);
  
+   /* - Check fchmod() fails - */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   n = fchmod(fd, S_IWUSR);
+   if (n >= 0) {
+     fprintf(stderr,
+ 	    "fchmod() succeeded in changing permissions of %s -"
+ 	    "it should fail\n",
+ 	    DEV_ZERO_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
    /* - Check fchown() - */
  
    /* fchown() should behave the same way for /dev/zero as it does for
*** /dev/null	Sat Mar  1 17:49:33 2003
--- src/libc/posix/sys/stat/fchmod.c	Sat Mar  1 17:33:12 2003
***************
*** 0 ****
--- 1,104 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ #include <libc/stubs.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <errno.h>
+ #include <io.h>
+ #include <sys/fsext.h>
+ #include <libc/fsexthlp.h>
+ #include <libc/fd_props.h>
+ #include <libc/getdinfo.h>
+ #include <fcntl.h>
+ #include <dpmi.h>
+ #include <go32.h>
+ #include <libc/farptrgs.h>
+ 
+ static int
+ get_current_mode (const int fd)
+ {
+   __dpmi_regs r;
+   int         mode = 0; /* Fail by default */
+ 
+   if (_USE_LFN) {
+     r.x.ax = 0x71a6; /* File info by handle */
+     r.x.bx = fd;
+     r.x.ds = __tb >> 4;
+     r.x.dx = 0;
+ 
+     __dpmi_int(0x21, &r);
+ 
+     if ((r.x.flags & 1) == 0) {
+       int attr = _farpeekl(_dos_ds, __tb);
+ 
+       mode = S_IRUSR; /* Files are always readable. */
+       if ((attr & 1) == 0)
+ 	mode |= S_IWUSR;
+     }
+   }
+ 
+   return(mode);
+ }
+ 
+ int
+ fchmod (int fd, mode_t mode)
+ {
+   __FSEXT_Function    *func     = __FSEXT_get_function(fd);
+   const char          *filename = __get_fd_name(fd);
+   const unsigned long  flags    = __get_fd_flags(fd);
+   int                  dev_info;
+   int                  current_mode;
+   int                  rv;
+ 
+   if (   func
+       && __FSEXT_func_wrapper(func, __FSEXT_fchmod, &rv, fd, mode))
+       return(rv);
+ 
+   /* Check that it's a valid file descriptor. */
+   dev_info = _get_dev_info(fd);
+   if (dev_info == -1)
+     return(-1);
+ 
+   /* Is this a pipe? Disallow changing the mode on pipes. */
+   if (flags & FILE_DESC_PIPE) {
+     errno = EINVAL;
+     return(-1);
+   }
+ 
+   /* Is this a redirected standard handle: stdin, stdout, stderr?
+    * I.e.: are the standard handles pipes? Disallow changing the mode
+    * on pipes. */
+   switch(fd) {
+   case STDIN_FILENO:
+   case STDOUT_FILENO:
+   case STDERR_FILENO:
+     if (isatty(fd) == 0) {
+       errno = EINVAL;
+       return(-1);
+     }
+     break;
+ 
+   default:
+     break;
+   }
+ 
+   /* Is this a character device? If so, silently ignore the request. */
+   if (dev_info & _DEV_CDEV)
+     return 0;
+ 
+   /* Get the current mode. If it's the same as those requested,
+    * just return. */
+   /* NB: Only implemented toggle is write/nowrite */
+   current_mode = get_current_mode(fd);
+   if (current_mode && (current_mode == (mode & (S_IRUSR|S_IWUSR))))
+     return 0;
+ 
+   /* It's not a device and we don't have the filename. So we can only
+    * fail. */
+   if (filename == NULL) {
+     errno = ENOSYS;
+     return(-1);
+   }
+ 
+   return(chmod(filename, mode));
+ }
*** /dev/null	Sat Mar  1 17:49:33 2003
--- src/libc/posix/sys/stat/fchmod.txh	Fri Feb 28 10:34:08 2003
***************
*** 0 ****
--- 1,63 ----
+ @node fchmod, file system
+ @findex fchmod
+ @subheading Syntax
+ 
+ @example
+ #include <sys/stat.h>
+ 
+ int fchmod(int fd, mode_t mode);
+ @end example
+ 
+ @subheading Description
+ 
+ This function changes the mode (writable or write-only) of the file
+ opened under the file descriptor @var{fd}.  The value of @var{mode}
+ can be a combination of one or more of the @code{S_I*} constants
+ described in the description of the @code{chmod} function (@pxref{chmod}).
+ 
+ Some @code{S_I*} constants are ignored for regular files:
+ 
+ @itemize @bullet
+ @item
+ @code{S_I*GRP} and @code{S_I*OTH} are ignored, because DOS/Windows
+ has no concept of ownership, so all files are considered to belong
+ to the user;
+ 
+ @item
+ @code{S_IR*} are ignored, because files are always readable on DOS/Windows.
+ @end itemize
+ 
+ @code{fchmod} will always succeed for character devices, but the mode
+ will be ignored.
+ 
+ @code{fchmod} may not be able to change the mode of files that have been
+ opened using low-level methods.  High-level methods for opening files
+ include the @code{fopen} (@pxref{fopen}) and @code{open} (@pxref{open})
+ functions.  Low-level methods include the @code{_open} (@pxref{_open})
+ and @code{_dos_open} (@pxref{_dos_open}) functions.  In particular,
+ redirected handles cannot have their mode changed with @code{fchmod}.
+ 
+ @code{fchmod} may also not work as expected under DOS.  For instance,
+ if a file is opened as read-write, then changed to read-only
+ with @code{fchmod}, but then written to, then the mode will not
+ be changed.
+ 
+ This function can be hooked by File System Extensions
+ (@pxref{File System Extensions}).
+ 
+ @subheading Return Value
+ 
+ Zero if the file exists and the mode was changed, else -1.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, posix
+ 
+ @subheading Example
+ 
+ @example
+ int fd;
+ 
+ fd = open("/tmp/dj.dat", O_RDWR);
+ fchmod(fd, S_IWUSR|S_IRUSR);
+ @end example
*** /dev/null	Sat Mar  1 17:49:33 2003
--- tests/libc/posix/sys/stat/t-fchmod.c	Sat Mar  1 17:37:34 2003
***************
*** 0 ****
--- 1,203 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <dos.h>
+ 
+ const char TEST_FILE[] = "t-fchmod.tst";
+ 
+ typedef struct {
+   FILE         *fp;
+   const char   *name;
+   const mode_t  mode;
+ } std_test_t;
+ 
+ /* Try setting the handles to the mode they should have anyway. */
+ std_test_t passing_std_tests[] = {
+   { stdin,  "stdin",  S_IRUSR },
+   { stdout, "stdout", S_IWUSR },
+   { stderr, "stderr", S_IWUSR },
+   { stdaux, "stdaux", S_IRUSR|S_IWUSR },
+   { stdprn, "stdprn", S_IWUSR },
+   { NULL, NULL, 0 }
+ };
+ 
+ /* Try setting the handles to the mode they shouldn't have. */
+ std_test_t failing_std_tests[] = {
+   { stdin,  "stdin",  S_IWUSR },
+   { stdout, "stdout", S_IRUSR },
+   { stderr, "stderr", S_IRUSR },
+ #if 0
+   { stdaux, "stdaux", 0 },
+   { stdprn, "stdprn", S_IRUSR },
+ #endif
+   { NULL, NULL, 0 }
+ };
+ 
+ static void
+ die (const char *prog_name)
+ {
+   perror(prog_name);
+   puts("FAIL");
+   exit(EXIT_FAILURE);
+ }
+ 
+ static int
+ check_read_only (const char *file)
+ {
+   if (access(file, R_OK))
+     {
+       printf("%s should be readable!\n", file);
+       return(0);
+     }
+ 
+   if (!access(file, W_OK))
+     {
+       printf("%s should not be writeable!\n", file);
+       return(0);
+     }
+ 
+   return(1);
+ }
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   int ok = 1;
+   int fd;
+   int fd_array[2];
+   int i;
+ 
+   /* - Standard handles - */
+ 
+   for (i = 0; passing_std_tests[i].fp != NULL; i++)
+     {
+       if (fchmod(fileno(passing_std_tests[i].fp),
+ 		 passing_std_tests[i].mode) < 0)
+ 	{
+ 	  perror(passing_std_tests[i].name);
+ 	  ok = 0;
+ 	}
+   }
+ 
+   for (i = 0; failing_std_tests[i].fp != NULL; i++)
+     {
+       int std_fd = fileno(failing_std_tests[i].fp);
+ 
+       if (   (fchmod(std_fd, failing_std_tests[i].mode) == 0)
+ 	  && !isatty(std_fd))
+ 	{
+ 	  printf("%s: Should not be able to set mode to 0%o\n",
+ 		 failing_std_tests[i].name, failing_std_tests[i].mode);
+ 	  ok = 0;
+ 	}
+     }
+ 
+   /* - Conventional file - */
+ 
+   /* Remove the test file, if it exists. */
+   if (!access(TEST_FILE, F_OK) && unlink(TEST_FILE))
+     die(argv[0]);
+ 
+   /* Create the file with read-write permissions. */
+   fd = open(TEST_FILE, O_BINARY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
+   if (fd < 0)
+     die(argv[0]);
+   if (close(fd) < 0)
+     die(argv[0]);
+ 
+   /* Check the permissions are read-write. */
+   if (access(TEST_FILE, R_OK) || access(TEST_FILE, W_OK))
+     {
+       printf("%s should be readable and writeable!\nFAIL\n", TEST_FILE);
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Re-open the file and change the permissions to read-only.
+    * Try writing to the file before and after. */
+   fd = open(TEST_FILE, O_BINARY|O_RDWR);
+   if (fd < 0)
+     die(argv[0]);
+ 
+   /* Try writing to the file. */
+   {
+     char wibble[] = "wibble-read-write";
+ 
+     if (write(fd, wibble, strlen(wibble)) < 0)
+       {
+ 	printf("Unable to write to read-write file %s\n", TEST_FILE);
+ 	perror(argv[0]);
+ 	ok = 0;
+       }
+   }
+ 
+   if (fchmod(fd, S_IRUSR) < 0)
+     die(argv[0]);
+ 
+   /* Check the permissions are read-only. */
+   if (!check_read_only(TEST_FILE))
+     ok = 0;
+ 
+   /* Try writing to the file. */
+   {
+     char wibble[] = "wibble-read-only";
+ 
+     if (write(fd, wibble, strlen(wibble)) < 0)
+       {
+ 	printf("Unable to write to read-only file %s\n", TEST_FILE);
+ 	perror(argv[0]);
+ 	ok = 0;
+       }
+   }
+ 
+   if (close(fd) < 0)
+     die(argv[0]);
+ 
+   /* Check the permissions are read-only. */
+   if (!check_read_only(TEST_FILE))
+     ok = 0;
+ 
+   /* - Bypass normal open calls to get a file handle. */
+   if (_dos_open(TEST_FILE, O_RDONLY, &fd) != 0)
+     die(argv[0]);
+ 
+   /* Test that fchmod just returns, when the file permissions are
+    * the same as the current and there is no filename in fd_props. */
+   if (fchmod(fd, S_IRUSR) < 0)
+     die(argv[0]);
+ 
+   /* Check that it fails, when we try different file permissions. */
+   if (fchmod(fd, S_IRUSR|S_IWUSR) >= 0)
+     {
+       printf("fchmod call should have failed: %s:%d!\n", __FILE__, __LINE__);
+       ok = 0;
+     }
+ 
+   if (_dos_close(fd) != 0)
+     die(argv[0]);
+ 
+   /* - Pipe - */
+   if (pipe(fd_array) < 0) {
+     puts("Unable to create pipe");
+     perror(argv[0]);
+     ok = 0;
+   } else {
+     if (fchmod(fd_array[0], S_IRUSR|S_IWUSR) >= 0)
+       {
+ 	printf("fchmod call should have failed: %s:%d!\n", __FILE__, __LINE__);
+ 	ok = 0;
+       }
+   }
+ 
+   /* - Done - */
+ 
+   if (!ok) {
+     puts("FAIL");
+     return(EXIT_FAILURE);
+   }
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019