Date: Sun, 09 Jun 2002 21:20:41 +0100 From: "Richard Dawe" 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: PATCH: fcntl and F_GETFL, mark 3 Message-Id: Reply-To: djgpp-workers AT delorie DOT com Hello. Below is version 3 of the patch to add support for F_GETFL to fcntl(). The only change since version 2 is that there are notes saying that the SFT entry code does not work properly on Windows NT 4 - the open mode will always be reported as O_RDONLY. OK to commit? Thanks, bye, Rich =] Index: src/libc/posix/fcntl/fcntl.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/fcntl.c,v retrieving revision 1.7 diff -p -u -3 -r1.7 fcntl.c --- src/libc/posix/fcntl/fcntl.c 2001/06/12 12:42:42 1.7 +++ src/libc/posix/fcntl/fcntl.c 2002/06/09 20:11:50 @@ -1,3 +1,4 @@ +/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ @@ -14,6 +15,7 @@ #include #include #include +#include #include @@ -408,8 +410,52 @@ fcntl(int fd, int cmd, ...) case F_GETFL: { - return 0; /* FIXME: should use the data in the SFT, and the - FILE_DESC_APPEND flag in __fd_properties */ + unsigned long sft_entry_ptr; + unsigned char sft_open_flags; + int flags = 0; + + /* + * Use the data in the SFT. + * + * This seems to work on Windows 2000 and therefore probably works + * on Windows XP. It does not work on Windows NT 4, where the file + * will always appear to have been opened read-only. It's hard + * to distinguish Windows 2000 and Windows NT 4 with an LFN TSR, + * so we can't have a special case for Windows NT 4. + */ + sft_entry_ptr = _get_sft_entry_ptr(fd); + if (sft_entry_ptr) + { + /* Offset 2 in the SFT contains the open flags. */ + sft_open_flags = _farpeekw(_dos_ds, sft_entry_ptr + 2); + + switch(sft_open_flags & 0x7) + { + case 0: flags |= O_RDONLY; break; + case 1: flags |= O_WRONLY; break; + case 2: flags |= O_RDWR; break; + + default: + break; + } + } + else + { + /* If we've failed to get an SFT pointer, pretend that the file + * is read-write, since that's most likely to be correct. */ + flags |= O_RDWR; + } + + /* Check the FILE_DESC_APPEND flag in __fd_properties. */ + if (__has_fd_properties(fd)) + { + unsigned long fd_flags = __get_fd_flags(fd); + + if (fd_flags & FILE_DESC_APPEND) + flags |= O_APPEND; + } + + return flags; } Index: tests/libc/posix/fcntl/tfcntl.c =================================================================== RCS file: /cvs/djgpp/djgpp/tests/libc/posix/fcntl/tfcntl.c,v retrieving revision 1.1 diff -p -u -3 -r1.1 tfcntl.c --- tests/libc/posix/fcntl/tfcntl.c 2001/02/01 19:24:45 1.1 +++ tests/libc/posix/fcntl/tfcntl.c 2002/06/09 20:11:50 @@ -1,13 +1,14 @@ #include #include +#include #include #include +#include #include -#include #include #include -void prdoserr(int fd) { +static void prdoserr(int fd) { struct DOSERROR de; struct DOSERROR_STR se; int errsave; @@ -30,14 +31,59 @@ void prdoserr(int fd) { printf("Error Locus: %02X : %s\n",de.locus,se.locus_str); } +static const char *flags2str(const int flags) { + static char buf[256]; + int need_comma = 0; + + buf[0] = '\0'; + + switch(flags & O_ACCMODE) { + case O_RDONLY: strcat(buf, "O_RDONLY"); need_comma++; break; + case O_WRONLY: strcat(buf, "O_WRONLY"); need_comma++; break; + case O_RDWR: strcat(buf, "O_RDWR"); need_comma++; break; + + default: + break; + } + + if (flags & O_APPEND) { + if (need_comma) { + strcat(buf, ", "); + need_comma--; + } + + strcat(buf, "O_APPEND"); + need_comma++; + } + + if (flags & O_NONBLOCK) { + if (need_comma) { + strcat(buf, ", "); + need_comma--; + } + + strcat(buf, "O_NONBLOCK"); + need_comma++; + } + return(buf); +} + int main(void) { + int retval, fd; + #if defined(F_SETLK) && defined(F_SETLKW) struct flock fl; struct flock64 fl64; - int retval, fd; +#endif /* F_SETLK && F_SETLKW */ fd = open("tfcntl.c", O_RDONLY); + if (fd < 0) { + perror("tfcntl"); + return(EXIT_FAILURE); + } + +#if defined(F_SETLK) && defined(F_SETLKW) fl.l_type = F_RDLCK; fl.l_whence = SEEK_SET; fl.l_start = fl.l_len = 0; @@ -80,6 +126,7 @@ int main(void) { if ((retval < 0) && (errno != 0)) prdoserr(fd); /* F_SETLKW tests */ + puts("--- F_SETLKW tests ---"); errno = 0; fl.l_type = F_RDLCK; @@ -123,6 +170,7 @@ int main(void) { if ((retval < 0) && (errno != 0)) prdoserr(fd); /* FAT32 tests */ + puts("--- FAT32 tests ---"); errno = 0; fl64.l_type = F_RDLCK; @@ -153,6 +201,7 @@ int main(void) { if ((retval < 0) && (errno != 0)) prdoserr(fd); /* F_SETLKW64 tests */ + puts("--- F_SETLKW64 tests ---"); errno = 0; fl64.l_type = F_RDLCK; @@ -194,8 +243,10 @@ int main(void) { retval = fcntl(fd, F_GETLK64, &fl64); printf("F_GETLK64/F_RDLCK:retval=%d\n", retval); if ((retval < 0) && (errno != 0)) prdoserr(fd); +#endif /* F_SETLK && F_SETLKW */ /* Other function tests (non-lock-related) */ + puts("--- Other tests ---"); errno = 0; retval = fcntl(fd, F_GETFD); @@ -208,13 +259,73 @@ int main(void) { if ((retval < 0) && (errno != 0)) prdoserr(fd); errno = 0; + retval = fcntl(fd, F_GETFL); + printf("F_GETFL:retval=%04x = %s\n", retval, flags2str(retval)); + if ((retval < 0) && (errno != 0)) prdoserr(fd); + + close(fd); + + /* F_GETFL tests */ + puts("--- F_GETFL tests ---"); + + /* Open a file for read-only */ + fd = open("tfcntl.c", O_RDONLY); + if (fd < 0) { + perror("tfcntl"); + return(EXIT_FAILURE); + } + + errno = 0; + retval = fcntl(fd, F_GETFL); + printf("F_GETFL:retval=%04x = %s\n", retval, flags2str(retval)); + if ((retval < 0) && (errno != 0)) prdoserr(fd); + + close(fd); + + /* Open a file for write-only */ + remove("tfcntl.wo"); + fd = open("tfcntl.wo", O_CREAT|O_WRONLY); + if (fd < 0) { + perror("tfcntl"); + return(EXIT_FAILURE); + } + + errno = 0; retval = fcntl(fd, F_GETFL); - printf("F_GETFL:retval=%04x\n", retval); + printf("F_GETFL:retval=%04x = %s\n", retval, flags2str(retval)); if ((retval < 0) && (errno != 0)) prdoserr(fd); close(fd); - exit(0); -#else - exit(99); -#endif + + /* Try opening a file for write-only using creat(). */ + remove("tfcntl.wo"); + fd = creat("tfcntl.wo", S_IWUSR); + if (fd < 0) { + perror("tfcntl"); + return(EXIT_FAILURE); + } + + errno = 0; + retval = fcntl(fd, F_GETFL); + printf("F_GETFL:retval=%04x = %s\n", retval, flags2str(retval)); + if ((retval < 0) && (errno != 0)) prdoserr(fd); + + close(fd); + + /* Open a file for read-write, append */ + remove("tfcntl.rwa"); + fd = open("tfcntl.rwa", O_CREAT|O_RDWR|O_APPEND); + if (fd < 0) { + perror("tfcntl"); + return(EXIT_FAILURE); + } + + errno = 0; + retval = fcntl(fd, F_GETFL); + printf("F_GETFL:retval=%04x = %s\n", retval, flags2str(retval)); + if ((retval < 0) && (errno != 0)) prdoserr(fd); + + close(fd); + + return(EXIT_SUCCESS); } Index: src/libc/posix/fcntl/fcntl.txh =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/fcntl/fcntl.txh,v retrieving revision 1.8 diff -p -u -3 -r1.8 fcntl.txh --- src/libc/posix/fcntl/fcntl.txh 2001/02/01 19:19:24 1.8 +++ src/libc/posix/fcntl/fcntl.txh 2002/06/09 20:11:58 @@ -62,8 +62,10 @@ will return -1, setting @code{errno} to @item F_GETFL Get the open mode and status flags associated with the handle @var{fd}. The flags are those supported by @code{open} and @code{creat} functions, -like @code{O_RDONLY}, @code{O_APPEND}, etc. Currently, this command -always returns zero, with no flags set. +like @code{O_RDONLY}, @code{O_APPEND}, etc. + +On Windows NT this cannot report the open mode correctly --- +@code{O_RDONLY} is always returned. @item F_SETFL Set the open mode and status flags associated with the handle @var{fd}. Index: src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.113 diff -p -u -3 -r1.113 wc204.txi --- src/docs/kb/wc204.txi 2002/04/14 16:25:43 1.113 +++ src/docs/kb/wc204.txi 2002/06/09 20:12:02 @@ -273,11 +273,15 @@ These functions now interrogate and use @item @findex fcntl AT r{ commands @code{F_GETFL} and @code{F_SETFL}} -These functions are still effective no-ops, since DOS/Windows does not -allow flags to be modified on an open file. A small exception is made -for @code{F_SETFL}: You may use @code{F_SETFL} to remove the -@code{O_NONBLOCK} flag, because it is not supported by DJGPP anyway, and -it does no harm to allow this functionality. +The @code{F_SETFL} function is still an effective no-op, since +DOS/Windows does not allow flags to be modified on an open file. +A small exception is made for @code{F_SETFL}: You may use @code{F_SETFL} +to remove the AT code{O_NONBLOCK} flag, because it is not supported +by DJGPP anyway, and it does no harm to allow this functionality. + +The @code{F_GETFL} function now computes the open mode and status flags. +On Windows NT this cannot report the open mode correctly --- +@code{O_RDONLY} is always returned. @item Documentation has been updated to reflect the new functionality and