Mail Archives: djgpp-workers/2003/02/28/05:35:19
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 -