This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, libfortran] PR 40812 Large file support on MinGW


Hi,

the attached patch should make gfortran support > 2 GB files on MinGW.
I don't have a windows installation to test on, so I don't know if
this works or not. Though I regtested on x86_64-unknown-linux-gnu to
make sure that non-MinGW targets didn't change (it's all behind
#ifdefs, but just to be sure).

Another caveat is that it uses features from the Win32 API that
according to MSDN are available only as of w2k and newer, so with this
patch we effectively drop support for pre-w2k targets on MinGW. I
don't know if anybody cares about such platforms any longer, if so
maybe the interested party could step up to the plate and contribute
some configure checks or somesuch so that we could fall back to the
old ftruncate or chsize functions?

Ok for trunk?

2009-12-01  Janne Blomqvist  <jb@gcc.gnu.org>

	PR libfortran/40812
	* libgfortran.h: typedef gfc_offset differently for mingw.
	* io/unix.h (struct stream): Change function pointers to use
	gfc_offset instead of off_t.
	(sseek): Change prototype to use gfc_offset instead of off_t.
	(stell): Likewise.
	(struncate): Likewise.
	* io/unix.c: Redefine lseek() for mingw.
	(raw_seek): Use gfc_offset instead of off_t.
	(raw_tell): Likewise.
	(buf_seek): Likewise.
	(buf_tell): Likewise.
	(buf_truncate): Likewise.
	(mem_seek): Likewise.
	(mem_tell): Likewise.
	(mem_truncate): Likewise.
	(fd_to_stream): Likewise.
	(file_length): Likewise.
	(raw_truncate): Use gfc_offset instead of off_t, add large file
	capable implementation for MinGW.


-- 
Janne Blomqvist
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index 8b32475..18ce6bb 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -47,6 +47,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
+#define lseek _lseeki64
+
 static uint64_t
 id_from_handle (HANDLE hFile)
 {
@@ -274,22 +276,63 @@ raw_write (unix_stream * s, const void * buf, ssize_t nbyte)
   return nbyte - bytes_left;
 }
 
-static off_t
-raw_seek (unix_stream * s, off_t offset, int whence)
+static gfc_offset
+raw_seek (unix_stream * s, gfc_offset offset, int whence)
 {
   return lseek (s->fd, offset, whence);
 }
 
-static off_t
+static gfc_offset
 raw_tell (unix_stream * s)
 {
   return lseek (s->fd, 0, SEEK_CUR);
 }
 
 static int
-raw_truncate (unix_stream * s, off_t length)
+raw_truncate (unix_stream * s, gfc_offset length)
 {
-#ifdef HAVE_FTRUNCATE
+#ifdef __MINGW32__
+  LARGE_INTEGER cur, tmp;
+  HANDLE h;
+  long htmp;
+
+  if (isatty (s->fd))
+    {
+      errno = EBADF;
+      return -1;
+    }
+  htmp = _get_osfhandle (s->fd);
+  if (htmp == INVALID_HANDLE_VALUE)
+    {
+      runtime_error ("Couldn't get handle from fd");
+      return -1;
+    }
+  h = (HANDLE) htmp;
+  tmp.LowPart = 0;
+  tmp.HighPart = 0;
+  if (!SetFilePointerEx (h, tmp, &cur, FILE_CURRENT))
+    {
+      runtime_error ("Couldn't determine file position");
+      return -1;
+    }
+  tmp.QuadPart = length;
+  if (!SetFilePointerEx (h, tmp, NULL, FILE_CURRENT))
+    {
+      runtime_error ("Couldn't seek to specified position for truncation");
+      return -1;
+    }
+  if (!SetEndOfFile (h))
+    {
+      runtime_error ("Couldn't truncate file");
+      return -1;
+    }
+  if (!SetFilePointerEx (h, cur, NULL, FILE_BEGIN))
+    {
+      runtime_error ("Couldn't seek back after truncating");
+      return -1;
+    }
+  return 0;
+#elif defined HAVE_FTRUNCATE
   return ftruncate (s->fd, length);
 #elif defined HAVE_CHSIZE
   return chsize (s->fd, length);
@@ -470,8 +513,8 @@ buf_write (unix_stream * s, const void * buf, ssize_t nbyte)
   return nbyte;
 }
 
