On cygwin, where __LARGE64_FILES is default, this program exposes a bug in 64-
bit support of ftello/fgetpos:
$ cat foo.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
fpos_t pos;
FILE *f;
if (argc > 2)
f = freopen(argv[1], "r", stdin);
else if (argc > 1)
f = fopen(argv[1], "r");
else
f = stdin;
getc(f);
printf("ftell:%d ", (int) ftell(f));
printf("ftello:%d ", (int) ftello(f));
fgetpos(f, &pos);
printf("fgetpos:%d ", (int) pos);
printf("lseek:%d ", (int) lseek(fileno(f), 0, SEEK_CUR));
return 0;
}
$ echo hello > blah
$ ./foo < blah
ftell:1 ftello:-1 fgetpos:-1 lseek:1
The problem here was that ftello is mapped to ftello64 in cygwin, but ftello64
checks only the field fp->_seek64 when determining if the file is seekable.
Unless the creation of std{in,out,err} also defaults to allowing 64-bit access,
the _seek64 field is left NULL, explaining why ftello and ftell disagreed.
$ ./foo blah 1
ftell:1 ftello:1 fgetpos:1 lseek:1
$ ./foo blah
ftell:1 ftello:1 fgetpos:1 lseek:1
The use of freopen(NULL) or of a different FILE than stdin both worked around
the problem, proving that it is localized to the initial setup of stdin.
Meanwhile, why is there __sseek64_r, but not __sseek_r? I think there is a
reentrancy problem here - if you use something other than _REENT, it looks like
any FILE operation such as fseek that invokes _lseek_r under the hood is not
preserving errno correctly to the alternate struct _reent. I'll attempt a
patch for this in a followup mail.
OK to apply?
2007-04-30 Eric Blake <ebb9@byu.net>
* libc/stdio64/local64.h: Delete, move contents to...
* libc/stdio/local.h: ...here.
* libc/stdio64/fdopen64.c: Update includes.
* libc/stdio64/fopen64.c: Likewise.
* libc/stdio64/freopen64.c: Likewise.
* libc/stdio64/fseeko64.c: Likewise.
* libc/stdio64/ftello64.c: Likewise.
* libc/stdio/findfp.c (std) [__LARGE64_FILES]: Open stdin, stdout,
and stderr with 64-bit offset.
* libc/stdio/fseek.c (_fseek_r): Avoid compile warning.
* libc/stdio/makebuf.c (__smakebuf_r): Likewise.
* libc/stdio/mktemp.c (_gettemp): Likewise.
Index: libc/stdio/findfp.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/findfp.c,v
retrieving revision 1.17
diff -u -b -r1.17 findfp.c
--- libc/stdio/findfp.c 26 Sep 2006 21:22:19 -0000 1.17
+++ libc/stdio/findfp.c 30 Apr 2007 14:25:48 -0000
@@ -52,7 +52,13 @@
ptr->_lbfsize = 0;
ptr->_cookie = ptr;
ptr->_read = __sread;
+#ifndef __LARGE64_FILES
ptr->_write = __swrite;
+#else /* __LARGE64_FILES */
+ ptr->_write = __swrite64;
+ ptr->_seek64 = __sseek64;
+ ptr->_flags |= __SL64;
+#endif /* __LARGE64_FILES */
ptr->_seek = __sseek;
ptr->_close = __sclose;
#if !defined(__SINGLE_THREAD__) && !defined(_REENT_SMALL)
Index: libc/stdio/fseek.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fseek.c,v
retrieving revision 1.15
diff -u -b -r1.15 fseek.c
--- libc/stdio/fseek.c 15 Mar 2007 18:40:48 -0000 1.15
+++ libc/stdio/fseek.c 30 Apr 2007 14:25:48 -0000
@@ -126,7 +126,11 @@
_fpos_t target;
_fpos_t curoff = 0;
size_t n;
+#ifdef __USE_INTERNAL_STAT64
+ struct stat64 st;
+#else
struct stat st;
+#endif
int havepos;
/* Make sure stdio is set up. */
Index: libc/stdio/local.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/local.h,v
retrieving revision 1.20
diff -u -b -r1.20 local.h
--- libc/stdio/local.h 15 Mar 2007 21:32:13 -0000 1.20
+++ libc/stdio/local.h 30 Apr 2007 14:25:48 -0000
@@ -46,6 +46,14 @@
extern int _EXFUN(_fwalk_reent,(struct _reent *, int (*)(struct _reent *,
FILE *)));
struct _glue * _EXFUN(__sfmoreglue,(struct _reent *,int n));
+#ifdef __LARGE64_FILES
+extern _fpos64_t _EXFUN(__sseek64,(void *, _fpos64_t, int));
+extern _fpos64_t _EXFUN(__sseek64_r,(struct _reent *, void *, _fpos64_t, int));
+extern _READ_WRITE_RETURN_TYPE _EXFUN(__swrite64,(void *, char const *, int));
+extern _READ_WRITE_RETURN_TYPE _EXFUN(__swrite64_r,(struct _reent *, void *,
+ char const *, int));
+#endif
+
/* Called by the main entry point fns to ensure stdio has been initialized. */
#ifdef _REENT_SMALL
Index: libc/stdio/makebuf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/makebuf.c,v
retrieving revision 1.7
diff -u -b -r1.7 makebuf.c
--- libc/stdio/makebuf.c 15 Mar 2007 18:40:48 -0000 1.7
+++ libc/stdio/makebuf.c 30 Apr 2007 14:25:48 -0000
@@ -41,7 +41,11 @@
{
register size_t size, couldbetty;
register _PTR p;
+#ifdef __USE_INTERNAL_STAT64
+ struct stat64 st;
+#else
struct stat st;
+#endif
if (fp->_flags & __SNBF)
{
Index: libc/stdio/mktemp.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/mktemp.c,v
retrieving revision 1.8
diff -u -b -r1.8 mktemp.c
--- libc/stdio/mktemp.c 23 Apr 2004 20:01:55 -0000 1.8
+++ libc/stdio/mktemp.c 30 Apr 2007 14:25:48 -0000
@@ -108,7 +108,11 @@
register int *doopen)
{
register char *start, *trv;
+#ifdef __USE_INTERNAL_STAT64
+ struct stat64 sbuf;
+#else
struct stat sbuf;
+#endif
unsigned int pid;
pid = _getpid_r (ptr);
Index: libc/stdio64/fdopen64.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio64/fdopen64.c,v
retrieving revision 1.3
diff -u -b -r1.3 fdopen64.c
--- libc/stdio64/fdopen64.c 25 Mar 2004 22:29:17 -0000 1.3
+++ libc/stdio64/fdopen64.c 30 Apr 2007 14:25:48 -0000
@@ -28,7 +28,7 @@
#include <stdio.h>
#include <errno.h>
-#include "local64.h"
+#include "local.h"
#include <_syslist.h>
#include <sys/lock.h>
Index: libc/stdio64/fopen64.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio64/fopen64.c,v
retrieving revision 1.6
diff -u -b -r1.6 fopen64.c
--- libc/stdio64/fopen64.c 11 Jun 2004 20:37:10 -0000 1.6
+++ libc/stdio64/fopen64.c 30 Apr 2007 14:25:48 -0000
@@ -66,7 +66,7 @@
#include <stdio.h>
#include <errno.h>
-#include "local64.h"
+#include "local.h"
#ifdef __CYGWIN__
#include <fcntl.h>
#endif
Index: libc/stdio64/freopen64.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio64/freopen64.c,v
retrieving revision 1.14
diff -u -b -r1.14 freopen64.c
--- libc/stdio64/freopen64.c 16 Mar 2007 20:05:10 -0000 1.14
+++ libc/stdio64/freopen64.c 30 Apr 2007 14:25:48 -0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1990, 2006 The Regents of the University of California.
+ * Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
@@ -78,7 +78,7 @@
#include <fcntl.h>
#include <stdlib.h>
#include <sys/lock.h>
-#include "local64.h"
+#include "local.h"
/*
* Re-direct an existing, open (probably) file to some other file.
Index: libc/stdio64/fseeko64.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio64/fseeko64.c,v
retrieving revision 1.9
diff -u -b -r1.9 fseeko64.c
--- libc/stdio64/fseeko64.c 16 Mar 2007 20:05:10 -0000 1.9
+++ libc/stdio64/fseeko64.c 30 Apr 2007 14:25:48 -0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1990, 2007 The Regents of the University of California.
+ * Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
@@ -86,7 +86,7 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include "local64.h"
+#include "local.h"
#define POS_ERR (-(_fpos64_t)1)
Index: libc/stdio64/ftello64.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio64/ftello64.c,v
retrieving revision 1.5
diff -u -b -r1.5 ftello64.c
--- libc/stdio64/ftello64.c 26 Sep 2006 21:22:19 -0000 1.5
+++ libc/stdio64/ftello64.c 30 Apr 2007 14:25:48 -0000
@@ -80,7 +80,7 @@
#include <stdio.h>
#include <errno.h>
-#include "local64.h"
+#include "local.h"
#ifdef __LARGE64_FILES
Index: libc/stdio64/local64.h
===================================================================
RCS file: libc/stdio64/local64.h
diff -N libc/stdio64/local64.h
--- libc/stdio64/local64.h 22 Aug 2003 18:52:25 -0000 1.3
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,16 +0,0 @@
-/*
- * Information local to this implementation of stdio64,
- * in particular, macros and private variables.
- */
-
-#include "local.h"
-
-#ifdef __LARGE64_FILES
-extern _fpos64_t _EXFUN(__sseek64,(void *, _fpos64_t, int));
-extern _fpos64_t _EXFUN(__sseek64_r,(struct _reent *, void *, _fpos64_t, int));
-extern _fpos64_t _EXFUN(__sseek64_error,(void *, _fpos64_t, int));
-extern _READ_WRITE_RETURN_TYPE _EXFUN(__swrite64,(void *, char const *, int));
-extern _READ_WRITE_RETURN_TYPE _EXFUN(__swrite64_r,(struct _reent *, void *,
- char const *, int));
-#endif
-