about summary refs log tree commit diff
path: root/libio/iofopen.c
diff options
context:
space:
mode:
Diffstat (limited to 'libio/iofopen.c')
-rw-r--r--libio/iofopen.c85
1 files changed, 81 insertions, 4 deletions
diff --git a/libio/iofopen.c b/libio/iofopen.c
index 8fd334543d..e4821cbf0e 100644
--- a/libio/iofopen.c
+++ b/libio/iofopen.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1993,1997,1998,1999,2000,2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -28,6 +28,7 @@
 #include "libioP.h"
 #ifdef __STDC__
 #include <stdlib.h>
+#include <stddef.h>
 #endif
 #ifdef _LIBC
 # include <shlib-compat.h>
@@ -36,9 +37,76 @@
 #endif
 
 _IO_FILE *
-_IO_new_fopen (filename, mode)
+__fopen_maybe_mmap (fp)
+     _IO_FILE *fp;
+{
+#ifdef _G_HAVE_MMAP
+  if (fp->_flags & _IO_NO_WRITES)
+    {
+      /* We use the file in read-only mode.  This could mean we can
+	 mmap the file and use it without any copying.  But not all
+	 file descriptors are for mmap-able objects and on 32-bit
+	 machines we don't want to map files which are too large since
+	 this would require too much virtual memory.  */
+      struct _G_stat64 st;
+
+      if (_IO_SYSSTAT (fp, &st) == 0
+	  && S_ISREG (st.st_mode) && st.st_size != 0
+	  /* Limit the file size to 1MB for 32-bit machines.  */
+	  && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024))
+	{
+	  /* Try to map the file.  */
+	  void *p;
+
+# ifdef _G_MMAP64
+	  p = _G_MMAP64 (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
+			 fp->_fileno, 0);
+# else
+	  p = __mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
+		      fp->_fileno, 0);
+# endif
+	  if (p != MAP_FAILED)
+	    {
+	      if (
+# ifdef _G_LSEEK64
+		  _G_LSEEK64 (fp->_fileno, st.st_size, SEEK_SET)
+# else
+		  __lseek (fp->_fileno, st.st_size, SEEK_SET)
+# endif
+		  != st.st_size)
+		{
+		  /* We cannot search the file.  Don't mmap then.  */
+		  __munmap (p, st.st_size);
+		  return fp;
+		}
+
+	      /* OK, we managed to map the file.  Set the buffer up
+		 and use a special jump table with simplified
+		 underflow functions which never tries to read
+		 anything from the file.  */
+	      _IO_setb (fp, p, (char *) p + st.st_size, 0);
+	      _IO_setg (fp, p, p, (char *) p + st.st_size);
+
+	      if (fp->_mode <= 0)
+		_IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps_mmap;
+	      else
+		_IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_wfile_jumps_mmap;
+	      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
+
+	      fp->_offset = st.st_size;
+	    }
+	}
+    }
+#endif
+  return fp;
+}
+
+
+_IO_FILE *
+__fopen_internal (filename, mode, is32)
      const char *filename;
      const char *mode;
+     int is32;
 {
   struct locked_FILE
   {
@@ -64,13 +132,22 @@ _IO_new_fopen (filename, mode)
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
 #endif
-  if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, 1) != NULL)
-    return (_IO_FILE *) &new_f->fp;
+  if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL)
+    return __fopen_maybe_mmap (&new_f->fp.file);
+
   _IO_un_link (&new_f->fp);
   free (new_f);
   return NULL;
 }
 
+_IO_FILE *
+_IO_new_fopen (filename, mode)
+     const char *filename;
+     const char *mode;
+{
+  return __fopen_internal (filename, mode, 1);
+}
+
 #ifdef _LIBC
 strong_alias (_IO_new_fopen, __new_fopen)
 versioned_symbol (libc, _IO_new_fopen, _IO_fopen, GLIBC_2_1);