-static off_t
-buf_seek (unix_stream * s, off_t offset, int whence)
+static gfc_offset
+buf_seek (unix_stream * s, gfc_offset offset, int whence)
 {
   switch (whence)
     {
@@ -495,14 +538,14 @@ buf_seek (unix_stream * s, off_t offset, int whence)
   return offset;
 }
 
-static off_t
+static gfc_offset
 buf_tell (unix_stream * s)
 {
   return s->logical_offset;
 }
 
 static int
-buf_truncate (unix_stream * s, off_t length)
+buf_truncate (unix_stream * s, gfc_offset length)
 {
   int r;
 
@@ -631,8 +674,8 @@ mem_write (stream * s, const void * buf, ssize_t nbytes)
 }
 
 
-static off_t
-mem_seek (stream * strm, off_t offset, int whence)
+static gfc_offset
+mem_seek (stream * strm, gfc_offset offset, int whence)
 {
   unix_stream * s = (unix_stream *) strm;
   switch (whence)
@@ -668,7 +711,7 @@ mem_seek (stream * strm, off_t offset, int whence)
 }
 
 
-static off_t
+static gfc_offset
 mem_tell (stream * s)
 {
   return ((unix_stream *)s)->logical_offset;
@@ -677,7 +720,7 @@ mem_tell (stream * s)
 
 static int
 mem_truncate (unix_stream * s __attribute__ ((unused)), 
-	      off_t length __attribute__ ((unused)))
+	      gfc_offset length __attribute__ ((unused)))
 {
   return 0;
 }
@@ -764,7 +807,7 @@ fd_to_stream (int fd, int prot)
 
   fstat (fd, &statbuf);
 
-  if (lseek (fd, 0, SEEK_CUR) == (off_t) -1)
+  if (lseek (fd, 0, SEEK_CUR) == (gfc_offset) -1)
     s->file_length = -1;
   else
     s->file_length = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
@@ -1602,7 +1645,7 @@ inquire_readwrite (const char *string, int len)
 gfc_offset
 file_length (stream * s)
 {
-  off_t curr, end;
+  gfc_offset curr, end;
   if (!is_seekable (s))
     return -1;
   curr = stell (s);
diff --git a/libgfortran/io/unix.h b/libgfortran/io/unix.h
index f0f0712..e691982 100644
--- a/libgfortran/io/unix.h
+++ b/libgfortran/io/unix.h
@@ -33,10 +33,10 @@ struct stream
 {
   ssize_t (*read) (struct stream *, void *, ssize_t);
   ssize_t (*write) (struct stream *, const void *, ssize_t);
-  off_t (*seek) (struct stream *, off_t, int);
-  off_t (*tell) (struct stream *);
+  gfc_offset (*seek) (struct stream *, gfc_offset, int);
+  gfc_offset (*tell) (struct stream *);
   /* Avoid keyword truncate due to AIX namespace collision.  */
-  int (*trunc) (struct stream *, off_t);
+  int (*trunc) (struct stream *, gfc_offset);
   int (*flush) (struct stream *);
   int (*close) (struct stream *);
 };
@@ -54,20 +54,20 @@ swrite (stream * s, const void * buf, ssize_t nbyte)
   return s->write (s, buf, nbyte);
 }
 
-static inline off_t
-sseek (stream * s, off_t offset, int whence)
+static inline gfc_offset
+sseek (stream * s, gfc_offset offset, int whence)
 {
   return s->seek (s, offset, whence);
 }
 
-static inline off_t
+static inline gfc_offset
 stell (stream * s)
 {
   return s->tell (s);
 }
 
 static inline int
-struncate (stream * s, off_t length)
+struncate (stream * s, gfc_offset length)
 {
   return s->trunc (s, length);
 }
diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h
index bba95f7..bb3f0ac 100644
--- a/libgfortran/libgfortran.h
+++ b/libgfortran/libgfortran.h
@@ -56,7 +56,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+
+#ifdef __MINGW32__
+typedef _off64_t gfc_offset;
+#else
 typedef off_t gfc_offset;
+#endif
 
 #ifndef NULL
 #define NULL (void *) 0

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]