+ FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN);
+ if (f == NULL)
+ return abfd->where;
+ return real_ftell (f);
+}
+
+static int
+cache_bseek (struct bfd *abfd, file_ptr offset, int whence)
+{
+ 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);
+}
+
+/* Note that archive entries don't have streams; they share their parent's.
+ This allows someone to play with the iostream behind BFD's back.
+
+ Also, note that the origin pointer points to the beginning of a file's
+ contents (0 for non-archive elements). For archive entries this is the
+ first octet in the file, NOT the beginning of the archive header. */
+
+static file_ptr
+cache_bread_1 (struct bfd *abfd, void *buf, file_ptr nbytes)
+{
+ FILE *f;
+ file_ptr nread;
+ /* FIXME - this looks like an optimization, but it's really to cover
+ up for a feature of some OSs (not solaris - sigh) that
+ ld/pe-dll.c takes advantage of (apparently) when it creates BFDs
+ internally and tries to link against them. BFD seems to be smart
+ enough to realize there are no symbol records in the "file" that
+ doesn't exist but attempts to read them anyway. On Solaris,
+ attempting to read zero bytes from a NULL file results in a core
+ dump, but on other platforms it just returns zero bytes read.
+ This makes it to something reasonable. - DJ */
+ if (nbytes == 0)
+ return 0;
+
+ f = bfd_cache_lookup (abfd, CACHE_NORMAL);
+ if (f == NULL)
+ return 0;
+
+#if defined (__VAX) && defined (VMS)
+ /* Apparently fread on Vax VMS does not keep the record length
+ information. */
+ nread = read (fileno (f), buf, nbytes);
+ /* Set bfd_error if we did not read as much data as we expected. If
+ the read failed due to an error set the bfd_error_system_call,
+ else set bfd_error_file_truncated. */
+ if (nread == (file_ptr)-1)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return nread;
+ }
+#else
+ nread = fread (buf, 1, nbytes, f);
+ /* Set bfd_error if we did not read as much data as we expected. If
+ the read failed due to an error set the bfd_error_system_call,
+ else set bfd_error_file_truncated. */
+ if (nread < nbytes && ferror (f))
+ {
+ bfd_set_error (bfd_error_system_call);
+ return nread;
+ }
+#endif
+ if (nread < nbytes)
+ /* This may or may not be an error, but in case the calling code
+ bails out because of it, set the right error code. */
+ bfd_set_error (bfd_error_file_truncated);
+ 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, CACHE_NORMAL);
+
+ if (f == NULL)
+ return 0;
+ nwrite = fwrite (where, 1, nbytes, f);
+ if (nwrite < nbytes && ferror (f))
+ {
+ bfd_set_error (bfd_error_system_call);
+ return -1;
+ }
+ return nwrite;