Date: Thu, 16 Jul 1998 13:24:19 +0300 (IDT) From: Eli Zaretskii To: cssl AT geocities DOT com cc: djgpp-workers AT delorie DOT com Subject: Re: FSEXT bug ? In-Reply-To: <199807152043.NAA16544@geocities.com> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk On Sat, 11 Jul 1998 cssl AT geocities DOT com wrote: > Getting strange results from FSEXT family of functions, I decided to > investigate a bit, so I wrote a test program to see what really happens. > Well, I think that's NOT the correct behaviour. Please in the future always explain just *what* is the incorrect behavior. Not everybody has time to copy your source to a development machine, compile it, and debug it. A verbal explanation of what seems to be incorrect behavior will usually allow to grasp the problem(s) much more quickly. Also, you shouldn't assume that your program will behave on my machine exactly as it does on yours. > Well, I think that's NOT the correct behaviour. Please try this little > program. Shouldn't it call WRITE only once ? Or at least once for every > character, but it shouldn't call it with different parts of the same > string ! Uh, try both WITH and WITHOUT the setvbuf(). Without it > apparently the first character is lost. These are all manifestations of two bugs in your code. First, you unconditionally assign a value of 10 to the *rv parameter: > // Just for testing ! > *rv=10; But functions like _read and _write (which call your handler) expect to see the number of bytes read/written in that parameter. A complete emulation such as yours should return there the same number as passed in the nbytes parameter by the caller. Otherwise, the buffered I/O machinery will take it that only part of the buffer was written, and will then repeatedly try to write out the rest. Which is exactly what you see: on each repeated call, your handler is called with the nbytes argument decreased by 10. You should keep in mind that when you work with Filesystem Extensions, you get access to the guts of the library which can be easily broken. Don't lie to the library, or you *will* be punished! The second bug is here: > printf("\nfopen : "); hnd= fopen("!.tst", "r+b"); > /* setvbuf(hnd, NULL, _IONBF, 0);*/ > printf("\nfgets : "); fgets(buff, 10, hnd); > printf("\nfputs : "); fputs("Hello, world ! I'm here !", hnd); You are opening the same file with "r+", i.e. for both input and output. But such streams require that between input and output you reposition the stream (e.g. with fseek), otherwise you wreak havoc on the buffered I/O machinery. This is an ANSI requirement. Since you don't call fseek between fgets and the following fputs, you get garbled output (``the first character is lost'' etc.), and that is also the reason that setvbuf changes some of the garbled behaviour. Last, but not least, your general design looks scary, since you unconditionally take over every handle opened by the program. However, some library functions sometimes open special files behind the scene, on behalf of your program. For example, time-related functions might open a file in the zoneinfo directory, to read the daylight-saving time rules, etc. You obviously cannot emulate these cases correctly, so some library functions will mysteriously break. Once again, you are messing with the library internals at a very low level here, so a solid design should try to interfere as little as you can. For the same reason, it is a bad idea to use stdio functions such as printf from a handler which catches writes: you might find yourself calling the handler recursively, and the results might be very surprising, to say the least ;-). And btw, your printf uses %s to print a buffer passed to the write function, but the buffer you get is not null-terminated. So you better use something like %.*s and pass the nbytes argument to printf as well.