Date: Wed, 11 Oct 2006 17:30:22 GMT From: Ruslan Ermilov <ru@FreeBSD.org> To: freebsd-bugs@FreeBSD.org Subject: Re: bin/104295: freopen(NULL, ...) does bad things to file offset. Message-ID: <200610111730.k9BHUMH4085536@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/104295; it has been noted by GNATS. From: Ruslan Ermilov <ru@FreeBSD.org> To: trasz <trasz@pin.if.uz.zgora.p> Cc: bug-followup@FreeBSD.org, Andrey Chernov <ache@nagual.pp.ru> Subject: Re: bin/104295: freopen(NULL, ...) does bad things to file offset. Date: Wed, 11 Oct 2006 21:14:44 +0400 On Wed, Oct 11, 2006 at 01:02:28PM +0000, trasz wrote: > Freopen(3) does bad things to the file offset when supplied with NULL > as a file path (freopen(NULL, mode, fd);). The test program below returns: > > file offset before freopen is 100. > file offset after freopen is 2399. > It's actually the minimum of a pagesize and file size. Now we know the size of your /etc/passwd. :-) > #include <stdio.h> > > int main(void) > { > int ret; > FILE *f; > > f=fopen("/etc/passwd", "r"); > if (f==NULL) { > perror("fopen"); > exit(-1); > } > > ret=fseek(f, 100, SEEK_CUR); > if (ret<0) { > perror("fseek"); > exit(-1); > } > > ret=ftell(f); > fprintf(stderr, "file offset before freopen is %d.\n", ret); > > f=freopen(NULL, "r", f); > if (f==NULL) { > perror("freopen"); > exit(-1); > } > > ret=ftell(f); > fprintf(stderr, "file offset after freopen is %d.\n", ret); > > return 0; > } > It's only a problem when a file was initially opened read-only; if you open it "r+" the problem doesn't show up. I don't know the stdio code very well, but I tracked it down to optimizations in _fseeko(); basically, freopen() calls _fseeko(fp, 0, SEEK_SET, 0) and that's getting optimized by not doing a real seek and simply adjusting the pointers. Later in freopen(), these pointers get reset but the underlying file in question stays at its old position. I've worked around this by temporarily disabling the fseek() optimization: %%% Index: freopen.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/freopen.c,v retrieving revision 1.13 diff -u -p -r1.13 freopen.c --- freopen.c 22 May 2004 15:19:41 -0000 1.13 +++ freopen.c 11 Oct 2006 17:01:00 -0000 @@ -115,6 +115,7 @@ freopen(file, mode, fp) } if (oflags & O_TRUNC) ftruncate(fp->_file, 0); + fp->_flags |= __SNPT; if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET, 0) < 0 && errno != ESPIPE) { sverrno = errno; %%% Someone with more stdio-fu should pick it up. Andrey? Cheers, -- Ruslan Ermilov ru@FreeBSD.org FreeBSD committer
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200610111730.k9BHUMH4085536>