delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/02/28/05:35:19

Date: Fri, 28 Feb 2003 10:37:50 +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 4 [PATCH]
Message-Id: <E18ohr8-0000Tb-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Here's revision 4 of the fchmod patch. Changes:

* check the return code of *close() in the test program;
* add notes about how fchmod may not work under DOS.

It still needs someone to test it on Win2k/XP...

Thanks, 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	28 Feb 2003 10:32:27 -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	28 Feb 2003 10:32:30 -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	28 Feb 2003 10:32:30 -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	28 Feb 2003 10:32:34 -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.142
diff -p -c -3 -r1.142 wc204.txi
*** src/docs/kb/wc204.txi	24 Feb 2003 21:06:42 -0000	1.142
--- src/docs/kb/wc204.txi	28 Feb 2003 10:32:39 -0000
*************** will inline to a single instruction when
*** 895,897 ****
--- 895,900 ----
  @cindex File System Extensions, and @code{chmod}
  @cindex File System Extensions, and @code{chown}
  @code{chmod} and @code{chown} can now be hooked by File System Extensions.
+ 
+ @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	28 Feb 2003 10:32:43 -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	28 Feb 2003 10:32:45 -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	28 Feb 2003 10:32:51 -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	Fri Feb 28 10:36:09 2003
--- src/libc/posix/sys/stat/fchmod.c	Tue Feb 25 12:13:44 2003
***************
*** 0 ****
--- 1,79 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ #include <libc/stubs.h>
+ #include <string.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);
+   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 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	Fri Feb 28 10:36:09 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	Fri Feb 28 10:36:09 2003
--- tests/libc/posix/sys/stat/t-fchmod.c	Wed Feb 26 17:25:24 2003
***************
*** 0 ****
--- 1,189 ----
+ #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 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]);
+ 
+   /* - 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