X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com Message-ID: <51E5D0C6.1060404@gmx.de> Date: Wed, 17 Jul 2013 01:01:26 +0200 From: Juan Manuel Guerrero User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121025 Thunderbird/16.0.2 MIME-Version: 1.0 To: djgpp-workers AT delorie DOT com Subject: Set _IOERR if the file stream has been opened in wrong mode. Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit X-Provags-ID: V03:K0:oy90SpKbqhEE4GKNwWpSj78dUrW/a+pjpAU5QTee6eXv4cQVtAs Qq1Sg2JVonjnY2/uZstTT9HfGEe34NP6D0lrpkTezkroKmndtQFKutCj/DAkab4n6xx8dJn 3zfkD5CA7lTWuBHvjhVvw9RYu1axJqlIk3MliUwokn4MBtM7PexzUktOw2Hk/+MSH9khM9C TpfPcr8J8GAfe5ADbBSgg== Reply-To: djgpp-workers AT delorie DOT com Please inspect the code snippet below: #include int main(void) { char buffer[1024]; FILE *f = fopen("foobar.txt", "w"); clearerr(f); if (fgets(buffer, sizeof(buffer), f) == NULL) printf("EOF encountered before data\n"); printf("ferror = %s\n", ferror(f) ? "TRUE" : "FALSE"); printf("feof = %s\n", feof(f) ? "TRUE" : "FALSE"); return 0; } The code snippet is not arbitrary (especially the "w" mode instead of the "w+" mode in the fopen function) but represents a compilable and working version of the code produced by the lua interpreter for the first two lines of the following lua code snippet: local f = io.open("foobar.txt", "w") local r, m, c = f:read() assert(r == nil and ismsg(m) and type(c) == "number") The above code is part of a test suite and it shall fail because it tries to read from a file opened to be written. The second line fails and initializes the variables in such a way that the assert is not triggert (the data is a error message and the file descriptor, but that is of no importance here). This is the way the test shall work and this is the way the code works if lua has been compiled on linux. If lua is compiled using any version of djgpp, the second line: local r, m, c = f:read() behaves in a different way (it does not fail, among other things) and the variables are initialized with nonsense data making the following assertion to be triggert and thus aborting the complete test suite. The reason for the different behavior of lua's :read() function is the different way the ferror function has been implemented on linux and djgpp. The issue concerns the fread, fwrite, __putc and __getc functions only. These functions manipulate the file stream FILE *. Functions like read, _read and dos_read are not involved because they work with the file descriptor. If these functions fail due to accessing the file with wrong file mode, they set the appropriate dos error number. Of course, ferror can only fail for those functions that use the file stream. The patch below will fix the issue for read and write functions. As usual, suggestions, objections, comments are welcome. Regards, Juan M. Guerrero cvs ci -"Set _IOERR if the file stream has been opened in wrong mode." djgpp/include/libc/file.h cvs ci -"Set _IOERR if the file stream has been opened in wrong mode." djgpp/src/docs/kb/wc204.txi cvs ci -"Set _IOERR if the file stream has been opened in wrong mode." djgpp/src/libc/ansi/stdio/fread.c cvs ci -"Set _IOERR if the file stream has been opened in wrong mode." djgpp/src/libc/ansi/stdio/fwrite.c Logging in to :pserver:anonymous AT cvs DOT delorie DOT com:2401/cvs/djgpp Index: djgpp/include/libc/file.h =================================================================== RCS file: /cvs/djgpp/djgpp/include/libc/file.h,v retrieving revision 1.14 diff -p -U 5 -r1.14 file.h --- djgpp/include/libc/file.h 16 Jul 2013 19:01:02 -0000 1.14 +++ djgpp/include/libc/file.h 16 Jul 2013 22:06:21 -0000 @@ -1,5 +1,6 @@ +/* Copyright (C) 2013 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2003 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) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ @@ -36,10 +37,14 @@ extern "C" { /* if _flag & _IORMONCL, ._name_to_remove needs freeing */ #define _IOUNGETC 010000 /* there is an ungetc'ed character in the buffer */ #define _IOTERM 020000 /* file's handle hooked by termios */ #define _IONTERM 040000 /* file's handle not hooked by termios */ +#define IN_READ_ONLY_MODE(f) ((f)->_flag & _IOREAD && !((f)->_flag & _IOWRT)) +#define IN_WRITE_ONLY_MODE(f) ((f)->_flag & _IOWRT && !((f)->_flag & _IOREAD)) + + int _flsbuf(int, FILE*); int _filbuf(FILE *); void _fwalk(void (*)(FILE *)); static __inline__ int __getc_raw(FILE *const p) @@ -69,10 +74,15 @@ static __inline__ int __is_text_file(FIL } static __inline__ int __getc(FILE *const p) { int __c; + if (IN_WRITE_ONLY_MODE(p)) + { + p->_flag |= _IOERR; + return EOF; + } if (__libc_read_termios_hook && !(p->_flag & (_IOTERM | _IONTERM))) { extern int __isatty(int); /* first time we see this handle--see if termios hooked it */ @@ -87,10 +97,15 @@ static __inline__ int __getc(FILE *const return __c; } static __inline__ int __putc(const int x, FILE *const p) { + if (IN_READ_ONLY_MODE(p)) + { + p->_flag |= _IOERR; + return EOF; + } if (__libc_write_termios_hook && !(p->_flag & (_IOTERM | _IONTERM))) { extern int __isatty(int); /* first time we see this handle--see if termios hooked it */ Index: djgpp/src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.207 diff -p -U 5 -r1.207 wc204.txi --- djgpp/src/docs/kb/wc204.txi 23 Mar 2013 11:54:58 -0000 1.207 +++ djgpp/src/docs/kb/wc204.txi 16 Jul 2013 22:06:21 -0000 @@ -1287,5 +1287,13 @@ members of @code{struct rlimit}. @findex islessgreater AT r{ added} @findex isunordered AT r{ added} The @acronym{C99} macros @code{isfinite}, @code{isinf}, @code{isnan}, @code{isnormal}, @code{isgreater}, @code{isgreaterequal}, @code{isless}, @code{islessequal}, @code{islessgreater} and @code{isunordered} were added to comply with the @acronym{C99} standard. + +@findex fread AT r{, and setting @code{_flag} to @code{_IOERR} if stream has been opened with wrong mode} +@findex fwrite AT r{, and setting @code{_flag} to @code{_IOERR} if stream has been opened with wrong mode} +@findex __getc AT r{, and setting @code{_flag} to @code{_IOERR} if stream has been opened with wrong mode} +@findex __putc AT r{, and setting @code{_flag} to @code{_IOERR} if stream has been opened with wrong mode} +@code{fread}, @code{fwrite}, @code{__getc} and @code{__putc} now check that the +file stream has been opened in correct mode. If it is the wrong mode the file +stream @code{_flag} flag will be set to @code{_IOERR} before aborting the operation. Index: djgpp/src/libc/ansi/stdio/fread.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/fread.c,v retrieving revision 1.8 diff -p -U 5 -r1.8 fread.c --- djgpp/src/libc/ansi/stdio/fread.c 16 Jul 2013 21:54:37 -0000 1.8 +++ djgpp/src/libc/ansi/stdio/fread.c 16 Jul 2013 22:06:21 -0000 @@ -1,5 +1,6 @@ +/* Copyright (C) 2013 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) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ @@ -16,10 +17,16 @@ fread(void *vptr, size_t size, size_t co { char *ptr = (char *)vptr; int s; int c; + if (IN_WRITE_ONLY_MODE(f)) + { + f->_flag |= _IOERR; + return 0; + } + /* grow if we know we're asking for a lot, even if it's in the buffer, since we'll probably read chunks this size for a while */ while (size * count > f->_fillsize && f->_fillsize < f->_bufsiz) { Index: djgpp/src/libc/ansi/stdio/fwrite.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/fwrite.c,v retrieving revision 1.9 diff -p -U 5 -r1.9 fwrite.c --- djgpp/src/libc/ansi/stdio/fwrite.c 16 Jul 2013 21:54:39 -0000 1.9 +++ djgpp/src/libc/ansi/stdio/fwrite.c 16 Jul 2013 22:06:21 -0000 @@ -1,5 +1,6 @@ +/* Copyright (C) 2013 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) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ @@ -13,10 +14,16 @@ size_t fwrite(const void *vptr, size_t size, size_t count, FILE *f) { const char *ptr = (const char *)vptr; ssize_t s; + if (IN_READ_ONLY_MODE(f)) + { + f->_flag |= _IOERR; + return 0; + } + if (__libc_write_termios_hook && !(f->_flag & (_IOTERM | _IONTERM))) { /* first time we see this handle--see if termios hooked it */ if (isatty(f->_file))