PR binutils/10654
[deliverable/binutils-gdb.git] / bfd / cache.c
index eb6120dfbe2f00734a5cf3250adf51b0619ddc0e..cf1869d0ed5c1139a67f78d9195b1034b58e80eb 100644 (file)
@@ -1,7 +1,7 @@
 /* BFD library -- caching of file descriptors.
 
    Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002,
-   2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
 
@@ -46,6 +46,10 @@ SUBSECTION
 #include "libbfd.h"
 #include "libiberty.h"
 
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
 /* In some cases we can optimize cache operation when reopening files.
    For instance, a flush is entirely unnecessary if the file is already
    closed, so a flush would use CACHE_NO_OPEN.  Similarly, a seek using
@@ -236,7 +240,7 @@ cache_btell (struct bfd *abfd)
 static int
 cache_bseek (struct bfd *abfd, file_ptr offset, int whence)
 {
-  FILE *f = bfd_cache_lookup (abfd, whence != SEEK_CUR ? CACHE_NO_SEEK : 0);
+  FILE *f = bfd_cache_lookup (abfd, whence != SEEK_CUR ? CACHE_NO_SEEK : CACHE_NORMAL);
   if (f == NULL)
     return -1;
   return real_fseek (f, offset, whence);
@@ -250,7 +254,7 @@ cache_bseek (struct bfd *abfd, file_ptr offset, int whence)
    first octet in the file, NOT the beginning of the archive header.  */
 
 static file_ptr
-cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
+cache_bread_1 (struct bfd *abfd, void *buf, file_ptr nbytes)
 {
   FILE *f;
   file_ptr nread;
@@ -266,7 +270,7 @@ cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
   if (nbytes == 0)
     return 0;
 
-  f = bfd_cache_lookup (abfd, 0);
+  f = bfd_cache_lookup (abfd, CACHE_NORMAL);
   if (f == NULL)
     return 0;
 
@@ -300,11 +304,49 @@ cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
   return nread;
 }
 
+static file_ptr
+cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
+{
+  file_ptr nread = 0;
+
+  /* Some filesystems are unable to handle reads that are too large
+     (for instance, NetApp shares with oplocks turned off).  To avoid
+     hitting this limitation, we read the buffer in chunks of 8MB max.  */
+  while (nread < nbytes)
+    {
+      const file_ptr max_chunk_size = 0x800000;
+      file_ptr chunk_size = nbytes - nread;
+      file_ptr chunk_nread;
+
+      if (chunk_size > max_chunk_size)
+        chunk_size = max_chunk_size;
+
+      chunk_nread = cache_bread_1 (abfd, (char *) buf + nread, chunk_size);
+
+      /* Update the nread count.
+
+         We just have to be careful of the case when cache_bread_1 returns
+         a negative count:  If this is our first read, then set nread to
+         that negative count in order to return that negative value to the
+         caller.  Otherwise, don't add it to our total count, or we would
+         end up returning a smaller number of bytes read than we actually
+         did.  */
+      if (nread == 0 || chunk_nread > 0)
+        nread += chunk_nread;
+
+      if (chunk_nread < chunk_size)
+        break;
+    }
+
+  return nread;
+}
+
 static file_ptr
 cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes)
 {
   file_ptr nwrite;
-  FILE *f = bfd_cache_lookup (abfd, 0);
+  FILE *f = bfd_cache_lookup (abfd, CACHE_NORMAL);
+
   if (f == NULL)
     return 0;
   nwrite = fwrite (where, 1, nbytes, f);
@@ -327,6 +369,7 @@ cache_bflush (struct bfd *abfd)
 {
   int sts;
   FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN);
+
   if (f == NULL)
     return 0;
   sts = fflush (f);
@@ -340,6 +383,7 @@ cache_bstat (struct bfd *abfd, struct stat *sb)
 {
   int sts;
   FILE *f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR);
+
   if (f == NULL)
     return -1;
   sts = fstat (fileno (f), sb);
@@ -348,9 +392,38 @@ cache_bstat (struct bfd *abfd, struct stat *sb)
   return sts;
 }
 
-static const struct bfd_iovec cache_iovec = {
+static void *
+cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
+            void *addr ATTRIBUTE_UNUSED,
+            bfd_size_type len ATTRIBUTE_UNUSED,
+            int prot ATTRIBUTE_UNUSED,
+            int flags ATTRIBUTE_UNUSED,
+            file_ptr offset ATTRIBUTE_UNUSED)
+{
+  void *ret = (void *) -1;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    abort ();
+#ifdef HAVE_MMAP
+  else
+    {
+      FILE *f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR);
+      if (f == NULL)
+       return ret;
+
+      ret = mmap (addr, len, prot, flags, fileno (f), offset);
+      if (ret == (void *) -1)
+       bfd_set_error (bfd_error_system_call);
+    }
+#endif
+
+  return ret;
+}
+
+static const struct bfd_iovec cache_iovec =
+{
   &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek,
-  &cache_bclose, &cache_bflush, &cache_bstat
+  &cache_bclose, &cache_bflush, &cache_bstat, &cache_bmmap
 };
 
 /*
This page took 0.02489 seconds and 4 git commands to generate.