// fileread.cc -- read files for gold
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
#include "dirsearch.h"
#include "target.h"
#include "binary.h"
+#include "descriptors.h"
#include "fileread.h"
namespace gold
unsigned long long File_read::current_mapped_bytes;
unsigned long long File_read::maximum_mapped_bytes;
-// The File_read class is designed to support file descriptor caching,
-// but this is not currently implemented.
-
File_read::~File_read()
{
gold_assert(this->token_.is_writable());
- if (this->descriptor_ >= 0)
+ if (this->is_descriptor_opened_)
{
- if (close(this->descriptor_) < 0)
- gold_warning(_("close of %s failed: %s"),
- this->name_.c_str(), strerror(errno));
+ release_descriptor(this->descriptor_, true);
this->descriptor_ = -1;
+ this->is_descriptor_opened_ = false;
}
this->name_.clear();
this->clear_views(true);
{
gold_assert(this->token_.is_writable()
&& this->descriptor_ < 0
+ && !this->is_descriptor_opened_
&& this->name_.empty());
this->name_ = name;
- this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
+ this->descriptor_ = open_descriptor(-1, this->name_.c_str(),
+ O_RDONLY);
if (this->descriptor_ >= 0)
{
+ this->is_descriptor_opened_ = true;
struct stat s;
if (::fstat(this->descriptor_, &s) < 0)
gold_error(_("%s: fstat failed: %s"),
this->size_ = s.st_size;
gold_debug(DEBUG_FILES, "Attempt to open %s succeeded",
this->name_.c_str());
- }
- this->token_.add_writer(task);
+ this->token_.add_writer(task);
+ }
return this->descriptor_ >= 0;
}
{
gold_assert(this->token_.is_writable()
&& this->descriptor_ < 0
+ && !this->is_descriptor_opened_
&& this->name_.empty());
this->name_ = name;
this->contents_ = contents;
return true;
}
+// Reopen a descriptor if necessary.
+
+void
+File_read::reopen_descriptor()
+{
+ if (!this->is_descriptor_opened_)
+ {
+ this->descriptor_ = open_descriptor(this->descriptor_,
+ this->name_.c_str(),
+ O_RDONLY);
+ if (this->descriptor_ < 0)
+ gold_fatal(_("could not reopen file %s"), this->name_.c_str());
+ this->is_descriptor_opened_ = true;
+ }
+}
+
// Release the file. This is called when we are done with the file in
// a Task.
File_read::maximum_mapped_bytes = File_read::current_mapped_bytes;
// Only clear views if there is only one attached object. Otherwise
- // we waste time trying to clear cached archive views.
+ // we waste time trying to clear cached archive views. Similarly
+ // for releasing the descriptor.
if (this->object_count_ <= 1)
- this->clear_views(false);
+ {
+ this->clear_views(false);
+ if (this->is_descriptor_opened_)
+ {
+ release_descriptor(this->descriptor_, false);
+ this->is_descriptor_opened_ = false;
+ }
+ }
this->released_ = true;
}
// the buffer at P.
void
-File_read::do_read(off_t start, section_size_type size, void* p) const
+File_read::do_read(off_t start, section_size_type size, void* p)
{
ssize_t bytes;
if (this->contents_ != NULL)
}
else
{
+ this->reopen_descriptor();
bytes = ::pread(this->descriptor_, p, size, start);
if (static_cast<section_size_type>(bytes) == size)
return;
// Read data from the file.
void
-File_read::read(off_t start, section_size_type size, void* p) const
+File_read::read(off_t start, section_size_type size, void* p)
{
const File_read::View* pv = this->find_view(start, size, -1U, NULL);
if (pv != NULL)
{
gold_assert(size > 0);
+ // Check that start and end of the view are within the file.
+ if (start > this->size_
+ || (static_cast<unsigned long long>(size)
+ > static_cast<unsigned long long>(this->size_ - start)))
+ gold_fatal(_("%s: attempt to map %lld bytes at offset %lld exceeds "
+ "size of file; the file may be corrupt"),
+ this->filename().c_str(),
+ static_cast<long long>(size),
+ static_cast<long long>(start));
+
off_t poff = File_read::page_offset(start);
section_size_type psize = File_read::pages(size + (start - poff));
}
else
{
+ this->reopen_descriptor();
void* p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE,
this->descriptor_, poff);
if (p == MAP_FAILED)
last_offset = i_entry.file_offset + i_entry.size;
}
+ this->reopen_descriptor();
+
gold_assert(iov_index < sizeof iov / sizeof iov[0]);
if (::lseek(this->descriptor_, base + first_offset, SEEK_SET) < 0)
this->input_argument_ =
new Input_file_argument(name, false, "", false,
Position_dependent_options());
- bool ok = file_.open(task, name, contents, size);
+ bool ok = this->file_.open(task, name, contents, size);
gold_assert(ok);
}
return this->input_argument_->name();
}
+// Return whether this file is in a system directory.
+
+bool
+Input_file::is_in_system_directory() const
+{
+ if (this->is_in_sysroot())
+ return true;
+ return parameters->options().is_in_system_directory(this->filename());
+}
+
// Return whether we are only reading symbols.
bool
return this->input_argument_->just_symbols();
}
+// Return whether this is a file that we will search for in the list
+// of directories.
+
+bool
+Input_file::will_search_for() const
+{
+ return (!IS_ABSOLUTE_PATH(this->input_argument_->name())
+ && (this->input_argument_->is_lib()
+ || this->input_argument_->extra_search_path() != NULL));
+}
+
// Open the file.
// If the filename is not absolute, we assume it is in the current
// the file location, rather than the current directory.
bool
-Input_file::open(const General_options& options, const Dirsearch& dirpath,
- const Task* task)
+Input_file::open(const Dirsearch& dirpath, const Task* task, int *pindex)
{
std::string name;
// Case 1: name is an absolute file, just try to open it
// Case 2: name is relative but is_lib is false and extra_search_path
// is empty
- if (IS_ABSOLUTE_PATH (this->input_argument_->name())
+ if (IS_ABSOLUTE_PATH(this->input_argument_->name())
|| (!this->input_argument_->is_lib()
&& this->input_argument_->extra_search_path() == NULL))
{
std::string n1("lib");
n1 += this->input_argument_->name();
std::string n2;
- if (options.is_static()
+ if (parameters->options().is_static()
|| !this->input_argument_->options().Bdynamic())
n1 += ".a";
else
n2 = n1 + ".a";
n1 += ".so";
}
- name = dirpath.find(n1, n2, &this->is_in_sysroot_);
+ name = dirpath.find(n1, n2, &this->is_in_sysroot_, pindex);
if (name.empty())
{
gold_error(_("cannot find -l%s"),
name += '/';
name += this->input_argument_->name();
struct stat dummy_stat;
- if (::stat(name.c_str(), &dummy_stat) < 0)
+ if (*pindex > 0 || ::stat(name.c_str(), &dummy_stat) < 0)
{
// extra_search_path failed, so check the normal search-path.
+ int index = *pindex;
+ if (index > 0)
+ --index;
name = dirpath.find(this->input_argument_->name(), "",
- &this->is_in_sysroot_);
+ &this->is_in_sysroot_, &index);
if (name.empty())
{
gold_error(_("cannot find %s"),
this->input_argument_->name());
return false;
}
+ *pindex = index + 1;
}
this->found_name_ = this->input_argument_->name();
}
else
{
gold_assert(format == General_options::OBJECT_FORMAT_BINARY);
- ok = this->open_binary(options, task, name);
+ ok = this->open_binary(task, name);
}
if (!ok)
// Open a file for --format binary.
bool
-Input_file::open_binary(const General_options&,
- const Task* task, const std::string& name)
+Input_file::open_binary(const Task* task, const std::string& name)
{
// In order to open a binary file, we need machine code, size, and
// endianness. We may not have a valid target at this point, in