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