Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!linus!decvax!tektronix!ogcvax!omsvax!hplabs!sri-unix!Lepreau@utah-20 From: Lepreau%utah-20@sri-unix.UUCP Newsgroups: net.unix-wizards Subject: Re: r+ on fopen. Message-ID: <11804@sri-arpa.UUCP> Date: Mon, 19-Sep-83 05:25:00 EDT Article-I.D.: sri-arpa.11804 Posted: Mon Sep 19 05:25:00 1983 Date-Received: Fri, 23-Sep-83 23:09:05 EDT Lines: 110 From: Jay Lepreau This is indeed a long-standing bug, to my knowledge first fixed by John Demco (ubc-vision!demco), and later this year by Guy Harris. Both messages are below, as each has info the other doesn't. >From harpo!decvax!microsof!uw-beave!ubc-visi!demco Thu Feb 17 17:54:32 1983 Subject: Re: read/write same file with one open Newsgroups: net.lang.c I have found a bug in the fseek() function of the stdio package as distributed by Berkeley (3/9/81). It can result in improper flushing with a stream file which has been opened for reading and writing (by specifying "r+", "w+", or "a+"). I don't know if the problem exists on System III or V. First, here is some background information about the stdio package. If a stream is opened for read/write, a flag bit called _IORW is set in the _iob structure for the file. Two other flag bits, _IOWRT and _IOREAD, indicate whether the file is currently being written or read. Changing from reading to writing or vice versa can only be done after reading an end of file, or calling fseek() or rewind(). In these cases the package tries to make sure that neither of the _IOWRT or _IOREAD bits are set, so you can subsequently do either a getc() or putc() and the package will enter reading or writing mode correctly. The problem is that fseek() called while in read mode can return with the file still in read mode. Subsequent putc()'s will not be written. A quick fix is to change resync = offset&01; to if (!(iop -> _flag & _IORW)) resync = offset & 01; else resync = 0; Can someone tell me what this "resync" business is all about? It looks like an attempt to keep the file's buffer aligned on an even byte offset into the file, but it won't do that in all cases. >From harpo!seismo!rlgvax!guy Sun Aug 14 22:50:11 1983 Subject: Standard I/O streams open for reading and writing Newsgroups: net.unix-wizards,net.bugs.4bsd The Standard I/O library for releases of UNIX from V7 on includes a feature to permit you to open a stream for reading and writing. This feature is documented in USG UNIX (System III, System V). There is one minor bug in the V7 implementation, and an additional major bug in the 4.?BSD implementation. The first bug is that if your "umask" takes away your own read or write permission, you may not use the "w+" or "a+" modes. The problem is that these modes require "stdio" to do a "creat" to create the file, and then to close and reopen the file in order to have it open for reading and writing (USG doesn't have to do this, but interestingly enough the S3 "stdio" does it anyway), so if your umask takes away read or write permissions the reopen fails. The fix is to change the lines f = creat(file, 0666); if (rw && f>=0) { close(f); f = open(file, 2); } to if (rw) { int m = umask(0); f = creat(file, 0666); if (f>=0) { close(f); f = open(file, 2); chmod(file, 0666 & ~m); } umask(m); } else f = creat(file, 0666); in "endopen.c" in V7, and in "fopen.c" and "freopen.c" in 4.?BSD. The more serious bug is due to the way the 4.?BSD "stdio" handles "fseek". If you have a stream open for reading and writing, you must do an "fseek" if you want to switch from reading to writing or vice versa (this is documented in the USG manuals, so it's not a buried feature). However, if you do an "fseek" to an odd-byte boundary on 4.?BSD on a stream where the last operation was a read, it seeks to the previous byte and does a "getc" to move to the next byte. This is not a problem if the stream is open only for reading or only for writing (I presume it was put in there for efficiency; PDP-11 UNIX moves data from kernel to user or vice versa much more efficiently if it is on a word boundary), but it makes it impossible to put an "fseek" after a read and immediately before a write (because the "fseek" may do a read before you get a chance to do your write). The code in "fseek.c" to handle seeks on a stream on which the last operation was a read has a section which reads: if (iop->_flag & _IORW) { iop->_ptr = iop->_base; iop->_flag &= ~_IOREAD; } A line "resync = 0;" should be added after the "iop->_flag &= ~_IOREAD;". This way, "fseek" will behave as it did if the stream is only open for reading, but will not do the "resync" if it is open for reading and writing. Guy Harris {seismo,mcnc,we13,brl-bmd,allegra}!rlgvax!guy -------