From owner-freebsd-bugs Mon Nov 10 22:03:01 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.7/8.8.7) id WAA28835 for bugs-outgoing; Mon, 10 Nov 1997 22:03:01 -0800 (PST) (envelope-from owner-freebsd-bugs) Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.19]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id WAA28829 for ; Mon, 10 Nov 1997 22:02:57 -0800 (PST) (envelope-from bde@zeta.org.au) Received: (from bde@localhost) by godzilla.zeta.org.au (8.8.7/8.6.9) id QAA20598; Tue, 11 Nov 1997 16:59:08 +1100 Date: Tue, 11 Nov 1997 16:59:08 +1100 From: Bruce Evans Message-Id: <199711110559.QAA20598@godzilla.zeta.org.au> To: freebsd-bugs@hub.freebsd.org, tege@nada.kth.se Subject: Re: bin/4961: Problems with fseek and fprints Sender: owner-freebsd-bugs@FreeBSD.ORG X-Loop: FreeBSD.org Precedence: bulk > >1) fseek is ignored on files that were fdopen'ed in append mode. > > This is not a bug. ANSI C says that writes are only allowed at the end > of file when opening in append mode (e.g. any write has an implicit It would be a bug to always completely ignore fseek on such files, since it sometimes has side effects if it succeeds (e.g., at least under POSIX, it must flush any buffered output and synchronise with with the underlying fd. Flushing must set file timestamps and these can be peeked at outside of stdio, so flushing can't be delayed). > seek to end preceding it). Open with "r+" if you want to write > somewhere other than the end of file. This won't work if the file descriptor is open in O_APPEND mode. fdopen should not and does not clear to O_APPEND flag, so it is impossible to write somewhere other than the end of a file using stdio. > (Does ANSI say anything about this? I thought POSIX was what spec'd these > functions?) ANSI permits fseek to fail if the request cannot be satisfied. Under POSIX, all offsets can be lseeked to although only EOF can be written to, so it isn't reasonable to reject requests because of the offset, and in fact fseek does whatever the FILE's _seek function does. fseek is just useless in the O_APPEND case, at least if the _seek function is lseek. You can get the same effect using fflush. fseek is more useless than lseek, since lseek(fd, off, SEEK_EOF) is useful for determining the current file, but the corresponding `fseek(fp, off, SEEK_EOF); ftell(fp);' is not, at least in POSIX, since the result of ftell() is unspecified for the O_APPEND case :-(. FreeBSD stdio actually depends on this loophole to be POSIXly correct: after `fseek(fp, 0L, SEEK_SET); putc('!', fp);', on a nonempty file, ftell() reports the bogus offset of 1. The fseek() sets the underlying file offset to 0 and the putc() advances it to previous_file_size+1 by writing at EOF, and ftell() apparently doesn't bother to synchronise with the file system. > I checked several other Unices and, and they behaved as I want. If > FreeBSD's behaviour is right, there is no obvious way of closing say stdout > and reopen what was associated to it and then keep writing to a specified > position. "w" truncates the file and "r+" cannot be done on stdout since > the underlying file descriptor disallows reads. You'll have to use fcntl() to change the O_APPEND flag at suitable times. There are some other problems with freopen() on files that are actually file descriptors. The files must be kept open to prevent their fd's from going away, but ANSI specifies closing of the old file. Closing the file sometimes has side effects. NIST PCTS detects brokenness here by noticing that side effects for named pipes don't occur. > >2) The second fprintf below sets errno even while no error really > > happens. > > errno is not set on a 2.2.2-RELEASE system; on a 3.0-CURRENT system, > errno is indeed set to ENOENT. Interestingly enough, it's the first > fprintf that's setting errno. This is definitely worth looking into; > I have no clue what fprintf might be doing that would cause a ENOENT. As discussed already, checking errno is usually the wrong way to detect errors, and the ENOENT may be for malloc attempting to open /etc/malloc.conf. Bruce