diff options
Diffstat (limited to 'libio/iofopen.c')
-rw-r--r-- | libio/iofopen.c | 85 |
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); |