1 // fileread.cc -- read files for gold
3 // Copyright 2006, 2007 Free Software Foundation, Inc.
4 // Written by Ian Lance Taylor <iant@google.com>.
6 // This file is part of gold.
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 // MA 02110-1301, USA.
32 #include "dirsearch.h"
38 // Class File_read::View.
40 File_read::View::~View()
42 gold_assert(!this->is_locked());
47 if (::munmap(const_cast<unsigned char*>(this->data_
), this->size_
) != 0)
48 fprintf(stderr
, _("%s: munmap failed: %s\n"),
49 program_name
, strerror(errno
));
54 File_read::View::lock()
60 File_read::View::unlock()
62 gold_assert(this->lock_count_
> 0);
67 File_read::View::is_locked()
69 return this->lock_count_
> 0;
74 // The File_read class is designed to support file descriptor caching,
75 // but this is not currently implemented.
77 File_read::~File_read()
79 gold_assert(this->lock_count_
== 0);
80 if (this->descriptor_
>= 0)
82 if (close(this->descriptor_
) < 0)
83 fprintf(stderr
, _("%s: warning: close(%s) failed: %s"),
84 program_name
, this->name_
.c_str(), strerror(errno
));
85 this->descriptor_
= -1;
88 this->clear_views(true);
94 File_read::open(const std::string
& name
)
96 gold_assert(this->lock_count_
== 0
97 && this->descriptor_
< 0
98 && this->name_
.empty());
101 this->descriptor_
= ::open(this->name_
.c_str(), O_RDONLY
);
103 if (this->descriptor_
>= 0)
106 if (::fstat(this->descriptor_
, &s
) < 0)
108 fprintf(stderr
, _("%s: %s: fstat failed: %s"), program_name
,
109 this->name_
.c_str(), strerror(errno
));
112 this->size_
= s
.st_size
;
117 return this->descriptor_
>= 0;
120 // Open the file for testing purposes.
123 File_read::open(const std::string
& name
, const unsigned char* contents
,
126 gold_assert(this->lock_count_
== 0
127 && this->descriptor_
< 0
128 && this->name_
.empty());
130 this->contents_
= contents
;
145 gold_assert(this->lock_count_
> 0);
147 if (this->lock_count_
== 0)
148 this->clear_views(false);
152 File_read::is_locked()
154 return this->lock_count_
> 0;
157 // See if we have a view which covers the file starting at START for
158 // SIZE bytes. Return a pointer to the View if found, NULL if not.
160 inline File_read::View
*
161 File_read::find_view(off_t start
, off_t size
)
163 off_t page
= File_read::page_offset(start
);
164 Views::iterator p
= this->views_
.find(page
);
165 if (p
== this->views_
.end())
167 if (p
->second
->size() - (start
- page
) < size
)
172 // Read SIZE bytes from the file starting at offset START. Read into
176 File_read::do_read(off_t start
, off_t size
, void* p
)
178 gold_assert(this->lock_count_
> 0);
181 if (this->contents_
!= NULL
)
183 bytes
= this->size_
- start
;
186 memcpy(p
, this->contents_
+ start
, size
);
192 bytes
= ::pread(this->descriptor_
, p
, size
, start
);
198 fprintf(stderr
, _("%s: %s: pread failed: %s\n"),
199 program_name
, this->filename().c_str(), strerror(errno
));
205 _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
206 program_name
, this->filename().c_str(),
207 static_cast<long long>(bytes
),
208 static_cast<long long>(size
),
209 static_cast<long long>(start
));
213 // Read data from the file.
216 File_read::read(off_t start
, off_t size
, void* p
)
218 gold_assert(this->lock_count_
> 0);
220 File_read::View
* pv
= this->find_view(start
, size
);
223 memcpy(p
, pv
->data() + (start
- pv
->start()), size
);
227 this->do_read(start
, size
, p
);
230 // Find an existing view or make a new one.
233 File_read::find_or_make_view(off_t start
, off_t size
, bool cache
)
235 gold_assert(this->lock_count_
> 0);
237 off_t poff
= File_read::page_offset(start
);
239 File_read::View
* const vnull
= NULL
;
240 std::pair
<Views::iterator
, bool> ins
=
241 this->views_
.insert(std::make_pair(poff
, vnull
));
245 // There was an existing view at this offset.
246 File_read::View
* v
= ins
.first
->second
;
247 if (v
->size() - (start
- v
->start()) >= size
)
254 // This view is not large enough.
255 this->saved_views_
.push_back(v
);
258 // We need to read data from the file. We read full pages for
259 // greater efficiency on small files.
261 off_t psize
= File_read::pages(size
+ (start
- poff
));
263 if (poff
+ psize
>= this->size_
)
265 psize
= this->size_
- poff
;
266 gold_assert(psize
>= size
);
271 if (this->contents_
!= NULL
)
273 unsigned char* p
= new unsigned char[psize
];
274 this->do_read(poff
, psize
, p
);
275 v
= new File_read::View(poff
, psize
, p
, cache
, false);
279 void* p
= ::mmap(NULL
, psize
, PROT_READ
, MAP_SHARED
,
280 this->descriptor_
, poff
);
283 fprintf(stderr
, _("%s: %s: mmap offset %lld size %lld failed: %s\n"),
284 program_name
, this->filename().c_str(),
285 static_cast<long long>(poff
),
286 static_cast<long long>(psize
),
291 const unsigned char* pbytes
= static_cast<const unsigned char*>(p
);
292 v
= new File_read::View(poff
, psize
, pbytes
, cache
, true);
295 ins
.first
->second
= v
;
299 // This implementation of get_view just reads into a memory buffer,
300 // which we store on view_list_. At some point we should support
304 File_read::get_view(off_t start
, off_t size
, bool cache
)
306 gold_assert(this->lock_count_
> 0);
307 File_read::View
* pv
= this->find_or_make_view(start
, size
, cache
);
308 return pv
->data() + (start
- pv
->start());
312 File_read::get_lasting_view(off_t start
, off_t size
, bool cache
)
314 gold_assert(this->lock_count_
> 0);
315 File_read::View
* pv
= this->find_or_make_view(start
, size
, cache
);
317 return new File_view(*this, pv
, pv
->data() + (start
- pv
->start()));
320 // Remove all the file views.
323 File_read::clear_views(bool destroying
)
325 for (Views::iterator p
= this->views_
.begin();
326 p
!= this->views_
.end();
329 if (!p
->second
->is_locked()
330 && (destroying
|| !p
->second
->should_cache()))
334 gold_assert(!destroying
);
335 this->saved_views_
.push_back(p
->second
);
338 this->views_
.clear();
340 Saved_views::iterator p
= this->saved_views_
.begin();
341 while (p
!= this->saved_views_
.end())
343 if (!(*p
)->is_locked()
344 && (destroying
|| !(*p
)->should_cache()))
347 p
= this->saved_views_
.erase(p
);
351 gold_assert(!destroying
);
359 File_view::~File_view()
361 gold_assert(this->file_
.is_locked());
362 this->view_
->unlock();
367 // Create a file for testing.
369 Input_file::Input_file(const char* name
, const unsigned char* contents
,
373 this->input_argument_
=
374 new Input_file_argument(name
, false, Position_dependent_options());
375 bool ok
= file_
.open(name
, contents
, size
);
382 Input_file::open(const General_options
& options
, const Dirsearch
& dirpath
)
385 if (!this->input_argument_
->is_lib())
386 name
= this->input_argument_
->name();
389 std::string
n1("lib");
390 n1
+= this->input_argument_
->name();
392 if (options
.is_static())
399 name
= dirpath
.find(n1
, n2
);
402 fprintf(stderr
, _("%s: cannot find %s\n"), program_name
,
403 this->input_argument_
->name());
408 if (!this->file_
.open(name
))
410 fprintf(stderr
, _("%s: cannot open %s: %s\n"), program_name
,
411 name
.c_str(), strerror(errno
));
416 } // End namespace gold.