Bug 8637 - fgetpos()/fsetpos() don't work for >2GB filesize
Summary: fgetpos()/fsetpos() don't work for >2GB filesize
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 2.2.7-STABLE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 1998-11-09 22:30 UTC by Dan Nelson (old address)
Modified: 1999-05-13 20:14 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dan Nelson (old address) 1998-11-09 22:30:00 UTC
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.
Comment 1 Dan Nelson (old address) 1998-11-10 16:46:28 UTC
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 .
Comment 2 Dmitrij Tejblum 1998-11-10 20:46:54 UTC
> 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
Comment 3 Dan Nelson (old address) 1998-11-10 22:43:48 UTC
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?
Comment 4 Dmitrij Tejblum 1998-11-11 00:45:46 UTC
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
Comment 5 peter 1998-11-11 05:05:38 UTC
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!" :-)
Comment 6 dt freebsd_committer freebsd_triage 1999-05-13 20:13:16 UTC
State Changed
From-To: open->closed

Fixed, thanks.