fgetpos() and fsetpos() call fseek and ftell to do their dirty work. This means that all FILE* operations are limited to the 2GB limit imposed by the "long" offset type. Fix: 1. Rename ftell to ftello, and fseek to fseeko, which are X/Open standard functions that take off_t offsets. All that had to be changed was the prototypes, as the internals already used fpos_t. 2. add new fseek/ftell functions. 3. change fsetpos/fgetpos to use fseeko/ftello. 4. add protptypes to stdio.h. One thing; our errno.h doesn't have an EOVERFLOW, so I used EFBIG in ftell() for filesizes that exceed 2GB. This should probably get fixed. -Dan Nelson dnelson@emsphone.com -Dan Nelson dnelson@emsphone.com--6s8K7NGLTh3ww6JmKfea8EktaH6JHOITYM6jZqwWV5bq1sDI Content-Type: text/plain; name="file.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="file.diff" Index: fgetpos.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/fgetpos.c,v retrieving revision 1.3 diff -u -r1.3 fgetpos.c --- fgetpos.c 1996/06/22 10:33:09 1.3 +++ fgetpos.c 1998/11/09 20:12:33 @@ -57,7 +57,7 @@ #ifdef _THREAD_SAFE _thread_flockfile(fp,__FILE__,__LINE__); #endif - retval = (*pos = ftell(fp)) == (fpos_t)-1; + retval = (*pos = ftello(fp)) == (fpos_t)-1; #ifdef _THREAD_SAFE _thread_funlockfile(fp); #endif Index: fseek.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/fseek.c,v retrieving revision 1.4 diff -u -r1.4 fseek.c --- fseek.c 1996/06/22 10:33:22 1.4 +++ fseek.c 1998/11/09 20:21:22 @@ -56,14 +56,23 @@ #define POS_ERR (-(fpos_t)1) +int +fseek(fp, offset, whence) + register FILE *fp; + long offset; + int whence; +{ + return (fseeko(fp, offset, whence)); +} + /* * Seek the given file to the given offset. * `Whence' must be one of the three SEEK_* macros. */ int -fseek(fp, offset, whence) +fseeko(fp, offset, whence) register FILE *fp; - long offset; + off_t offset; int whence; { register fpos_t (*seekfn) __P((void *, fpos_t, int)); Index: fsetpos.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/fsetpos.c,v retrieving revision 1.3 diff -u -r1.3 fsetpos.c --- fsetpos.c 1996/06/22 10:33:23 1.3 +++ fsetpos.c 1998/11/09 20:12:47 @@ -52,5 +52,5 @@ FILE *iop; const fpos_t *pos; { - return (fseek(iop, (long)*pos, SEEK_SET)); + return (fseeko(iop, (off_t)*pos, SEEK_SET)); } Index: ftell.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/ftell.c,v retrieving revision 1.5 diff -u -r1.5 ftell.c --- ftell.c 1996/06/22 10:33:25 1.5 +++ ftell.c 1998/11/09 21:59:47 @@ -44,17 +44,32 @@ #include <stdio.h> #include <errno.h> +#include <limits.h> #include "local.h" #ifdef _THREAD_SAFE #include <pthread.h> #include "pthread_private.h" #endif +/* standard ftell function. */ +long +ftell(fp) + register FILE *fp; +{ + register off_t rv; + rv = ftello(fp); + if (rv > LONG_MAX) { + errno = EFBIG; /* XXX should be EOVERFLOW */ + return (-1); + } + return (rv); +} + /* * ftell: return current offset. */ -long -ftell(fp) +off_t +ftello(fp) register FILE *fp; { register fpos_t pos; Index: stdio.h =================================================================== RCS file: /home/ncvs/src/include/stdio.h,v retrieving revision 1.8.2.2 diff -u -r1.8.2.2 stdio.h --- stdio.h 1998/02/17 00:48:17 1.8.2.2 +++ stdio.h 1998/11/09 20:32:03 @@ -234,8 +234,10 @@ FILE *freopen __P((const char *, const char *, FILE *)); int fscanf __P((FILE *, const char *, ...)); int fseek __P((FILE *, long, int)); +int fseeko __P((FILE *, off_t, int)); int fsetpos __P((FILE *, const fpos_t *)); long ftell __P((FILE *)); +off_t ftello __P((FILE *)); size_t fwrite __P((const void *, size_t, size_t, FILE *)); int getc __P((FILE *)); int getchar __P((void)); How-To-Repeat: Create a 3GB file. Read 2.1GB into it. Call fsetpos(fgetpos()), and note that you are not where you should be.
And here is the documentation to go along with the code: Index: Makefile.inc =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/Makefile.inc,v retrieving revision 1.6.2.2 diff -u -r1.6.2.2 Makefile.inc --- Makefile.inc 1998/04/13 23:20:52 1.6.2.2 +++ Makefile.inc 1998/11/10 15:11:58 @@ -30,6 +30,7 @@ MLINKS+=fputs.3 puts.3 MLINKS+=fread.3 fwrite.3 MLINKS+=fseek.3 fgetpos.3 fseek.3 fsetpos.3 fseek.3 ftell.3 fseek.3 rewind.3 +MLINKS+=fseek.3 fseeko.3 fseek.3 ftello.3 MLINKS+=funopen.3 fropen.3 funopen.3 fwopen.3 MLINKS+=getc.3 fgetc.3 getc.3 getchar.3 getc.3 getw.3 MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 Index: fseek.3 =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/fseek.3,v retrieving revision 1.1.1.1.8.1 diff -u -r1.1.1.1.8.1 fseek.3 --- fseek.3 1998/02/17 17:28:44 1.1.1.1.8.1 +++ fseek.3 1998/11/10 16:26:54 @@ -41,8 +41,10 @@ .Sh NAME .Nm fgetpos , .Nm fseek , +.Nm fseeko , .Nm fsetpos , .Nm ftell , +.Nm ftello , .Nm rewind .Nd reposition a stream .Sh SYNOPSIS @@ -57,6 +59,10 @@ .Fn fgetpos "FILE *stream" "fpos_t *pos" .Ft int .Fn fsetpos "FILE *stream" "const fpos_t *pos" +.Ft int +.Fn fseeko "FILE *stream" "off_t offset" "int whence" +.Ft off_t +.Fn ftello "FILE *stream" .Sh DESCRIPTION The .Fn fseek @@ -106,6 +112,19 @@ .Xr clearerr 3 ) . .Pp The +.Fn fseeko +and +.Fn ftello +functions +are alternate interfaces equivalent to +.Fn ftell +and +.Fn fseek , +but take an off_t argument instead of a long. On systems that use a 32-bit +long type but support 64-bit filesizes, this is the only way to seek past the +2-gigabyte point. +.Pp +The .Fn fgetpos and .Fn fsetpos @@ -133,10 +152,14 @@ Upon successful completion, .Fn fgetpos , .Fn fseek , +.Fn fseeko , +and .Fn fsetpos return 0, and .Fn ftell +and +.Fn ftello returns the current offset. Otherwise, \-1 is returned and the global variable errno is set to indicate the error. @@ -157,14 +180,21 @@ .Dv SEEK_END , or .Dv SEEK_CUR . +.It Bq Er EFBIG +For +.Fn ftello , +the resulting file offset would be a value which +cannot be represented correctly in an object of type off_t. .El .Pp -The function +The functions .Fn fgetpos , .Fn fseek , +.Fn fseeko , .Fn fsetpos , -and -.Fn ftell +.Fn ftell , +and +.Fn ftello may also fail and set .Va errno for any of the errors specified for the routines @@ -186,3 +216,16 @@ functions conform to .St -ansiC . +.Pp +The +.Fn fseeko +and +.Fn ftello +functions conform to the X/Open Single UNIX Specification, Version 2. +.Sh BUGS +The +.Bq Er EFBIG +error return should be +.Bq Er EOVERFLOW +according to the Single Unix specification, but FreeBSD has no +.Bq Er EOVERFLOW .
> One thing; our errno.h doesn't have an EOVERFLOW, so I used EFBIG in > ftell() for filesizes that exceed 2GB. This should probably get fixed. And how about just add EOVERFLOW to errno.h, instead of document the bug in man pages??? Dima
In the last episode (Nov 10), Dmitrij Tejblum said: > > One thing; our errno.h doesn't have an EOVERFLOW, so I used EFBIG in > > ftell() for filesizes that exceed 2GB. This should probably get fixed. > > And how about just add EOVERFLOW to errno.h, instead of document the bug > in man pages??? Well, if it's that easy, sure. I don't know all that much about the repercussions of adding errors to errno.h. I suppose there's a string table that needs adjusting, too, for strerror()? Anything else?
Dan Nelson wrote: > > And how about just add EOVERFLOW to errno.h, instead of document the bug > > in man pages??? > > Well, if it's that easy, sure. I don't know all that much about the > repercussions of adding errors to errno.h. I suppose there's a string > table that needs adjusting, too, for strerror()? Anything else? The string table is in lib/libc/gen/errlst.c. It is already incomplete. I don't know of anything else. Dima
Dan Nelson wrote: > In the last episode (Nov 10), Dmitrij Tejblum said: > > > One thing; our errno.h doesn't have an EOVERFLOW, so I used EFBIG in > > > ftell() for filesizes that exceed 2GB. This should probably get fixed. > > > > And how about just add EOVERFLOW to errno.h, instead of document the bug > > in man pages??? > > Well, if it's that easy, sure. I don't know all that much about the > repercussions of adding errors to errno.h. I suppose there's a string > table that needs adjusting, too, for strerror()? Anything else? NFS needs it added to the errno mapping tables, I suspect the binary emulation (linux, ibcs2 etc) need it too. Cheers, -Peter -- Peter Wemm <peter@netplex.com.au> Netplex Consulting "No coffee, No workee!" :-)
State Changed From-To: open->closed Fixed, thanks.