1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44: #include "sysdep.h"
45: #include "bfd.h"
46: #include "libbfd.h"
47: #include "libiberty.h"
48:
49:
50:
51:
52:
53:
54:
55:
56:
57: enum cache_flag {
58: CACHE_NORMAL = 0,
59: CACHE_NO_OPEN = 1,
60: CACHE_NO_SEEK = 2,
61: CACHE_NO_SEEK_ERROR = 4
62: };
63:
64:
65:
66:
67: #define BFD_CACHE_MAX_OPEN 10
68:
69:
70:
71: static int open_files;
72:
73:
74:
75:
76:
77: static bfd *bfd_last_cache = NULL;
78:
79:
80:
81: static void
82: insert (bfd *abfd)
83: {
84: if (bfd_last_cache == NULL)
85: {
86: abfd->lru_next = abfd;
87: abfd->lru_prev = abfd;
88: }
89: else
90: {
91: abfd->lru_next = bfd_last_cache;
92: abfd->lru_prev = bfd_last_cache->lru_prev;
93: abfd->lru_prev->lru_next = abfd;
94: abfd->lru_next->lru_prev = abfd;
95: }
96: bfd_last_cache = abfd;
97: }
98:
99:
100:
101: static void
102: snip (bfd *abfd)
103: {
104: abfd->lru_prev->lru_next = abfd->lru_next;
105: abfd->lru_next->lru_prev = abfd->lru_prev;
106: if (abfd == bfd_last_cache)
107: {
108: bfd_last_cache = abfd->lru_next;
109: if (abfd == bfd_last_cache)
110: bfd_last_cache = NULL;
111: }
112: }
113:
114:
115:
116: static bfd_boolean
117: bfd_cache_delete (bfd *abfd)
118: {
119: bfd_boolean ret;
120:
121: if (fclose ((FILE *) abfd->iostream) == 0)
122: ret = TRUE;
123: else
124: {
125: ret = FALSE;
126: bfd_set_error (bfd_error_system_call);
127: }
128:
129: snip (abfd);
130:
131: abfd->iostream = NULL;
132: --open_files;
133:
134: return ret;
135: }
136:
137:
138:
139:
140: static bfd_boolean
141: close_one (void)
142: {
143: register bfd *kill;
144:
145: if (bfd_last_cache == NULL)
146: kill = NULL;
147: else
148: {
149: for (kill = bfd_last_cache->lru_prev;
150: ! kill->cacheable;
151: kill = kill->lru_prev)
152: {
153: if (kill == bfd_last_cache)
154: {
155: kill = NULL;
156: break;
157: }
158: }
159: }
160:
161: if (kill == NULL)
162: {
163:
164: return TRUE;
165: }
166:
167: kill->where = real_ftell ((FILE *) kill->iostream);
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179: if (kill->direction == no_direction || kill->direction == read_direction)
180: {
181: bfd_get_mtime (kill);
182: kill->mtime_set = TRUE;
183: }
184:
185: return bfd_cache_delete (kill);
186: }
187:
188:
189:
190:
191:
192:
193: #define bfd_cache_lookup(x, flag) \
194: ((x) == bfd_last_cache \
195: ? (FILE *) (bfd_last_cache->iostream) \
196: : bfd_cache_lookup_worker (x, flag))
197:
198:
199:
200:
201:
202:
203:
204:
205: static FILE *
206: bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag)
207: {
208: bfd *orig_bfd = abfd;
209: if ((abfd->flags & BFD_IN_MEMORY) != 0)
210: abort ();
211:
212: if (abfd->my_archive)
213: abfd = abfd->my_archive;
214:
215: if (abfd->iostream != NULL)
216: {
217:
218: if (abfd != bfd_last_cache)
219: {
220: snip (abfd);
221: insert (abfd);
222: }
223: return (FILE *) abfd->iostream;
224: }
225:
226: if (flag & CACHE_NO_OPEN)
227: return NULL;
228:
229: if (bfd_open_file (abfd) == NULL)
230: ;
231: else if (!(flag & CACHE_NO_SEEK)
232: && real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0
233: && !(flag & CACHE_NO_SEEK_ERROR))
234: bfd_set_error (bfd_error_system_call);
235: else
236: return (FILE *) abfd->iostream;
237:
238: (*_bfd_error_handler) (_("reopening %B: %s\n"),
239: orig_bfd, bfd_errmsg (bfd_get_error ()));
240: return NULL;
241: }
242:
243: static file_ptr
244: cache_btell (struct bfd *abfd)
245: {
246: FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN);
247: if (f == NULL)
248: return abfd->where;
249: return real_ftell (f);
250: }
251:
252: static int
253: cache_bseek (struct bfd *abfd, file_ptr offset, int whence)
254: {
255: FILE *f = bfd_cache_lookup (abfd, whence != SEEK_CUR ? CACHE_NO_SEEK : 0);
256: if (f == NULL)
257: return -1;
258: return real_fseek (f, offset, whence);
259: }
260:
261:
262:
263:
264:
265:
266:
267:
268: static file_ptr
269: cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
270: {
271: FILE *f;
272: file_ptr nread;
273:
274:
275:
276:
277:
278:
279:
280:
281:
282: if (nbytes == 0)
283: return 0;
284:
285: f = bfd_cache_lookup (abfd, 0);
286: if (f == NULL)
287: return 0;
288:
289: #if defined (__VAX) && defined (VMS)
290:
291:
292: nread = read (fileno (f), buf, nbytes);
293:
294:
295:
296: if (nread == (file_ptr)-1)
297: {
298: bfd_set_error (bfd_error_system_call);
299: return -1;
300: }
301: #else
302: nread = fread (buf, 1, nbytes, f);
303:
304:
305:
306: if (nread < nbytes && ferror (f))
307: {
308: bfd_set_error (bfd_error_system_call);
309: return -1;
310: }
311: #endif
312: return nread;
313: }
314:
315: static file_ptr
316: cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes)
317: {
318: file_ptr nwrite;
319: FILE *f = bfd_cache_lookup (abfd, 0);
320: if (f == NULL)
321: return 0;
322: nwrite = fwrite (where, 1, nbytes, f);
323: if (nwrite < nbytes && ferror (f))
324: {
325: bfd_set_error (bfd_error_system_call);
326: return -1;
327: }
328: return nwrite;
329: }
330:
331: static int
332: cache_bclose (struct bfd *abfd)
333: {
334: return bfd_cache_close (abfd);
335: }
336:
337: static int
338: cache_bflush (struct bfd *abfd)
339: {
340: int sts;
341: FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN);
342: if (f == NULL)
343: return 0;
344: sts = fflush (f);
345: if (sts < 0)
346: bfd_set_error (bfd_error_system_call);
347: return sts;
348: }
349:
350: static int
351: cache_bstat (struct bfd *abfd, struct stat *sb)
352: {
353: int sts;
354: FILE *f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR);
355: if (f == NULL)
356: return -1;
357: sts = fstat (fileno (f), sb);
358: if (sts < 0)
359: bfd_set_error (bfd_error_system_call);
360: return sts;
361: }
362:
363: static const struct bfd_iovec cache_iovec = {
364: &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek,
365: &cache_bclose, &cache_bflush, &cache_bstat
366: };
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379: bfd_boolean
380: bfd_cache_init (bfd *abfd)
381: {
382: BFD_ASSERT (abfd->iostream != NULL);
383: if (open_files >= BFD_CACHE_MAX_OPEN)
384: {
385: if (! close_one ())
386: return FALSE;
387: }
388: abfd->iovec = &cache_iovec;
389: insert (abfd);
390: ++open_files;
391: return TRUE;
392: }
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410: bfd_boolean
411: bfd_cache_close (bfd *abfd)
412: {
413: if (abfd->iovec != &cache_iovec)
414: return TRUE;
415:
416: if (abfd->iostream == NULL)
417:
418: return TRUE;
419:
420: return bfd_cache_delete (abfd);
421: }
422:
423:
424:
425:
426:
427:
428:
429:
430:
431:
432:
433:
434:
435:
436:
437:
438:
439: bfd_boolean
440: bfd_cache_close_all ()
441: {
442: bfd_boolean ret = TRUE;
443:
444: while (bfd_last_cache != NULL)
445: ret &= bfd_cache_close (bfd_last_cache);
446:
447: return ret;
448: }
449:
450:
451:
452:
453:
454:
455:
456:
457:
458:
459:
460:
461:
462:
463:
464:
465: FILE *
466: bfd_open_file (bfd *abfd)
467: {
468: abfd->cacheable = TRUE;
469:
470: if (open_files >= BFD_CACHE_MAX_OPEN)
471: {
472: if (! close_one ())
473: return NULL;
474: }
475:
476: switch (abfd->direction)
477: {
478: case read_direction:
479: case no_direction:
480: abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_RB);
481: break;
482: case both_direction:
483: case write_direction:
484: if (abfd->opened_once)
485: {
486: abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_RUB);
487: if (abfd->iostream == NULL)
488: abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_WUB);
489: }
490: else
491: {
492:
493:
494:
495:
496:
497:
498:
499:
500:
501:
502:
503:
504:
505:
506:
507: #ifndef __MSDOS__
508:
509:
510:
511:
512:
513: struct stat s;
514:
515: if (stat (abfd->filename, &s) == 0 && s.st_size != 0)
516: unlink_if_ordinary (abfd->filename);
517: #endif
518: abfd->iostream = (PTR) real_fopen (abfd->filename, FOPEN_WUB);
519: abfd->opened_once = TRUE;
520: }
521: break;
522: }
523:
524: if (abfd->iostream == NULL)
525: bfd_set_error (bfd_error_system_call);
526: else
527: {
528: if (! bfd_cache_init (abfd))
529: return NULL;
530: }
531:
532: return (FILE *) abfd->iostream;
533: }