1 |
/* BFD library -- caching of file descriptors. |
/* BFD library -- caching of file descriptors. |
2 |
Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002 |
|
3 |
Free Software Foundation, Inc. |
Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002, |
4 |
|
2003, 2004 Free Software Foundation, Inc. |
5 |
|
|
6 |
Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). |
Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). |
7 |
|
|
8 |
This file is part of BFD, the Binary File Descriptor library. |
This file is part of BFD, the Binary File Descriptor library. |
41 |
#include "bfd.h" |
#include "bfd.h" |
42 |
#include "sysdep.h" |
#include "sysdep.h" |
43 |
#include "libbfd.h" |
#include "libbfd.h" |
44 |
|
#include "libiberty.h" |
45 |
|
|
46 |
|
static bfd_boolean bfd_cache_delete (bfd *); |
47 |
|
|
48 |
|
|
49 |
|
static file_ptr |
50 |
|
cache_btell (struct bfd *abfd) |
51 |
|
{ |
52 |
|
return real_ftell (bfd_cache_lookup (abfd)); |
53 |
|
} |
54 |
|
|
55 |
|
static int |
56 |
|
cache_bseek (struct bfd *abfd, file_ptr offset, int whence) |
57 |
|
{ |
58 |
|
return real_fseek (bfd_cache_lookup (abfd), offset, whence); |
59 |
|
} |
60 |
|
|
61 |
|
/* Note that archive entries don't have streams; they share their parent's. |
62 |
|
This allows someone to play with the iostream behind BFD's back. |
63 |
|
|
64 |
|
Also, note that the origin pointer points to the beginning of a file's |
65 |
|
contents (0 for non-archive elements). For archive entries this is the |
66 |
|
first octet in the file, NOT the beginning of the archive header. */ |
67 |
|
|
68 |
|
static file_ptr |
69 |
|
cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes) |
70 |
|
{ |
71 |
|
file_ptr nread; |
72 |
|
/* FIXME - this looks like an optimization, but it's really to cover |
73 |
|
up for a feature of some OSs (not solaris - sigh) that |
74 |
|
ld/pe-dll.c takes advantage of (apparently) when it creates BFDs |
75 |
|
internally and tries to link against them. BFD seems to be smart |
76 |
|
enough to realize there are no symbol records in the "file" that |
77 |
|
doesn't exist but attempts to read them anyway. On Solaris, |
78 |
|
attempting to read zero bytes from a NULL file results in a core |
79 |
|
dump, but on other platforms it just returns zero bytes read. |
80 |
|
This makes it to something reasonable. - DJ */ |
81 |
|
if (nbytes == 0) |
82 |
|
return 0; |
83 |
|
|
84 |
|
#if defined (__VAX) && defined (VMS) |
85 |
|
/* Apparently fread on Vax VMS does not keep the record length |
86 |
|
information. */ |
87 |
|
nread = read (fileno (bfd_cache_lookup (abfd)), buf, nbytes); |
88 |
|
/* Set bfd_error if we did not read as much data as we expected. If |
89 |
|
the read failed due to an error set the bfd_error_system_call, |
90 |
|
else set bfd_error_file_truncated. */ |
91 |
|
if (nread == (file_ptr)-1) |
92 |
|
{ |
93 |
|
bfd_set_error (bfd_error_system_call); |
94 |
|
return -1; |
95 |
|
} |
96 |
|
#else |
97 |
|
nread = fread (buf, 1, nbytes, bfd_cache_lookup (abfd)); |
98 |
|
/* Set bfd_error if we did not read as much data as we expected. If |
99 |
|
the read failed due to an error set the bfd_error_system_call, |
100 |
|
else set bfd_error_file_truncated. */ |
101 |
|
if (nread < nbytes && ferror (bfd_cache_lookup (abfd))) |
102 |
|
{ |
103 |
|
bfd_set_error (bfd_error_system_call); |
104 |
|
return -1; |
105 |
|
} |
106 |
|
#endif |
107 |
|
return nread; |
108 |
|
} |
109 |
|
|
110 |
static void insert PARAMS ((bfd *)); |
static file_ptr |
111 |
static void snip PARAMS ((bfd *)); |
cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes) |
112 |
static boolean close_one PARAMS ((void)); |
{ |
113 |
static boolean bfd_cache_delete PARAMS ((bfd *)); |
file_ptr nwrite = fwrite (where, 1, nbytes, bfd_cache_lookup (abfd)); |
114 |
|
if (nwrite < nbytes && ferror (bfd_cache_lookup (abfd))) |
115 |
|
{ |
116 |
|
bfd_set_error (bfd_error_system_call); |
117 |
|
return -1; |
118 |
|
} |
119 |
|
return nwrite; |
120 |
|
} |
121 |
|
|
122 |
|
static int |
123 |
|
cache_bclose (struct bfd *abfd) |
124 |
|
{ |
125 |
|
return bfd_cache_close (abfd); |
126 |
|
} |
127 |
|
|
128 |
|
static int |
129 |
|
cache_bflush (struct bfd *abfd) |
130 |
|
{ |
131 |
|
int sts = fflush (bfd_cache_lookup (abfd)); |
132 |
|
if (sts < 0) |
133 |
|
bfd_set_error (bfd_error_system_call); |
134 |
|
return sts; |
135 |
|
} |
136 |
|
|
137 |
|
static int |
138 |
|
cache_bstat (struct bfd *abfd, struct stat *sb) |
139 |
|
{ |
140 |
|
int sts = fstat (fileno (bfd_cache_lookup (abfd)), sb); |
141 |
|
if (sts < 0) |
142 |
|
bfd_set_error (bfd_error_system_call); |
143 |
|
return sts; |
144 |
|
} |
145 |
|
|
146 |
|
static const struct bfd_iovec cache_iovec = { |
147 |
|
&cache_bread, &cache_bwrite, &cache_btell, &cache_bseek, |
148 |
|
&cache_bclose, &cache_bflush, &cache_bstat |
149 |
|
}; |
150 |
|
|
151 |
/* |
/* |
152 |
INTERNAL_FUNCTION |
INTERNAL_FUNCTION |
190 |
otherwise, it has to perform the complicated lookup function. |
otherwise, it has to perform the complicated lookup function. |
191 |
|
|
192 |
.#define bfd_cache_lookup(x) \ |
.#define bfd_cache_lookup(x) \ |
193 |
. ((x)==bfd_last_cache? \ |
. ((x) == bfd_last_cache ? \ |
194 |
. (FILE*) (bfd_last_cache->iostream): \ |
. (FILE *) (bfd_last_cache->iostream): \ |
195 |
. bfd_cache_lookup_worker(x)) |
. bfd_cache_lookup_worker (x)) |
196 |
|
|
197 |
*/ |
*/ |
198 |
|
|
199 |
/* Insert a BFD into the cache. */ |
/* Insert a BFD into the cache. */ |
200 |
|
|
201 |
static INLINE void |
static void |
202 |
insert (abfd) |
insert (bfd *abfd) |
|
bfd *abfd; |
|
203 |
{ |
{ |
204 |
if (bfd_last_cache == NULL) |
if (bfd_last_cache == NULL) |
205 |
{ |
{ |
218 |
|
|
219 |
/* Remove a BFD from the cache. */ |
/* Remove a BFD from the cache. */ |
220 |
|
|
221 |
static INLINE void |
static void |
222 |
snip (abfd) |
snip (bfd *abfd) |
|
bfd *abfd; |
|
223 |
{ |
{ |
224 |
abfd->lru_prev->lru_next = abfd->lru_next; |
abfd->lru_prev->lru_next = abfd->lru_next; |
225 |
abfd->lru_next->lru_prev = abfd->lru_prev; |
abfd->lru_next->lru_prev = abfd->lru_prev; |
234 |
/* We need to open a new file, and the cache is full. Find the least |
/* We need to open a new file, and the cache is full. Find the least |
235 |
recently used cacheable BFD and close it. */ |
recently used cacheable BFD and close it. */ |
236 |
|
|
237 |
static boolean |
static bfd_boolean |
238 |
close_one () |
close_one (void) |
239 |
{ |
{ |
240 |
register bfd *kill; |
register bfd *kill; |
241 |
|
|
258 |
if (kill == NULL) |
if (kill == NULL) |
259 |
{ |
{ |
260 |
/* There are no open cacheable BFD's. */ |
/* There are no open cacheable BFD's. */ |
261 |
return true; |
return TRUE; |
262 |
} |
} |
263 |
|
|
264 |
kill->where = ftell ((FILE *) kill->iostream); |
kill->where = real_ftell ((FILE *) kill->iostream); |
265 |
|
|
266 |
return bfd_cache_delete (kill); |
return bfd_cache_delete (kill); |
267 |
} |
} |
268 |
|
|
269 |
/* Close a BFD and remove it from the cache. */ |
/* Close a BFD and remove it from the cache. */ |
270 |
|
|
271 |
static boolean |
static bfd_boolean |
272 |
bfd_cache_delete (abfd) |
bfd_cache_delete (bfd *abfd) |
|
bfd *abfd; |
|
273 |
{ |
{ |
274 |
boolean ret; |
bfd_boolean ret; |
275 |
|
|
276 |
if (fclose ((FILE *) abfd->iostream) == 0) |
if (fclose ((FILE *) abfd->iostream) == 0) |
277 |
ret = true; |
ret = TRUE; |
278 |
else |
else |
279 |
{ |
{ |
280 |
ret = false; |
ret = FALSE; |
281 |
bfd_set_error (bfd_error_system_call); |
bfd_set_error (bfd_error_system_call); |
282 |
} |
} |
283 |
|
|
294 |
bfd_cache_init |
bfd_cache_init |
295 |
|
|
296 |
SYNOPSIS |
SYNOPSIS |
297 |
boolean bfd_cache_init (bfd *abfd); |
bfd_boolean bfd_cache_init (bfd *abfd); |
298 |
|
|
299 |
DESCRIPTION |
DESCRIPTION |
300 |
Add a newly opened BFD to the cache. |
Add a newly opened BFD to the cache. |
301 |
*/ |
*/ |
302 |
|
|
303 |
boolean |
bfd_boolean |
304 |
bfd_cache_init (abfd) |
bfd_cache_init (bfd *abfd) |
|
bfd *abfd; |
|
305 |
{ |
{ |
306 |
BFD_ASSERT (abfd->iostream != NULL); |
BFD_ASSERT (abfd->iostream != NULL); |
307 |
if (open_files >= BFD_CACHE_MAX_OPEN) |
if (open_files >= BFD_CACHE_MAX_OPEN) |
308 |
{ |
{ |
309 |
if (! close_one ()) |
if (! close_one ()) |
310 |
return false; |
return FALSE; |
311 |
} |
} |
312 |
|
abfd->iovec = &cache_iovec; |
313 |
insert (abfd); |
insert (abfd); |
314 |
++open_files; |
++open_files; |
315 |
return true; |
return TRUE; |
316 |
} |
} |
317 |
|
|
318 |
/* |
/* |
320 |
bfd_cache_close |
bfd_cache_close |
321 |
|
|
322 |
SYNOPSIS |
SYNOPSIS |
323 |
boolean bfd_cache_close (bfd *abfd); |
bfd_boolean bfd_cache_close (bfd *abfd); |
324 |
|
|
325 |
DESCRIPTION |
DESCRIPTION |
326 |
Remove the BFD @var{abfd} from the cache. If the attached file is open, |
Remove the BFD @var{abfd} from the cache. If the attached file is open, |
327 |
then close it too. |
then close it too. |
328 |
|
|
329 |
RETURNS |
RETURNS |
330 |
<<false>> is returned if closing the file fails, <<true>> is |
<<FALSE>> is returned if closing the file fails, <<TRUE>> is |
331 |
returned if all is well. |
returned if all is well. |
332 |
*/ |
*/ |
333 |
|
|
334 |
boolean |
bfd_boolean |
335 |
bfd_cache_close (abfd) |
bfd_cache_close (bfd *abfd) |
336 |
bfd *abfd; |
{ |
337 |
{ |
if (abfd->iovec != &cache_iovec) |
338 |
if (abfd->iostream == NULL |
return TRUE; |
339 |
|| (abfd->flags & BFD_IN_MEMORY) != 0) |
|
340 |
return true; |
if (abfd->iostream == NULL) |
341 |
|
/* Previously closed. */ |
342 |
|
return TRUE; |
343 |
|
|
344 |
return bfd_cache_delete (abfd); |
return bfd_cache_delete (abfd); |
345 |
} |
} |
346 |
|
|
347 |
/* |
/* |
348 |
|
FUNCTION |
349 |
|
bfd_cache_close_all |
350 |
|
|
351 |
|
SYNOPSIS |
352 |
|
bfd_boolean bfd_cache_close_all (void); |
353 |
|
|
354 |
|
DESCRIPTION |
355 |
|
Remove all BFDs from the cache. If the attached file is open, |
356 |
|
then close it too. |
357 |
|
|
358 |
|
RETURNS |
359 |
|
<<FALSE>> is returned if closing one of the file fails, <<TRUE>> is |
360 |
|
returned if all is well. |
361 |
|
*/ |
362 |
|
|
363 |
|
bfd_boolean |
364 |
|
bfd_cache_close_all () |
365 |
|
{ |
366 |
|
bfd_boolean ret = TRUE; |
367 |
|
|
368 |
|
while (bfd_last_cache != NULL) |
369 |
|
ret &= bfd_cache_close (bfd_last_cache); |
370 |
|
|
371 |
|
return ret; |
372 |
|
} |
373 |
|
|
374 |
|
/* |
375 |
INTERNAL_FUNCTION |
INTERNAL_FUNCTION |
376 |
bfd_open_file |
bfd_open_file |
377 |
|
|
378 |
SYNOPSIS |
SYNOPSIS |
379 |
FILE* bfd_open_file(bfd *abfd); |
FILE* bfd_open_file (bfd *abfd); |
380 |
|
|
381 |
DESCRIPTION |
DESCRIPTION |
382 |
Call the OS to open a file for @var{abfd}. Return the <<FILE *>> |
Call the OS to open a file for @var{abfd}. Return the <<FILE *>> |
387 |
*/ |
*/ |
388 |
|
|
389 |
FILE * |
FILE * |
390 |
bfd_open_file (abfd) |
bfd_open_file (bfd *abfd) |
|
bfd *abfd; |
|
391 |
{ |
{ |
392 |
abfd->cacheable = true; /* Allow it to be closed later. */ |
abfd->cacheable = TRUE; /* Allow it to be closed later. */ |
393 |
|
|
394 |
if (open_files >= BFD_CACHE_MAX_OPEN) |
if (open_files >= BFD_CACHE_MAX_OPEN) |
395 |
{ |
{ |
437 |
struct stat s; |
struct stat s; |
438 |
|
|
439 |
if (stat (abfd->filename, &s) == 0 && s.st_size != 0) |
if (stat (abfd->filename, &s) == 0 && s.st_size != 0) |
440 |
unlink (abfd->filename); |
unlink_if_ordinary (abfd->filename); |
441 |
#endif |
#endif |
442 |
abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); |
abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); |
443 |
abfd->opened_once = true; |
abfd->opened_once = TRUE; |
444 |
} |
} |
445 |
break; |
break; |
446 |
} |
} |
459 |
bfd_cache_lookup_worker |
bfd_cache_lookup_worker |
460 |
|
|
461 |
SYNOPSIS |
SYNOPSIS |
462 |
FILE *bfd_cache_lookup_worker(bfd *abfd); |
FILE *bfd_cache_lookup_worker (bfd *abfd); |
463 |
|
|
464 |
DESCRIPTION |
DESCRIPTION |
465 |
Called when the macro <<bfd_cache_lookup>> fails to find a |
Called when the macro <<bfd_cache_lookup>> fails to find a |
466 |
quick answer. Find a file descriptor for @var{abfd}. If |
quick answer. Find a file descriptor for @var{abfd}. If |
467 |
necessary, it open it. If there are already more than |
necessary, it open it. If there are already more than |
468 |
<<BFD_CACHE_MAX_OPEN>> files open, it tries to close one first, to |
<<BFD_CACHE_MAX_OPEN>> files open, it tries to close one first, to |
469 |
avoid running out of file descriptors. |
avoid running out of file descriptors. It will abort rather than |
470 |
|
returning NULL if it is unable to (re)open the @var{abfd}. |
471 |
*/ |
*/ |
472 |
|
|
473 |
FILE * |
FILE * |
474 |
bfd_cache_lookup_worker (abfd) |
bfd_cache_lookup_worker (bfd *abfd) |
|
bfd *abfd; |
|
475 |
{ |
{ |
476 |
if ((abfd->flags & BFD_IN_MEMORY) != 0) |
if ((abfd->flags & BFD_IN_MEMORY) != 0) |
477 |
abort (); |
abort (); |
490 |
} |
} |
491 |
else |
else |
492 |
{ |
{ |
493 |
if (bfd_open_file (abfd) == NULL) |
if (bfd_open_file (abfd) == NULL |
494 |
return NULL; |
|| abfd->where != (unsigned long) abfd->where |
495 |
if (abfd->where != (unsigned long) abfd->where) |
|| real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0) |
496 |
return NULL; |
abort (); |
|
if (fseek ((FILE *) abfd->iostream, (long) abfd->where, SEEK_SET) != 0) |
|
|
return NULL; |
|
497 |
} |
} |
498 |
|
|
499 |
return (FILE *) abfd->iostream; |
return (FILE *) abfd->iostream; |