daily update
[deliverable/binutils-gdb.git] / gold / fileread.cc
CommitLineData
bae7f79e
ILT
1// fileread.cc -- read files for gold
2
6cb15b7f
ILT
3// Copyright 2006, 2007 Free Software Foundation, Inc.
4// Written by Ian Lance Taylor <iant@google.com>.
5
6// This file is part of gold.
7
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.
12
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.
17
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.
22
bae7f79e
ILT
23#include "gold.h"
24
bae7f79e
ILT
25#include <cstring>
26#include <cerrno>
27#include <fcntl.h>
28#include <unistd.h>
29
30#include "options.h"
31#include "dirsearch.h"
32#include "fileread.h"
33
34namespace gold
35{
36
37// Class File_read::View.
38
39File_read::View::~View()
40{
a3ad94ed 41 gold_assert(!this->is_locked());
bae7f79e
ILT
42 delete[] this->data_;
43}
44
45void
46File_read::View::lock()
47{
48 ++this->lock_count_;
49}
50
51void
52File_read::View::unlock()
53{
a3ad94ed 54 gold_assert(this->lock_count_ > 0);
bae7f79e
ILT
55 --this->lock_count_;
56}
57
58bool
59File_read::View::is_locked()
60{
61 return this->lock_count_ > 0;
62}
63
64// Class File_read.
65
66// The File_read class is designed to support file descriptor caching,
67// but this is not currently implemented.
68
69File_read::~File_read()
70{
a3ad94ed 71 gold_assert(this->lock_count_ == 0);
bae7f79e
ILT
72 if (this->descriptor_ >= 0)
73 {
74 if (close(this->descriptor_) < 0)
75 fprintf(stderr, _("%s: warning: close(%s) failed: %s"),
76 program_name, this->name_.c_str(), strerror(errno));
77 this->descriptor_ = -1;
78 }
79 this->name_.clear();
80 this->clear_views(true);
81}
82
5a6f7e2d
ILT
83// Open the file.
84
bae7f79e
ILT
85bool
86File_read::open(const std::string& name)
87{
a3ad94ed
ILT
88 gold_assert(this->lock_count_ == 0
89 && this->descriptor_ < 0
90 && this->name_.empty());
bae7f79e
ILT
91 this->name_ = name;
92 this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
93 ++this->lock_count_;
94 return this->descriptor_ >= 0;
95}
96
5a6f7e2d
ILT
97// Open the file for testing purposes.
98
99bool
100File_read::open(const std::string& name, const unsigned char* contents,
101 off_t contents_size)
bae7f79e 102{
5a6f7e2d
ILT
103 gold_assert(this->lock_count_ == 0
104 && this->descriptor_ < 0
105 && this->name_.empty());
106 this->name_ = name;
107 this->contents_ = contents;
108 this->contents_size_ = contents_size;
109 ++this->lock_count_;
110 return true;
bae7f79e
ILT
111}
112
113void
114File_read::lock()
115{
116 ++this->lock_count_;
117}
118
119void
120File_read::unlock()
121{
a3ad94ed 122 gold_assert(this->lock_count_ > 0);
bae7f79e
ILT
123 --this->lock_count_;
124}
125
126bool
127File_read::is_locked()
128{
129 return this->lock_count_ > 0;
130}
131
132// See if we have a view which covers the file starting at START for
133// SIZE bytes. Return a pointer to the View if found, NULL if not.
134
ead1e424 135inline File_read::View*
bae7f79e
ILT
136File_read::find_view(off_t start, off_t size)
137{
ead1e424
ILT
138 off_t page = File_read::page_offset(start);
139 Views::iterator p = this->views_.find(page);
140 if (p == this->views_.end())
141 return NULL;
142 if (p->second->size() - (start - page) < size)
143 return NULL;
144 return p->second;
bae7f79e
ILT
145}
146
147// Read data from the file. Return the number of bytes read. If
148// PBYTES is not NULL, store the number of bytes in *PBYTES, otherwise
149// require that we read exactly the number of bytes requested.
150
151off_t
152File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
153{
a3ad94ed 154 gold_assert(this->lock_count_ > 0);
bae7f79e 155
5a6f7e2d
ILT
156 off_t bytes;
157 if (this->contents_ == NULL)
bae7f79e 158 {
5a6f7e2d 159 int o = this->descriptor_;
bae7f79e 160
5a6f7e2d
ILT
161 if (lseek(o, start, SEEK_SET) < 0)
162 {
163 fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"),
164 program_name, this->filename().c_str(),
165 static_cast<long long>(start),
166 strerror(errno));
167 gold_exit(false);
168 }
169
170 bytes = ::read(o, p, size);
171 if (bytes < 0)
172 {
173 fprintf(stderr, _("%s: %s: read failed: %s\n"),
174 program_name, this->filename().c_str(), strerror(errno));
175 gold_exit(false);
176 }
177 }
178 else
bae7f79e 179 {
5a6f7e2d
ILT
180 bytes = this->contents_size_ - start;
181 if (bytes < 0)
182 bytes = 0;
183 else if (bytes > size)
184 bytes = size;
185 memcpy(p, this->contents_ + start, bytes);
bae7f79e
ILT
186 }
187
188 if (pbytes != NULL)
189 *pbytes = bytes;
190 else if (bytes != size)
191 {
192 fprintf(stderr,
193 _("%s: %s: file too short: read only %lld of %lld "
194 "bytes at %lld\n"),
195 program_name, this->filename().c_str(),
196 static_cast<long long>(bytes),
197 static_cast<long long>(size),
198 static_cast<long long>(start));
199 gold_exit(false);
200 }
201
202 return bytes;
203}
204
205void
206File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
207{
a3ad94ed 208 gold_assert(this->lock_count_ > 0);
bae7f79e
ILT
209
210 File_read::View* pv = this->find_view(start, size);
211 if (pv != NULL)
212 {
213 memcpy(p, pv->data() + (start - pv->start()), size);
214 if (pbytes != NULL)
215 *pbytes = size;
216 return;
217 }
218
219 this->do_read(start, size, p, pbytes);
220}
221
222// Find an existing view or make a new one.
223
224File_read::View*
225File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
226{
a3ad94ed 227 gold_assert(this->lock_count_ > 0);
bae7f79e 228
ead1e424
ILT
229 off_t poff = File_read::page_offset(start);
230
231 File_read::View* const vnull = NULL;
232 std::pair<Views::iterator, bool> ins =
233 this->views_.insert(std::make_pair(poff, vnull));
234
235 if (!ins.second)
236 {
237 // There was an existing view at this offset.
238 File_read::View* v = ins.first->second;
239 if (v->size() - (start - v->start()) >= size)
240 {
241 if (pbytes != NULL)
242 *pbytes = size;
243 return v;
244 }
245
246 // This view is not large enough.
247 this->saved_views_.push_back(v);
248 }
249
250 // We need to read data from the file.
251
252 off_t psize = File_read::pages(size + (start - poff));
253 unsigned char* p = new unsigned char[psize];
bae7f79e 254
ead1e424
ILT
255 off_t got_bytes;
256 off_t bytes = this->do_read(poff, psize, p, &got_bytes);
257
258 File_read::View* v = new File_read::View(poff, bytes, p);
259
260 ins.first->second = v;
261
262 if (bytes - (start - poff) >= size)
263 {
264 if (pbytes != NULL)
265 *pbytes = size;
266 return v;
267 }
268
269 if (pbytes != NULL)
270 {
271 *pbytes = bytes - (start - poff);
272 return v;
273 }
274
275 fprintf(stderr,
276 _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
277 program_name, this->filename().c_str(),
278 static_cast<long long>(bytes - (start - poff)),
279 static_cast<long long>(size),
280 static_cast<long long>(start));
281 gold_exit(false);
bae7f79e
ILT
282}
283
284// This implementation of get_view just reads into a memory buffer,
285// which we store on view_list_. At some point we should support
286// mmap.
287
288const unsigned char*
289File_read::get_view(off_t start, off_t size, off_t* pbytes)
290{
a3ad94ed 291 gold_assert(this->lock_count_ > 0);
bae7f79e
ILT
292 File_read::View* pv = this->find_or_make_view(start, size, pbytes);
293 return pv->data() + (start - pv->start());
294}
295
296File_view*
297File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
298{
a3ad94ed 299 gold_assert(this->lock_count_ > 0);
bae7f79e
ILT
300 File_read::View* pv = this->find_or_make_view(start, size, pbytes);
301 pv->lock();
302 return new File_view(*this, pv, pv->data() + (start - pv->start()));
303}
304
305// Remove all the file views.
306
307void
308File_read::clear_views(bool destroying)
309{
ead1e424
ILT
310 for (Views::iterator p = this->views_.begin();
311 p != this->views_.end();
312 ++p)
bae7f79e 313 {
ead1e424
ILT
314 if (!p->second->is_locked())
315 delete p->second;
316 else
bae7f79e 317 {
a3ad94ed 318 gold_assert(!destroying);
ead1e424 319 this->saved_views_.push_back(p->second);
bae7f79e 320 }
ead1e424
ILT
321 }
322 this->views_.clear();
323
324 Saved_views::iterator p = this->saved_views_.begin();
325 while (p != this->saved_views_.end())
326 {
327 if (!(*p)->is_locked())
bae7f79e
ILT
328 {
329 delete *p;
ead1e424
ILT
330 p = this->saved_views_.erase(p);
331 }
332 else
333 {
a3ad94ed 334 gold_assert(!destroying);
ead1e424 335 ++p;
bae7f79e
ILT
336 }
337 }
338}
339
340// Class File_view.
341
342File_view::~File_view()
343{
a3ad94ed 344 gold_assert(this->file_.is_locked());
bae7f79e
ILT
345 this->view_->unlock();
346}
347
348// Class Input_file.
349
5a6f7e2d
ILT
350// Create a file for testing.
351
352Input_file::Input_file(const char* name, const unsigned char* contents,
353 off_t size)
354 : file_()
355{
356 this->input_argument_ =
357 new Input_file_argument(name, false, Position_dependent_options());
358 bool ok = file_.open(name, contents, size);
359 gold_assert(ok);
360}
361
362// Open the file.
363
bae7f79e
ILT
364void
365Input_file::open(const General_options& options, const Dirsearch& dirpath)
366{
367 std::string name;
5a6f7e2d
ILT
368 if (!this->input_argument_->is_lib())
369 name = this->input_argument_->name();
bae7f79e
ILT
370 else
371 {
372 std::string n1("lib");
5a6f7e2d 373 n1 += this->input_argument_->name();
bae7f79e 374 std::string n2;
f6ce93d6
ILT
375 if (options.is_static())
376 n1 += ".a";
377 else
378 {
379 n2 = n1 + ".a";
380 n1 += ".so";
381 }
bae7f79e
ILT
382 name = dirpath.find(n1, n2);
383 if (name.empty())
384 {
61ba1cf9 385 fprintf(stderr, _("%s: cannot find %s\n"), program_name,
5a6f7e2d 386 this->input_argument_->name());
bae7f79e
ILT
387 gold_exit(false);
388 }
389 }
390
391 if (!this->file_.open(name))
392 {
61ba1cf9
ILT
393 fprintf(stderr, _("%s: cannot open %s: %s\n"), program_name,
394 name.c_str(), strerror(errno));
bae7f79e
ILT
395 gold_exit(false);
396 }
397}
398
399} // End namespace gold.
This page took 0.126399 seconds and 4 git commands to generate.