Changed obstack_chunk_alloc to xmalloc
[platform/upstream/binutils.git] / bfd / opncls.c
1 /* opncls.c -- open and close a bfd. */
2
3 /* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
4
5 This file is part of BFD, the Binary File Diddler.
6
7 BFD is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 1, or (at your option)
10 any later version.
11
12 BFD is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with BFD; see the file COPYING.  If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* $Id$ */
22
23 #include <sysdep.h>
24 #include "bfd.h"
25 #include "libbfd.h"
26
27 extern void bfd_cache_init();
28 FILE *bfd_open_file();
29
30 /* fdopen is a loser -- we should use stdio exclusively.  Unfortunately
31    if we do that we can't use fcntl.  */
32 \f
33 /** Locking 
34
35    Locking is loosely controlled by the preprocessor variable
36    BFD_LOCKS.  I say loosely because Unix barely understands locking
37    -- at least in BSD it doesn't affect programs which don't
38    explicitly use it!  That is to say it's practically useless, though
39    if everyone uses this library you'll be OK.
40
41    From among the many and varied lock facilities available, (none of
42    which, of course, knows about any other) we use the fcntl locks,
43    because they're Posix.
44
45    The reason that bfd_openr and bfd_fdopenr exist, yet only bfd_openw
46    exists is because of locking.  When we do output, we lock the
47    filename file for output, then open a temporary file which does not
48    actually get its correct filename until closing time.  This is
49    safest, but requires the asymmetry in read and write entry points.
50
51    Perhaps, since unix has so many different kinds of locking anyway,
52    we should use the emacs lock scheme?... */
53
54 #define obstack_chunk_alloc xmalloc
55 #define obstack_chunk_free free
56
57 /* Return a new BFD.  All BFD's are allocated through this routine.  */
58
59 bfd *new_bfd()
60 {
61   bfd *nbfd;
62
63   nbfd = (bfd *)zalloc (sizeof (bfd));
64   if (!nbfd)
65     return 0;
66
67   obstack_begin((PTR)&nbfd->memory, 128);
68   
69   nbfd->direction = no_direction;
70   nbfd->iostream = NULL;
71   nbfd->where = 0;
72   nbfd->sections = (asection *)NULL;
73   nbfd->format = bfd_unknown;
74   nbfd->my_archive = (bfd *)NULL;
75   nbfd->origin = 0;                                
76   nbfd->opened_once = false;
77   nbfd->output_has_begun = false;
78   nbfd->section_count = 0;
79   nbfd->usrdata = (PTR)NULL;
80   nbfd->sections = (asection *)NULL;
81   nbfd->cacheable = false;
82   nbfd->flags = NO_FLAGS;
83   nbfd->mtime_set = 0;
84   return nbfd;
85 }
86
87 /* Allocate a new BFD as a member of archive OBFD.  */
88
89 bfd *new_bfd_contained_in(obfd)
90 bfd *obfd;
91 {
92         bfd *nbfd = new_bfd();
93         nbfd->xvec = obfd->xvec;
94         nbfd->my_archive = obfd;
95         nbfd->direction = read_direction;
96         return nbfd;
97 }
98
99 /** bfd_openr, bfd_fdopenr -- open for reading.
100   Returns a pointer to a freshly-allocated bfd on success, or NULL. */
101
102 bfd *
103 DEFUN(bfd_openr, (filename, target),
104       CONST char *filename AND
105       CONST char *target)
106 {
107   bfd *nbfd;
108   bfd_target *target_vec;
109
110   target_vec = bfd_find_target (target);
111   if (target_vec == NULL) {
112     bfd_error = invalid_target;
113     return NULL;
114   }
115
116   bfd_error = system_call_error;
117   nbfd = new_bfd();
118   if (nbfd == NULL) {
119     bfd_error = no_memory;
120     return NULL;
121   }
122
123   nbfd->filename = filename;
124   nbfd->xvec = target_vec;
125   nbfd->direction = read_direction; 
126
127   if (bfd_open_file (nbfd) == NULL) {
128     bfd_error = system_call_error;      /* File didn't exist, or some such */
129     bfd_release(nbfd,0);
130     return NULL;
131   }
132   return nbfd;
133 }
134
135
136 /* Don't try to `optimize' this function:
137
138    o - We lock using stack space so that interrupting the locking
139        won't cause a storage leak.
140    o - We open the file stream last, since we don't want to have to
141        close it if anything goes wrong.  Closing the stream means closing
142        the file descriptor too, even though we didn't open it.
143  */
144
145 bfd *
146 DEFUN(bfd_fdopenr,(filename, target, fd),
147       CONST char *filename AND
148       CONST char *target AND
149       int fd)
150 {
151   bfd *nbfd;
152   bfd_target *target_vec;
153   int fdflags;
154 #ifdef BFD_LOCKS
155   struct flock lock, *lockp = &lock;
156 #endif
157
158   target_vec = bfd_find_target (target);
159   if (target_vec == NULL) {
160     bfd_error = invalid_target;
161     return NULL;
162   }
163
164   bfd_error = system_call_error;
165   
166   fdflags = fcntl (fd, F_GETFL);
167   if (fdflags == -1) return NULL;
168
169 #ifdef BFD_LOCKS
170   lockp->l_type = F_RDLCK;
171   if (fcntl (fd, F_SETLKW, lockp) == -1) return NULL;
172 #endif
173
174   nbfd = new_bfd();
175
176   if (nbfd == NULL) {
177     bfd_error = no_memory;
178     return NULL;
179   }
180 #ifdef BFD_LOCKS
181   nbfd->lock = (struct flock *) (nbfd + 1);
182 #endif
183   /* if the fd were open for read only, this still would not hurt: */
184   nbfd->iostream = (char *) fdopen (fd, "r+"); 
185   if (nbfd->iostream == NULL) {
186     (void) obstack_free (&nbfd->memory, (PTR)0);
187     return NULL;
188   }
189   
190   /* OK, put everything where it belongs */
191
192   nbfd->filename = filename;
193   nbfd->xvec = target_vec;
194
195   /* As a special case we allow a FD open for read/write to
196      be written through, although doing so requires that we end
197      the previous clause with a preposition.  */
198   switch (fdflags & O_ACCMODE) {
199   case O_RDONLY: nbfd->direction = read_direction; break;
200   case O_WRONLY: nbfd->direction = write_direction; break;  
201   case O_RDWR: nbfd->direction = both_direction; break;
202   default: abort ();
203   }
204                                    
205 #ifdef BFD_LOCKS
206   memcpy (nbfd->lock, lockp, sizeof (struct flock))
207 #endif
208
209     bfd_cache_init (nbfd);
210
211   return nbfd;
212 }
213 \f
214 /** bfd_openw -- open for writing.
215   Returns a pointer to a freshly-allocated bfd on success, or NULL.
216
217   See comment by bfd_fdopenr before you try to modify this function. */
218
219 bfd *
220 DEFUN(bfd_openw,(filename, target),
221       CONST char *filename AND
222       CONST char *target)
223 {
224   bfd *nbfd;
225   bfd_target *target_vec;
226   
227   target_vec = bfd_find_target (target);
228   if (target_vec == NULL) return NULL;
229
230   bfd_error = system_call_error;
231
232   /* nbfd has to point to head of malloc'ed block so that bfd_close may
233      reclaim it correctly. */
234
235   nbfd = new_bfd();
236   if (nbfd == NULL) {
237     bfd_error = no_memory;
238     return NULL;
239   }
240
241   nbfd->filename = filename;
242   nbfd->xvec = target_vec;
243   nbfd->direction = write_direction;
244
245   if (bfd_open_file (nbfd) == NULL) {
246     bfd_error = system_call_error;      /* File not writeable, etc */
247     (void) obstack_free (&nbfd->memory, (PTR)0);
248     return NULL;
249   }
250   return nbfd;
251 }
252
253
254 \f
255 /** Close up shop, get your deposit back. */
256 boolean
257 bfd_close (abfd)
258      bfd *abfd;
259 {
260   if (!bfd_read_p(abfd))
261     if (BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)) != true)
262       return false;
263
264   if (BFD_SEND (abfd, _close_and_cleanup, (abfd)) != true) return false;
265
266   bfd_cache_close(abfd);
267
268   /* If the file was open for writing and is now executable,
269      make it so */
270   if (abfd->direction == write_direction 
271       && abfd->flags & EXEC_P) {
272     struct stat buf;
273     stat(abfd->filename, &buf);
274 #ifndef S_IXUSR
275 #define S_IXUSR 0100    /* Execute by owner.  */
276 #endif
277 #ifndef S_IXGRP
278 #define S_IXGRP 0010    /* Execute by group.  */
279 #endif
280 #ifndef S_IXOTH
281 #define S_IXOTH 0001    /* Execute by others.  */
282 #endif
283
284     chmod(abfd->filename,buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH);
285   }
286   (void) obstack_free (&abfd->memory, (PTR)0);
287   /* FIXME, shouldn't we de-allocate the bfd as well? */
288   return true;
289 }
290
291 /* Create a bfd with no associated file or target.  */
292
293 bfd *
294 DEFUN(bfd_create,(filename, template),
295       CONST char *filename AND
296       CONST bfd *template)
297 {
298   bfd *nbfd = new_bfd();
299   if (nbfd == (bfd *)NULL) {
300     bfd_error = no_memory;
301     return (bfd *)NULL;
302   }
303   nbfd->filename = filename;
304   if(template) {
305     nbfd->xvec = template->xvec;
306   }
307   nbfd->direction = no_direction;
308   bfd_set_format(nbfd, bfd_object);
309   return nbfd;
310 }
311
312 /* Memory allocation */
313
314 DEFUN(PTR bfd_alloc_by_size_t,(abfd, size),
315       bfd *abfd AND
316       size_t size)
317 {
318   PTR res = obstack_alloc(&(abfd->memory), size);
319   return res;
320 }
321 DEFUN(PTR bfd_alloc, (abfd, size),
322       bfd *abfd AND
323       bfd_size_type size)
324 {
325   return bfd_alloc_by_size_t(abfd, (size_t)size);
326 }
327
328 DEFUN(PTR bfd_zalloc,(abfd, size),
329       bfd *abfd AND
330       bfd_size_type size)
331 {
332   PTR res = bfd_alloc(abfd, size);
333   memset(res, 0, (size_t)size);
334   return res;
335 }
336
337 DEFUN(PTR bfd_realloc,(abfd, old, size),
338       bfd *abfd AND
339       PTR old AND
340       bfd_size_type size)
341 {
342   PTR res = bfd_alloc(abfd, size);
343   memcpy(res, old, (size_t)size);
344   return res;
345 }
346
347
348 DEFUN(bfd_size_type bfd_alloc_size,(abfd),
349       bfd *abfd)
350 {
351   struct _obstack_chunk *chunk = abfd->memory.chunk;
352   size_t size = 0;
353   while (chunk) {
354     size += chunk->limit - &(chunk->contents[0]);
355     chunk = chunk->prev;
356   }
357   return size;
358 }