133965Sjdp/* opncls.c -- open and close a BFD.
278828Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
3218822Sdim   2001, 2002, 2003, 2004, 2005, 2006, 2007
433965Sjdp   Free Software Foundation, Inc.
533965Sjdp
633965Sjdp   Written by Cygnus Support.
733965Sjdp
8104834Sobrien   This file is part of BFD, the Binary File Descriptor library.
933965Sjdp
10104834Sobrien   This program is free software; you can redistribute it and/or modify
11104834Sobrien   it under the terms of the GNU General Public License as published by
12104834Sobrien   the Free Software Foundation; either version 2 of the License, or
13104834Sobrien   (at your option) any later version.
1433965Sjdp
15104834Sobrien   This program is distributed in the hope that it will be useful,
16104834Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
17104834Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18104834Sobrien   GNU General Public License for more details.
1933965Sjdp
20104834Sobrien   You should have received a copy of the GNU General Public License
21104834Sobrien   along with this program; if not, write to the Free Software
22218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2333965Sjdp
24218822Sdim#include "sysdep.h"
2533965Sjdp#include "bfd.h"
2633965Sjdp#include "objalloc.h"
2733965Sjdp#include "libbfd.h"
28130561Sobrien#include "libiberty.h"
2933965Sjdp
3033965Sjdp#ifndef S_IXUSR
3133965Sjdp#define S_IXUSR 0100	/* Execute by owner.  */
3233965Sjdp#endif
3333965Sjdp#ifndef S_IXGRP
3433965Sjdp#define S_IXGRP 0010	/* Execute by group.  */
3533965Sjdp#endif
3633965Sjdp#ifndef S_IXOTH
3733965Sjdp#define S_IXOTH 0001	/* Execute by others.  */
3833965Sjdp#endif
3933965Sjdp
40130561Sobrien/* Counter used to initialize the bfd identifier.  */
41130561Sobrien
42130561Sobrienstatic unsigned int _bfd_id_counter = 0;
43130561Sobrien
4433965Sjdp/* fdopen is a loser -- we should use stdio exclusively.  Unfortunately
4533965Sjdp   if we do that we can't use fcntl.  */
4633965Sjdp
4733965Sjdp/* Return a new BFD.  All BFD's are allocated through this routine.  */
4833965Sjdp
4933965Sjdpbfd *
50130561Sobrien_bfd_new_bfd (void)
5133965Sjdp{
5233965Sjdp  bfd *nbfd;
5333965Sjdp
54130561Sobrien  nbfd = bfd_zmalloc (sizeof (bfd));
5533965Sjdp  if (nbfd == NULL)
5633965Sjdp    return NULL;
5733965Sjdp
58130561Sobrien  nbfd->id = _bfd_id_counter++;
59130561Sobrien
60130561Sobrien  nbfd->memory = objalloc_create ();
6133965Sjdp  if (nbfd->memory == NULL)
6233965Sjdp    {
6333965Sjdp      bfd_set_error (bfd_error_no_memory);
6489857Sobrien      free (nbfd);
6533965Sjdp      return NULL;
6633965Sjdp    }
6733965Sjdp
6833965Sjdp  nbfd->arch_info = &bfd_default_arch_struct;
6933965Sjdp
7033965Sjdp  nbfd->direction = no_direction;
7133965Sjdp  nbfd->iostream = NULL;
7233965Sjdp  nbfd->where = 0;
73130561Sobrien  if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc,
74218822Sdim			      sizeof (struct section_hash_entry), 251))
7589857Sobrien    {
7689857Sobrien      free (nbfd);
7789857Sobrien      return NULL;
7889857Sobrien    }
79130561Sobrien  nbfd->sections = NULL;
80218822Sdim  nbfd->section_last = NULL;
8133965Sjdp  nbfd->format = bfd_unknown;
82130561Sobrien  nbfd->my_archive = NULL;
8389857Sobrien  nbfd->origin = 0;
84130561Sobrien  nbfd->opened_once = FALSE;
85130561Sobrien  nbfd->output_has_begun = FALSE;
8633965Sjdp  nbfd->section_count = 0;
87130561Sobrien  nbfd->usrdata = NULL;
88130561Sobrien  nbfd->cacheable = FALSE;
8933965Sjdp  nbfd->flags = BFD_NO_FLAGS;
90130561Sobrien  nbfd->mtime_set = FALSE;
9133965Sjdp
9233965Sjdp  return nbfd;
9333965Sjdp}
9433965Sjdp
9533965Sjdp/* Allocate a new BFD as a member of archive OBFD.  */
9633965Sjdp
9733965Sjdpbfd *
98130561Sobrien_bfd_new_bfd_contained_in (bfd *obfd)
9933965Sjdp{
10033965Sjdp  bfd *nbfd;
10133965Sjdp
10233965Sjdp  nbfd = _bfd_new_bfd ();
10399461Sobrien  if (nbfd == NULL)
10499461Sobrien    return NULL;
10533965Sjdp  nbfd->xvec = obfd->xvec;
106218822Sdim  nbfd->iovec = obfd->iovec;
10733965Sjdp  nbfd->my_archive = obfd;
10833965Sjdp  nbfd->direction = read_direction;
10933965Sjdp  nbfd->target_defaulted = obfd->target_defaulted;
11033965Sjdp  return nbfd;
11133965Sjdp}
11233965Sjdp
11389857Sobrien/* Delete a BFD.  */
11489857Sobrien
11589857Sobrienvoid
116130561Sobrien_bfd_delete_bfd (bfd *abfd)
11789857Sobrien{
118218822Sdim  if (abfd->memory)
119218822Sdim    {
120218822Sdim      bfd_hash_table_free (&abfd->section_htab);
121218822Sdim      objalloc_free ((struct objalloc *) abfd->memory);
122218822Sdim    }
12389857Sobrien  free (abfd);
12489857Sobrien}
12589857Sobrien
126218822Sdim/* Free objalloc memory.  */
127218822Sdim
128218822Sdimbfd_boolean
129218822Sdim_bfd_free_cached_info (bfd *abfd)
130218822Sdim{
131218822Sdim  if (abfd->memory)
132218822Sdim    {
133218822Sdim      bfd_hash_table_free (&abfd->section_htab);
134218822Sdim      objalloc_free ((struct objalloc *) abfd->memory);
135218822Sdim
136218822Sdim      abfd->sections = NULL;
137218822Sdim      abfd->section_last = NULL;
138218822Sdim      abfd->outsymbols = NULL;
139218822Sdim      abfd->tdata.any = NULL;
140218822Sdim      abfd->usrdata = NULL;
141218822Sdim      abfd->memory = NULL;
142218822Sdim    }
143218822Sdim
144218822Sdim  return TRUE;
145218822Sdim}
146218822Sdim
14733965Sjdp/*
14833965SjdpSECTION
14933965Sjdp	Opening and closing BFDs
15033965Sjdp
151218822SdimSUBSECTION
152218822Sdim	Functions for opening and closing
15333965Sjdp*/
15433965Sjdp
15533965Sjdp/*
15633965SjdpFUNCTION
157218822Sdim	bfd_fopen
15833965Sjdp
15933965SjdpSYNOPSIS
160218822Sdim	bfd *bfd_fopen (const char *filename, const char *target,
161218822Sdim                        const char *mode, int fd);
16233965Sjdp
16333965SjdpDESCRIPTION
164218822Sdim	Open the file @var{filename} with the target @var{target}.
165218822Sdim	Return a pointer to the created BFD.  If @var{fd} is not -1,
166218822Sdim	then <<fdopen>> is used to open the file; otherwise, <<fopen>>
167218822Sdim	is used.  @var{mode} is passed directly to <<fopen>> or
168218822Sdim	<<fdopen>>.
16933965Sjdp
17033965Sjdp	Calls <<bfd_find_target>>, so @var{target} is interpreted as by
17133965Sjdp	that function.
17233965Sjdp
173218822Sdim	The new BFD is marked as cacheable iff @var{fd} is -1.
174218822Sdim
17533965Sjdp	If <<NULL>> is returned then an error has occured.   Possible errors
176130561Sobrien	are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or
177130561Sobrien	<<system_call>> error.
17833965Sjdp*/
17933965Sjdp
18033965Sjdpbfd *
181218822Sdimbfd_fopen (const char *filename, const char *target, const char *mode, int fd)
18233965Sjdp{
18333965Sjdp  bfd *nbfd;
18433965Sjdp  const bfd_target *target_vec;
18533965Sjdp
18633965Sjdp  nbfd = _bfd_new_bfd ();
18733965Sjdp  if (nbfd == NULL)
18833965Sjdp    return NULL;
18933965Sjdp
19033965Sjdp  target_vec = bfd_find_target (target, nbfd);
19133965Sjdp  if (target_vec == NULL)
19233965Sjdp    {
19389857Sobrien      _bfd_delete_bfd (nbfd);
19433965Sjdp      return NULL;
19533965Sjdp    }
196218822Sdim
197218822Sdim#ifdef HAVE_FDOPEN
198218822Sdim  if (fd != -1)
199218822Sdim    nbfd->iostream = fdopen (fd, mode);
200218822Sdim  else
201218822Sdim#endif
202218822Sdim    nbfd->iostream = real_fopen (filename, mode);
203218822Sdim  if (nbfd->iostream == NULL)
204218822Sdim    {
205218822Sdim      bfd_set_error (bfd_error_system_call);
206218822Sdim      _bfd_delete_bfd (nbfd);
207218822Sdim      return NULL;
208218822Sdim    }
20933965Sjdp
210218822Sdim  /* OK, put everything where it belongs.  */
21133965Sjdp  nbfd->filename = filename;
21233965Sjdp
213218822Sdim  /* Figure out whether the user is opening the file for reading,
214218822Sdim     writing, or both, by looking at the MODE argument.  */
215218822Sdim  if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a')
216218822Sdim      && mode[1] == '+')
217218822Sdim    nbfd->direction = both_direction;
218218822Sdim  else if (mode[0] == 'r')
219218822Sdim    nbfd->direction = read_direction;
220218822Sdim  else
221218822Sdim    nbfd->direction = write_direction;
222218822Sdim
223218822Sdim  if (! bfd_cache_init (nbfd))
22433965Sjdp    {
22589857Sobrien      _bfd_delete_bfd (nbfd);
22633965Sjdp      return NULL;
22733965Sjdp    }
228218822Sdim  nbfd->opened_once = TRUE;
229218822Sdim  /* If we opened the file by name, mark it cacheable; we can close it
230218822Sdim     and reopen it later.  However, if a file descriptor was provided,
231218822Sdim     then it may have been opened with special flags that make it
232218822Sdim     unsafe to close and reopen the file.  */
233218822Sdim  if (fd == -1)
234223262Sbenl    (void) bfd_set_cacheable (nbfd, TRUE);
23533965Sjdp
23633965Sjdp  return nbfd;
23733965Sjdp}
23833965Sjdp
239218822Sdim/*
240218822SdimFUNCTION
241218822Sdim	bfd_openr
242218822Sdim
243218822SdimSYNOPSIS
244218822Sdim	bfd *bfd_openr (const char *filename, const char *target);
245218822Sdim
246218822SdimDESCRIPTION
247218822Sdim	Open the file @var{filename} (using <<fopen>>) with the target
248218822Sdim	@var{target}.  Return a pointer to the created BFD.
249218822Sdim
250218822Sdim	Calls <<bfd_find_target>>, so @var{target} is interpreted as by
251218822Sdim	that function.
252218822Sdim
253218822Sdim	If <<NULL>> is returned then an error has occured.   Possible errors
254218822Sdim	are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or
255218822Sdim	<<system_call>> error.
256218822Sdim*/
257218822Sdim
258218822Sdimbfd *
259218822Sdimbfd_openr (const char *filename, const char *target)
260218822Sdim{
261218822Sdim  return bfd_fopen (filename, target, FOPEN_RB, -1);
262218822Sdim}
263218822Sdim
26433965Sjdp/* Don't try to `optimize' this function:
26533965Sjdp
26633965Sjdp   o - We lock using stack space so that interrupting the locking
26733965Sjdp       won't cause a storage leak.
26833965Sjdp   o - We open the file stream last, since we don't want to have to
26933965Sjdp       close it if anything goes wrong.  Closing the stream means closing
270104834Sobrien       the file descriptor too, even though we didn't open it.  */
27133965Sjdp/*
27233965SjdpFUNCTION
273130561Sobrien	bfd_fdopenr
27433965Sjdp
27533965SjdpSYNOPSIS
276130561Sobrien	bfd *bfd_fdopenr (const char *filename, const char *target, int fd);
27733965Sjdp
27833965SjdpDESCRIPTION
279130561Sobrien	<<bfd_fdopenr>> is to <<bfd_fopenr>> much like <<fdopen>> is to
280130561Sobrien	<<fopen>>.  It opens a BFD on a file already described by the
281130561Sobrien	@var{fd} supplied.
28233965Sjdp
283130561Sobrien	When the file is later <<bfd_close>>d, the file descriptor will
284130561Sobrien	be closed.  If the caller desires that this file descriptor be
285130561Sobrien	cached by BFD (opened as needed, closed as needed to free
286130561Sobrien	descriptors for other opens), with the supplied @var{fd} used as
287130561Sobrien	an initial file descriptor (but subject to closure at any time),
288130561Sobrien	call bfd_set_cacheable(bfd, 1) on the returned BFD.  The default
289130561Sobrien	is to assume no caching; the file descriptor will remain open
290130561Sobrien	until <<bfd_close>>, and will not be affected by BFD operations
291130561Sobrien	on other files.
29233965Sjdp
293130561Sobrien	Possible errors are <<bfd_error_no_memory>>,
294130561Sobrien	<<bfd_error_invalid_target>> and <<bfd_error_system_call>>.
29533965Sjdp*/
29633965Sjdp
29733965Sjdpbfd *
298130561Sobrienbfd_fdopenr (const char *filename, const char *target, int fd)
29933965Sjdp{
300218822Sdim  const char *mode;
301218822Sdim#if defined(HAVE_FCNTL) && defined(F_GETFL)
30233965Sjdp  int fdflags;
303218822Sdim#endif
30433965Sjdp
30533965Sjdp#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL)
306218822Sdim  mode = FOPEN_RUB; /* Assume full access.  */
30733965Sjdp#else
30833965Sjdp  fdflags = fcntl (fd, F_GETFL, NULL);
309104834Sobrien  if (fdflags == -1)
31033965Sjdp    {
311218822Sdim      bfd_set_error (bfd_error_system_call);
31233965Sjdp      return NULL;
31333965Sjdp    }
31433965Sjdp
315104834Sobrien  /* (O_ACCMODE) parens are to avoid Ultrix header file bug.  */
31638889Sjdp  switch (fdflags & (O_ACCMODE))
31738889Sjdp    {
318218822Sdim    case O_RDONLY: mode = FOPEN_RB; break;
319218822Sdim    case O_WRONLY: mode = FOPEN_RUB; break;
320218822Sdim    case O_RDWR:   mode = FOPEN_RUB; break;
32138889Sjdp    default: abort ();
32238889Sjdp    }
32333965Sjdp#endif
32433965Sjdp
325218822Sdim  return bfd_fopen (filename, target, mode, fd);
326218822Sdim}
327218822Sdim
328218822Sdim/*
329218822SdimFUNCTION
330218822Sdim	bfd_openstreamr
331218822Sdim
332218822SdimSYNOPSIS
333218822Sdim	bfd *bfd_openstreamr (const char *, const char *, void *);
334218822Sdim
335218822SdimDESCRIPTION
336218822Sdim
337218822Sdim	Open a BFD for read access on an existing stdio stream.  When
338218822Sdim	the BFD is passed to <<bfd_close>>, the stream will be closed.
339218822Sdim*/
340218822Sdim
341218822Sdimbfd *
342218822Sdimbfd_openstreamr (const char *filename, const char *target, void *streamarg)
343218822Sdim{
344218822Sdim  FILE *stream = streamarg;
345218822Sdim  bfd *nbfd;
346218822Sdim  const bfd_target *target_vec;
347218822Sdim
348218822Sdim  nbfd = _bfd_new_bfd ();
349218822Sdim  if (nbfd == NULL)
350218822Sdim    return NULL;
351218822Sdim
352218822Sdim  target_vec = bfd_find_target (target, nbfd);
353218822Sdim  if (target_vec == NULL)
35433965Sjdp    {
35589857Sobrien      _bfd_delete_bfd (nbfd);
35633965Sjdp      return NULL;
35733965Sjdp    }
35833965Sjdp
359218822Sdim  nbfd->iostream = stream;
36033965Sjdp  nbfd->filename = filename;
361218822Sdim  nbfd->direction = read_direction;
36233965Sjdp
36333965Sjdp  if (! bfd_cache_init (nbfd))
36433965Sjdp    {
36589857Sobrien      _bfd_delete_bfd (nbfd);
36633965Sjdp      return NULL;
36733965Sjdp    }
36833965Sjdp
36933965Sjdp  return nbfd;
37033965Sjdp}
37133965Sjdp
37233965Sjdp/*
37333965SjdpFUNCTION
374218822Sdim	bfd_openr_iovec
37533965Sjdp
37633965SjdpSYNOPSIS
377218822Sdim        bfd *bfd_openr_iovec (const char *filename, const char *target,
378218822Sdim                              void *(*open) (struct bfd *nbfd,
379218822Sdim                                             void *open_closure),
380218822Sdim                              void *open_closure,
381218822Sdim                              file_ptr (*pread) (struct bfd *nbfd,
382218822Sdim                                                 void *stream,
383218822Sdim                                                 void *buf,
384218822Sdim                                                 file_ptr nbytes,
385218822Sdim                                                 file_ptr offset),
386218822Sdim                              int (*close) (struct bfd *nbfd,
387218822Sdim                                            void *stream),
388218822Sdim			      int (*stat) (struct bfd *abfd,
389218822Sdim					   void *stream,
390218822Sdim					   struct stat *sb));
39133965Sjdp
39233965SjdpDESCRIPTION
39333965Sjdp
394218822Sdim        Create and return a BFD backed by a read-only @var{stream}.
395218822Sdim        The @var{stream} is created using @var{open}, accessed using
396218822Sdim        @var{pread} and destroyed using @var{close}.
397218822Sdim
398218822Sdim	Calls <<bfd_find_target>>, so @var{target} is interpreted as by
399218822Sdim	that function.
400218822Sdim
401218822Sdim	Calls @var{open} (which can call <<bfd_zalloc>> and
402218822Sdim	<<bfd_get_filename>>) to obtain the read-only stream backing
403218822Sdim	the BFD.  @var{open} either succeeds returning the
404218822Sdim	non-<<NULL>> @var{stream}, or fails returning <<NULL>>
405218822Sdim	(setting <<bfd_error>>).
406218822Sdim
407218822Sdim	Calls @var{pread} to request @var{nbytes} of data from
408218822Sdim	@var{stream} starting at @var{offset} (e.g., via a call to
409218822Sdim	<<bfd_read>>).  @var{pread} either succeeds returning the
410218822Sdim	number of bytes read (which can be less than @var{nbytes} when
411218822Sdim	end-of-file), or fails returning -1 (setting <<bfd_error>>).
412218822Sdim
413218822Sdim	Calls @var{close} when the BFD is later closed using
414218822Sdim	<<bfd_close>>.  @var{close} either succeeds returning 0, or
415218822Sdim	fails returning -1 (setting <<bfd_error>>).
416218822Sdim
417218822Sdim	Calls @var{stat} to fill in a stat structure for bfd_stat,
418218822Sdim	bfd_get_size, and bfd_get_mtime calls.  @var{stat} returns 0
419218822Sdim	on success, or returns -1 on failure (setting <<bfd_error>>).
420218822Sdim
421218822Sdim	If <<bfd_openr_iovec>> returns <<NULL>> then an error has
422218822Sdim	occurred.  Possible errors are <<bfd_error_no_memory>>,
423218822Sdim	<<bfd_error_invalid_target>> and <<bfd_error_system_call>>.
424218822Sdim
42533965Sjdp*/
42633965Sjdp
427218822Sdimstruct opncls
428218822Sdim{
429218822Sdim  void *stream;
430218822Sdim  file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf,
431218822Sdim		     file_ptr nbytes, file_ptr offset);
432218822Sdim  int (*close) (struct bfd *abfd, void *stream);
433218822Sdim  int (*stat) (struct bfd *abfd, void *stream, struct stat *sb);
434218822Sdim  file_ptr where;
435218822Sdim};
436218822Sdim
437218822Sdimstatic file_ptr
438218822Sdimopncls_btell (struct bfd *abfd)
439218822Sdim{
440218822Sdim  struct opncls *vec = abfd->iostream;
441218822Sdim  return vec->where;
442218822Sdim}
443218822Sdim
444218822Sdimstatic int
445218822Sdimopncls_bseek (struct bfd *abfd, file_ptr offset, int whence)
446218822Sdim{
447218822Sdim  struct opncls *vec = abfd->iostream;
448218822Sdim  switch (whence)
449218822Sdim    {
450218822Sdim    case SEEK_SET: vec->where = offset; break;
451218822Sdim    case SEEK_CUR: vec->where += offset; break;
452218822Sdim    case SEEK_END: return -1;
453218822Sdim    }
454218822Sdim  return 0;
455218822Sdim}
456218822Sdim
457218822Sdimstatic file_ptr
458218822Sdimopncls_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
459218822Sdim{
460218822Sdim  struct opncls *vec = abfd->iostream;
461218822Sdim  file_ptr nread = (vec->pread) (abfd, vec->stream, buf, nbytes, vec->where);
462218822Sdim  if (nread < 0)
463218822Sdim    return nread;
464218822Sdim  vec->where += nread;
465218822Sdim  return nread;
466218822Sdim}
467218822Sdim
468218822Sdimstatic file_ptr
469218822Sdimopncls_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
470218822Sdim	      const void *where ATTRIBUTE_UNUSED,
471218822Sdim	      file_ptr nbytes ATTRIBUTE_UNUSED)
472218822Sdim{
473218822Sdim  return -1;
474218822Sdim}
475218822Sdim
476218822Sdimstatic int
477218822Sdimopncls_bclose (struct bfd *abfd)
478218822Sdim{
479218822Sdim  struct opncls *vec = abfd->iostream;
480218822Sdim  /* Since the VEC's memory is bound to the bfd deleting the bfd will
481218822Sdim     free it.  */
482218822Sdim  int status = 0;
483218822Sdim  if (vec->close != NULL)
484218822Sdim    status = (vec->close) (abfd, vec->stream);
485218822Sdim  abfd->iostream = NULL;
486218822Sdim  return status;
487218822Sdim}
488218822Sdim
489218822Sdimstatic int
490218822Sdimopncls_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
491218822Sdim{
492218822Sdim  return 0;
493218822Sdim}
494218822Sdim
495218822Sdimstatic int
496218822Sdimopncls_bstat (struct bfd *abfd, struct stat *sb)
497218822Sdim{
498218822Sdim  struct opncls *vec = abfd->iostream;
499218822Sdim
500218822Sdim  memset (sb, 0, sizeof (*sb));
501218822Sdim  if (vec->stat == NULL)
502218822Sdim    return 0;
503218822Sdim
504218822Sdim  return (vec->stat) (abfd, vec->stream, sb);
505218822Sdim}
506218822Sdim
507218822Sdimstatic const struct bfd_iovec opncls_iovec = {
508218822Sdim  &opncls_bread, &opncls_bwrite, &opncls_btell, &opncls_bseek,
509218822Sdim  &opncls_bclose, &opncls_bflush, &opncls_bstat
510218822Sdim};
511218822Sdim
51233965Sjdpbfd *
513218822Sdimbfd_openr_iovec (const char *filename, const char *target,
514218822Sdim		 void *(*open) (struct bfd *nbfd,
515218822Sdim				void *open_closure),
516218822Sdim		 void *open_closure,
517218822Sdim		 file_ptr (*pread) (struct bfd *abfd,
518218822Sdim				    void *stream,
519218822Sdim				    void *buf,
520218822Sdim				    file_ptr nbytes,
521218822Sdim				    file_ptr offset),
522218822Sdim		 int (*close) (struct bfd *nbfd,
523218822Sdim			       void *stream),
524218822Sdim		 int (*stat) (struct bfd *abfd,
525218822Sdim			      void *stream,
526218822Sdim			      struct stat *sb))
52733965Sjdp{
52833965Sjdp  bfd *nbfd;
52933965Sjdp  const bfd_target *target_vec;
530218822Sdim  struct opncls *vec;
531218822Sdim  void *stream;
53233965Sjdp
53333965Sjdp  nbfd = _bfd_new_bfd ();
53433965Sjdp  if (nbfd == NULL)
53533965Sjdp    return NULL;
53633965Sjdp
53733965Sjdp  target_vec = bfd_find_target (target, nbfd);
53833965Sjdp  if (target_vec == NULL)
53933965Sjdp    {
54089857Sobrien      _bfd_delete_bfd (nbfd);
54133965Sjdp      return NULL;
54233965Sjdp    }
54333965Sjdp
54433965Sjdp  nbfd->filename = filename;
54533965Sjdp  nbfd->direction = read_direction;
54689857Sobrien
547218822Sdim  stream = open (nbfd, open_closure);
548218822Sdim  if (stream == NULL)
54933965Sjdp    {
55089857Sobrien      _bfd_delete_bfd (nbfd);
55133965Sjdp      return NULL;
55233965Sjdp    }
55333965Sjdp
554218822Sdim  vec = bfd_zalloc (nbfd, sizeof (struct opncls));
555218822Sdim  vec->stream = stream;
556218822Sdim  vec->pread = pread;
557218822Sdim  vec->close = close;
558218822Sdim  vec->stat = stat;
559218822Sdim
560218822Sdim  nbfd->iovec = &opncls_iovec;
561218822Sdim  nbfd->iostream = vec;
562218822Sdim
56333965Sjdp  return nbfd;
56433965Sjdp}
56533965Sjdp
566104834Sobrien/* bfd_openw -- open for writing.
567104834Sobrien   Returns a pointer to a freshly-allocated BFD on success, or NULL.
56833965Sjdp
569104834Sobrien   See comment by bfd_fdopenr before you try to modify this function.  */
57033965Sjdp
57133965Sjdp/*
57233965SjdpFUNCTION
57333965Sjdp	bfd_openw
57433965Sjdp
57533965SjdpSYNOPSIS
576130561Sobrien	bfd *bfd_openw (const char *filename, const char *target);
57733965Sjdp
57833965SjdpDESCRIPTION
57933965Sjdp	Create a BFD, associated with file @var{filename}, using the
58033965Sjdp	file format @var{target}, and return a pointer to it.
58133965Sjdp
58233965Sjdp	Possible errors are <<bfd_error_system_call>>, <<bfd_error_no_memory>>,
58333965Sjdp	<<bfd_error_invalid_target>>.
58433965Sjdp*/
58533965Sjdp
58633965Sjdpbfd *
587130561Sobrienbfd_openw (const char *filename, const char *target)
58833965Sjdp{
58933965Sjdp  bfd *nbfd;
59033965Sjdp  const bfd_target *target_vec;
59133965Sjdp
59233965Sjdp  /* nbfd has to point to head of malloc'ed block so that bfd_close may
593104834Sobrien     reclaim it correctly.  */
59433965Sjdp  nbfd = _bfd_new_bfd ();
59533965Sjdp  if (nbfd == NULL)
59633965Sjdp    return NULL;
59733965Sjdp
59833965Sjdp  target_vec = bfd_find_target (target, nbfd);
59933965Sjdp  if (target_vec == NULL)
60033965Sjdp    {
60189857Sobrien      _bfd_delete_bfd (nbfd);
60233965Sjdp      return NULL;
60333965Sjdp    }
60433965Sjdp
60533965Sjdp  nbfd->filename = filename;
60633965Sjdp  nbfd->direction = write_direction;
60733965Sjdp
60833965Sjdp  if (bfd_open_file (nbfd) == NULL)
60933965Sjdp    {
610104834Sobrien      /* File not writeable, etc.  */
611104834Sobrien      bfd_set_error (bfd_error_system_call);
61289857Sobrien      _bfd_delete_bfd (nbfd);
61333965Sjdp      return NULL;
61433965Sjdp  }
61533965Sjdp
61633965Sjdp  return nbfd;
61733965Sjdp}
61833965Sjdp
61933965Sjdp/*
62033965Sjdp
62133965SjdpFUNCTION
62233965Sjdp	bfd_close
62333965Sjdp
62433965SjdpSYNOPSIS
625130561Sobrien	bfd_boolean bfd_close (bfd *abfd);
62633965Sjdp
62733965SjdpDESCRIPTION
62833965Sjdp
629130561Sobrien	Close a BFD. If the BFD was open for writing, then pending
630130561Sobrien	operations are completed and the file written out and closed.
631130561Sobrien	If the created file is executable, then <<chmod>> is called
632130561Sobrien	to mark it as such.
63333965Sjdp
63433965Sjdp	All memory attached to the BFD is released.
63533965Sjdp
63633965Sjdp	The file descriptor associated with the BFD is closed (even
63733965Sjdp	if it was passed in to BFD by <<bfd_fdopenr>>).
63833965Sjdp
63933965SjdpRETURNS
640130561Sobrien	<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.
64133965Sjdp*/
64233965Sjdp
64333965Sjdp
644130561Sobrienbfd_boolean
645130561Sobrienbfd_close (bfd *abfd)
64633965Sjdp{
647130561Sobrien  bfd_boolean ret;
64833965Sjdp
649104834Sobrien  if (bfd_write_p (abfd))
65033965Sjdp    {
65133965Sjdp      if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)))
652130561Sobrien	return FALSE;
65333965Sjdp    }
65433965Sjdp
65533965Sjdp  if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
656130561Sobrien    return FALSE;
65733965Sjdp
658218822Sdim  /* FIXME: cagney/2004-02-15: Need to implement a BFD_IN_MEMORY io
659218822Sdim     vector.  */
660218822Sdim  if (!(abfd->flags & BFD_IN_MEMORY))
661218822Sdim    ret = abfd->iovec->bclose (abfd);
662218822Sdim  else
663218822Sdim    ret = TRUE;
66433965Sjdp
66533965Sjdp  /* If the file was open for writing and is now executable,
666104834Sobrien     make it so.  */
66733965Sjdp  if (ret
66833965Sjdp      && abfd->direction == write_direction
66933965Sjdp      && abfd->flags & EXEC_P)
67033965Sjdp    {
67133965Sjdp      struct stat buf;
67233965Sjdp
67333965Sjdp      if (stat (abfd->filename, &buf) == 0)
67433965Sjdp	{
675130561Sobrien	  unsigned int mask = umask (0);
676104834Sobrien
67733965Sjdp	  umask (mask);
67833965Sjdp	  chmod (abfd->filename,
67933965Sjdp		 (0777
68033965Sjdp		  & (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask))));
68133965Sjdp	}
68233965Sjdp    }
68333965Sjdp
68489857Sobrien  _bfd_delete_bfd (abfd);
68533965Sjdp
68633965Sjdp  return ret;
68733965Sjdp}
68833965Sjdp
68933965Sjdp/*
69033965SjdpFUNCTION
69133965Sjdp	bfd_close_all_done
69233965Sjdp
69333965SjdpSYNOPSIS
694130561Sobrien	bfd_boolean bfd_close_all_done (bfd *);
69533965Sjdp
69633965SjdpDESCRIPTION
697130561Sobrien	Close a BFD.  Differs from <<bfd_close>> since it does not
698130561Sobrien	complete any pending operations.  This routine would be used
699130561Sobrien	if the application had just used BFD for swapping and didn't
700130561Sobrien	want to use any of the writing code.
70133965Sjdp
70233965Sjdp	If the created file is executable, then <<chmod>> is called
70333965Sjdp	to mark it as such.
70433965Sjdp
70533965Sjdp	All memory attached to the BFD is released.
70633965Sjdp
70733965SjdpRETURNS
708130561Sobrien	<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.
70933965Sjdp*/
71033965Sjdp
711130561Sobrienbfd_boolean
712130561Sobrienbfd_close_all_done (bfd *abfd)
71333965Sjdp{
714130561Sobrien  bfd_boolean ret;
71533965Sjdp
71633965Sjdp  ret = bfd_cache_close (abfd);
71733965Sjdp
71833965Sjdp  /* If the file was open for writing and is now executable,
719104834Sobrien     make it so.  */
72033965Sjdp  if (ret
72133965Sjdp      && abfd->direction == write_direction
72233965Sjdp      && abfd->flags & EXEC_P)
72333965Sjdp    {
72433965Sjdp      struct stat buf;
72533965Sjdp
72633965Sjdp      if (stat (abfd->filename, &buf) == 0)
72733965Sjdp	{
72889857Sobrien	  unsigned int mask = umask (0);
729104834Sobrien
73033965Sjdp	  umask (mask);
73133965Sjdp	  chmod (abfd->filename,
73261843Sobrien		 (0777
73333965Sjdp		  & (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask))));
73433965Sjdp	}
73533965Sjdp    }
73633965Sjdp
73789857Sobrien  _bfd_delete_bfd (abfd);
73833965Sjdp
73933965Sjdp  return ret;
74033965Sjdp}
74133965Sjdp
74233965Sjdp/*
74333965SjdpFUNCTION
74433965Sjdp	bfd_create
74533965Sjdp
74633965SjdpSYNOPSIS
747130561Sobrien	bfd *bfd_create (const char *filename, bfd *templ);
74833965Sjdp
74933965SjdpDESCRIPTION
750130561Sobrien	Create a new BFD in the manner of <<bfd_openw>>, but without
751130561Sobrien	opening a file. The new BFD takes the target from the target
752130561Sobrien	used by @var{template}. The format is always set to <<bfd_object>>.
75333965Sjdp*/
75433965Sjdp
75533965Sjdpbfd *
756130561Sobrienbfd_create (const char *filename, bfd *templ)
75733965Sjdp{
75833965Sjdp  bfd *nbfd;
75933965Sjdp
76033965Sjdp  nbfd = _bfd_new_bfd ();
76133965Sjdp  if (nbfd == NULL)
76233965Sjdp    return NULL;
76333965Sjdp  nbfd->filename = filename;
76433965Sjdp  if (templ)
76533965Sjdp    nbfd->xvec = templ->xvec;
76633965Sjdp  nbfd->direction = no_direction;
76733965Sjdp  bfd_set_format (nbfd, bfd_object);
768104834Sobrien
76933965Sjdp  return nbfd;
77033965Sjdp}
77133965Sjdp
77233965Sjdp/*
77360484SobrienFUNCTION
77460484Sobrien	bfd_make_writable
77560484Sobrien
77660484SobrienSYNOPSIS
777130561Sobrien	bfd_boolean bfd_make_writable (bfd *abfd);
77860484Sobrien
77960484SobrienDESCRIPTION
78060484Sobrien	Takes a BFD as created by <<bfd_create>> and converts it
78160484Sobrien	into one like as returned by <<bfd_openw>>.  It does this
78260484Sobrien	by converting the BFD to BFD_IN_MEMORY.  It's assumed that
78360484Sobrien	you will call <<bfd_make_readable>> on this bfd later.
78460484Sobrien
78560484SobrienRETURNS
786130561Sobrien	<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.
78760484Sobrien*/
78860484Sobrien
789130561Sobrienbfd_boolean
790130561Sobrienbfd_make_writable (bfd *abfd)
79160484Sobrien{
79260484Sobrien  struct bfd_in_memory *bim;
79360484Sobrien
79460484Sobrien  if (abfd->direction != no_direction)
79560484Sobrien    {
79660484Sobrien      bfd_set_error (bfd_error_invalid_operation);
797130561Sobrien      return FALSE;
79860484Sobrien    }
79960484Sobrien
800130561Sobrien  bim = bfd_malloc (sizeof (struct bfd_in_memory));
801130561Sobrien  abfd->iostream = bim;
802104834Sobrien  /* bfd_bwrite will grow these as needed.  */
80360484Sobrien  bim->size = 0;
80460484Sobrien  bim->buffer = 0;
80560484Sobrien
80660484Sobrien  abfd->flags |= BFD_IN_MEMORY;
80760484Sobrien  abfd->direction = write_direction;
80860484Sobrien  abfd->where = 0;
80960484Sobrien
810130561Sobrien  return TRUE;
81160484Sobrien}
81260484Sobrien
81360484Sobrien/*
81460484SobrienFUNCTION
81560484Sobrien	bfd_make_readable
81660484Sobrien
81760484SobrienSYNOPSIS
818130561Sobrien	bfd_boolean bfd_make_readable (bfd *abfd);
81960484Sobrien
82060484SobrienDESCRIPTION
82160484Sobrien	Takes a BFD as created by <<bfd_create>> and
82260484Sobrien	<<bfd_make_writable>> and converts it into one like as
82360484Sobrien	returned by <<bfd_openr>>.  It does this by writing the
82460484Sobrien	contents out to the memory buffer, then reversing the
82560484Sobrien	direction.
82660484Sobrien
82760484SobrienRETURNS
828130561Sobrien	<<TRUE>> is returned if all is ok, otherwise <<FALSE>>.  */
82960484Sobrien
830130561Sobrienbfd_boolean
831130561Sobrienbfd_make_readable (bfd *abfd)
83260484Sobrien{
83360484Sobrien  if (abfd->direction != write_direction || !(abfd->flags & BFD_IN_MEMORY))
83460484Sobrien    {
83560484Sobrien      bfd_set_error (bfd_error_invalid_operation);
836130561Sobrien      return FALSE;
83760484Sobrien    }
83860484Sobrien
83960484Sobrien  if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)))
840130561Sobrien    return FALSE;
84160484Sobrien
84260484Sobrien  if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
843130561Sobrien    return FALSE;
84460484Sobrien
84560484Sobrien
84660484Sobrien  abfd->arch_info = &bfd_default_arch_struct;
84760484Sobrien
84860484Sobrien  abfd->where = 0;
84960484Sobrien  abfd->format = bfd_unknown;
850130561Sobrien  abfd->my_archive = NULL;
85189857Sobrien  abfd->origin = 0;
852130561Sobrien  abfd->opened_once = FALSE;
853130561Sobrien  abfd->output_has_begun = FALSE;
85460484Sobrien  abfd->section_count = 0;
855130561Sobrien  abfd->usrdata = NULL;
856130561Sobrien  abfd->cacheable = FALSE;
85760484Sobrien  abfd->flags = BFD_IN_MEMORY;
858130561Sobrien  abfd->mtime_set = FALSE;
85960484Sobrien
860130561Sobrien  abfd->target_defaulted = TRUE;
86160484Sobrien  abfd->direction = read_direction;
86260484Sobrien  abfd->sections = 0;
86360484Sobrien  abfd->symcount = 0;
86460484Sobrien  abfd->outsymbols = 0;
86560484Sobrien  abfd->tdata.any = 0;
86660484Sobrien
86799461Sobrien  bfd_section_list_clear (abfd);
868104834Sobrien  bfd_check_format (abfd, bfd_object);
86960484Sobrien
870130561Sobrien  return TRUE;
87160484Sobrien}
87260484Sobrien
87360484Sobrien/*
87433965SjdpINTERNAL_FUNCTION
87533965Sjdp	bfd_alloc
87633965Sjdp
87733965SjdpSYNOPSIS
878218822Sdim	void *bfd_alloc (bfd *abfd, bfd_size_type wanted);
87933965Sjdp
88033965SjdpDESCRIPTION
88133965Sjdp	Allocate a block of @var{wanted} bytes of memory attached to
88233965Sjdp	<<abfd>> and return a pointer to it.
88333965Sjdp*/
88433965Sjdp
885130561Sobrienvoid *
886130561Sobrienbfd_alloc (bfd *abfd, bfd_size_type size)
88733965Sjdp{
888130561Sobrien  void *ret;
88933965Sjdp
89089857Sobrien  if (size != (unsigned long) size)
89189857Sobrien    {
89289857Sobrien      bfd_set_error (bfd_error_no_memory);
89389857Sobrien      return NULL;
89489857Sobrien    }
89589857Sobrien
89633965Sjdp  ret = objalloc_alloc (abfd->memory, (unsigned long) size);
89733965Sjdp  if (ret == NULL)
89833965Sjdp    bfd_set_error (bfd_error_no_memory);
89933965Sjdp  return ret;
90033965Sjdp}
90133965Sjdp
902218822Sdim/*
903218822SdimINTERNAL_FUNCTION
904218822Sdim	bfd_alloc2
905218822Sdim
906218822SdimSYNOPSIS
907218822Sdim	void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
908218822Sdim
909218822SdimDESCRIPTION
910218822Sdim	Allocate a block of @var{nmemb} elements of @var{size} bytes each
911218822Sdim	of memory attached to <<abfd>> and return a pointer to it.
912218822Sdim*/
913218822Sdim
914130561Sobrienvoid *
915218822Sdimbfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
916218822Sdim{
917218822Sdim  void *ret;
918218822Sdim
919218822Sdim  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
920218822Sdim      && size != 0
921218822Sdim      && nmemb > ~(bfd_size_type) 0 / size)
922218822Sdim    {
923218822Sdim      bfd_set_error (bfd_error_no_memory);
924218822Sdim      return NULL;
925218822Sdim    }
926218822Sdim
927218822Sdim  size *= nmemb;
928218822Sdim
929218822Sdim  if (size != (unsigned long) size)
930218822Sdim    {
931218822Sdim      bfd_set_error (bfd_error_no_memory);
932218822Sdim      return NULL;
933218822Sdim    }
934218822Sdim
935218822Sdim  ret = objalloc_alloc (abfd->memory, (unsigned long) size);
936218822Sdim  if (ret == NULL)
937218822Sdim    bfd_set_error (bfd_error_no_memory);
938218822Sdim  return ret;
939218822Sdim}
940218822Sdim
941218822Sdim/*
942218822SdimINTERNAL_FUNCTION
943218822Sdim	bfd_zalloc
944218822Sdim
945218822SdimSYNOPSIS
946218822Sdim	void *bfd_zalloc (bfd *abfd, bfd_size_type wanted);
947218822Sdim
948218822SdimDESCRIPTION
949218822Sdim	Allocate a block of @var{wanted} bytes of zeroed memory
950218822Sdim	attached to <<abfd>> and return a pointer to it.
951218822Sdim*/
952218822Sdim
953218822Sdimvoid *
954130561Sobrienbfd_zalloc (bfd *abfd, bfd_size_type size)
95533965Sjdp{
956130561Sobrien  void *res;
95733965Sjdp
95833965Sjdp  res = bfd_alloc (abfd, size);
95933965Sjdp  if (res)
96089857Sobrien    memset (res, 0, (size_t) size);
96133965Sjdp  return res;
96233965Sjdp}
96333965Sjdp
964218822Sdim/*
965218822SdimINTERNAL_FUNCTION
966218822Sdim	bfd_zalloc2
967218822Sdim
968218822SdimSYNOPSIS
969218822Sdim	void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
970218822Sdim
971218822SdimDESCRIPTION
972218822Sdim	Allocate a block of @var{nmemb} elements of @var{size} bytes each
973218822Sdim	of zeroed memory attached to <<abfd>> and return a pointer to it.
974218822Sdim*/
975218822Sdim
976218822Sdimvoid *
977218822Sdimbfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
978218822Sdim{
979218822Sdim  void *res;
980218822Sdim
981218822Sdim  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
982218822Sdim      && size != 0
983218822Sdim      && nmemb > ~(bfd_size_type) 0 / size)
984218822Sdim    {
985218822Sdim      bfd_set_error (bfd_error_no_memory);
986218822Sdim      return NULL;
987218822Sdim    }
988218822Sdim
989218822Sdim  size *= nmemb;
990218822Sdim
991218822Sdim  res = bfd_alloc (abfd, size);
992218822Sdim  if (res)
993218822Sdim    memset (res, 0, (size_t) size);
994218822Sdim  return res;
995218822Sdim}
996218822Sdim
99789857Sobrien/* Free a block allocated for a BFD.
99889857Sobrien   Note:  Also frees all more recently allocated blocks!  */
99933965Sjdp
100033965Sjdpvoid
1001130561Sobrienbfd_release (bfd *abfd, void *block)
100233965Sjdp{
100333965Sjdp  objalloc_free_block ((struct objalloc *) abfd->memory, block);
100433965Sjdp}
1005130561Sobrien
1006130561Sobrien
1007218822Sdim/*
1008218822Sdim   GNU Extension: separate debug-info files
1009218822Sdim
1010130561Sobrien   The idea here is that a special section called .gnu_debuglink might be
1011130561Sobrien   embedded in a binary file, which indicates that some *other* file
1012130561Sobrien   contains the real debugging information. This special section contains a
1013130561Sobrien   filename and CRC32 checksum, which we read and resolve to another file,
1014130561Sobrien   if it exists.
1015130561Sobrien
1016130561Sobrien   This facilitates "optional" provision of debugging information, without
1017130561Sobrien   having to provide two complete copies of every binary object (with and
1018130561Sobrien   without debug symbols).
1019130561Sobrien*/
1020130561Sobrien
1021130561Sobrien#define GNU_DEBUGLINK	".gnu_debuglink"
1022130561Sobrien/*
1023130561SobrienFUNCTION
1024130561Sobrien	bfd_calc_gnu_debuglink_crc32
1025130561Sobrien
1026130561SobrienSYNOPSIS
1027130561Sobrien	unsigned long bfd_calc_gnu_debuglink_crc32
1028130561Sobrien	  (unsigned long crc, const unsigned char *buf, bfd_size_type len);
1029130561Sobrien
1030130561SobrienDESCRIPTION
1031130561Sobrien	Computes a CRC value as used in the .gnu_debuglink section.
1032130561Sobrien	Advances the previously computed @var{crc} value by computing
1033130561Sobrien	and adding in the crc32 for @var{len} bytes of @var{buf}.
1034130561Sobrien
1035130561SobrienRETURNS
1036130561Sobrien	Return the updated CRC32 value.
1037218822Sdim*/
1038130561Sobrien
1039130561Sobrienunsigned long
1040130561Sobrienbfd_calc_gnu_debuglink_crc32 (unsigned long crc,
1041130561Sobrien			      const unsigned char *buf,
1042130561Sobrien			      bfd_size_type len)
1043130561Sobrien{
1044130561Sobrien  static const unsigned long crc32_table[256] =
1045130561Sobrien    {
1046130561Sobrien      0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
1047130561Sobrien      0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
1048130561Sobrien      0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
1049130561Sobrien      0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1050130561Sobrien      0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
1051130561Sobrien      0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1052130561Sobrien      0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
1053130561Sobrien      0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1054130561Sobrien      0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
1055130561Sobrien      0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
1056130561Sobrien      0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
1057130561Sobrien      0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1058130561Sobrien      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
1059130561Sobrien      0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
1060130561Sobrien      0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
1061130561Sobrien      0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1062130561Sobrien      0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
1063130561Sobrien      0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1064130561Sobrien      0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
1065130561Sobrien      0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1066130561Sobrien      0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
1067130561Sobrien      0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
1068130561Sobrien      0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
1069130561Sobrien      0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1070130561Sobrien      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
1071130561Sobrien      0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
1072130561Sobrien      0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1073130561Sobrien      0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1074130561Sobrien      0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
1075130561Sobrien      0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1076130561Sobrien      0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
1077130561Sobrien      0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1078130561Sobrien      0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
1079130561Sobrien      0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
1080130561Sobrien      0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
1081130561Sobrien      0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1082130561Sobrien      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1083130561Sobrien      0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1084130561Sobrien      0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1085130561Sobrien      0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1086130561Sobrien      0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1087130561Sobrien      0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1088130561Sobrien      0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1089130561Sobrien      0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1090130561Sobrien      0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1091130561Sobrien      0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1092130561Sobrien      0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1093130561Sobrien      0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1094130561Sobrien      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1095130561Sobrien      0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1096130561Sobrien      0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1097130561Sobrien      0x2d02ef8d
1098130561Sobrien    };
1099130561Sobrien  const unsigned char *end;
1100130561Sobrien
1101130561Sobrien  crc = ~crc & 0xffffffff;
1102130561Sobrien  for (end = buf + len; buf < end; ++ buf)
1103130561Sobrien    crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
1104130561Sobrien  return ~crc & 0xffffffff;;
1105130561Sobrien}
1106130561Sobrien
1107130561Sobrien
1108130561Sobrien/*
1109130561SobrienINTERNAL_FUNCTION
1110130561Sobrien	get_debug_link_info
1111130561Sobrien
1112130561SobrienSYNOPSIS
1113130561Sobrien	char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out);
1114130561Sobrien
1115130561SobrienDESCRIPTION
1116130561Sobrien	fetch the filename and CRC32 value for any separate debuginfo
1117130561Sobrien	associated with @var{abfd}. Return NULL if no such info found,
1118130561Sobrien	otherwise return filename and update @var{crc32_out}.
1119130561Sobrien*/
1120130561Sobrien
1121130561Sobrienstatic char *
1122130561Sobrienget_debug_link_info (bfd *abfd, unsigned long *crc32_out)
1123130561Sobrien{
1124218822Sdim  asection *sect;
1125130561Sobrien  unsigned long crc32;
1126218822Sdim  bfd_byte *contents;
1127130561Sobrien  int crc_offset;
1128218822Sdim  char *name;
1129130561Sobrien
1130130561Sobrien  BFD_ASSERT (abfd);
1131130561Sobrien  BFD_ASSERT (crc32_out);
1132130561Sobrien
1133130561Sobrien  sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK);
1134130561Sobrien
1135130561Sobrien  if (sect == NULL)
1136130561Sobrien    return NULL;
1137130561Sobrien
1138218822Sdim  if (!bfd_malloc_and_get_section (abfd, sect, &contents))
1139130561Sobrien    {
1140218822Sdim      if (contents != NULL)
1141218822Sdim	free (contents);
1142130561Sobrien      return NULL;
1143130561Sobrien    }
1144130561Sobrien
1145130561Sobrien  /* Crc value is stored after the filename, aligned up to 4 bytes.  */
1146218822Sdim  name = (char *) contents;
1147218822Sdim  crc_offset = strlen (name) + 1;
1148130561Sobrien  crc_offset = (crc_offset + 3) & ~3;
1149130561Sobrien
1150130561Sobrien  crc32 = bfd_get_32 (abfd, contents + crc_offset);
1151130561Sobrien
1152130561Sobrien  *crc32_out = crc32;
1153218822Sdim  return name;
1154130561Sobrien}
1155130561Sobrien
1156130561Sobrien/*
1157130561SobrienINTERNAL_FUNCTION
1158130561Sobrien	separate_debug_file_exists
1159130561Sobrien
1160130561SobrienSYNOPSIS
1161130561Sobrien	bfd_boolean separate_debug_file_exists
1162130561Sobrien	  (char *name, unsigned long crc32);
1163130561Sobrien
1164130561SobrienDESCRIPTION
1165130561Sobrien	Checks to see if @var{name} is a file and if its contents
1166130561Sobrien	match @var{crc32}.
1167130561Sobrien*/
1168130561Sobrien
1169130561Sobrienstatic bfd_boolean
1170130561Sobrienseparate_debug_file_exists (const char *name, const unsigned long crc)
1171130561Sobrien{
1172218822Sdim  static unsigned char buffer [8 * 1024];
1173130561Sobrien  unsigned long file_crc = 0;
1174130561Sobrien  int fd;
1175130561Sobrien  bfd_size_type count;
1176130561Sobrien
1177130561Sobrien  BFD_ASSERT (name);
1178130561Sobrien
1179130561Sobrien  fd = open (name, O_RDONLY);
1180130561Sobrien  if (fd < 0)
1181130561Sobrien    return FALSE;
1182130561Sobrien
1183130561Sobrien  while ((count = read (fd, buffer, sizeof (buffer))) > 0)
1184130561Sobrien    file_crc = bfd_calc_gnu_debuglink_crc32 (file_crc, buffer, count);
1185130561Sobrien
1186130561Sobrien  close (fd);
1187130561Sobrien
1188130561Sobrien  return crc == file_crc;
1189130561Sobrien}
1190130561Sobrien
1191130561Sobrien
1192130561Sobrien/*
1193130561SobrienINTERNAL_FUNCTION
1194130561Sobrien	find_separate_debug_file
1195130561Sobrien
1196130561SobrienSYNOPSIS
1197130561Sobrien	char *find_separate_debug_file (bfd *abfd);
1198130561Sobrien
1199130561SobrienDESCRIPTION
1200130561Sobrien	Searches @var{abfd} for a reference to separate debugging
1201130561Sobrien	information, scans various locations in the filesystem, including
1202130561Sobrien	the file tree rooted at @var{debug_file_directory}, and returns a
1203130561Sobrien	filename of such debugging information if the file is found and has
1204130561Sobrien	matching CRC32.  Returns NULL if no reference to debugging file
1205130561Sobrien	exists, or file cannot be found.
1206130561Sobrien*/
1207130561Sobrien
1208130561Sobrienstatic char *
1209130561Sobrienfind_separate_debug_file (bfd *abfd, const char *debug_file_directory)
1210130561Sobrien{
1211130561Sobrien  char *basename;
1212130561Sobrien  char *dir;
1213130561Sobrien  char *debugfile;
1214130561Sobrien  unsigned long crc32;
1215130561Sobrien  int i;
1216130561Sobrien
1217130561Sobrien  BFD_ASSERT (abfd);
1218130561Sobrien  if (debug_file_directory == NULL)
1219130561Sobrien    debug_file_directory = ".";
1220130561Sobrien
1221130561Sobrien  /* BFD may have been opened from a stream.  */
1222130561Sobrien  if (! abfd->filename)
1223130561Sobrien    return NULL;
1224130561Sobrien
1225130561Sobrien  basename = get_debug_link_info (abfd, & crc32);
1226130561Sobrien  if (basename == NULL)
1227130561Sobrien    return NULL;
1228130561Sobrien
1229130561Sobrien  if (strlen (basename) < 1)
1230130561Sobrien    {
1231130561Sobrien      free (basename);
1232130561Sobrien      return NULL;
1233130561Sobrien    }
1234130561Sobrien
1235130561Sobrien  dir = strdup (abfd->filename);
1236130561Sobrien  if (dir == NULL)
1237130561Sobrien    {
1238130561Sobrien      free (basename);
1239130561Sobrien      return NULL;
1240130561Sobrien    }
1241130561Sobrien  BFD_ASSERT (strlen (dir) != 0);
1242218822Sdim
1243130561Sobrien  /* Strip off filename part.  */
1244130561Sobrien  for (i = strlen (dir) - 1; i >= 0; i--)
1245130561Sobrien    if (IS_DIR_SEPARATOR (dir[i]))
1246130561Sobrien      break;
1247130561Sobrien
1248130561Sobrien  dir[i + 1] = '\0';
1249218822Sdim  BFD_ASSERT (dir[i] == '/' || dir[0] == '\0');
1250130561Sobrien
1251130561Sobrien  debugfile = malloc (strlen (debug_file_directory) + 1
1252130561Sobrien		      + strlen (dir)
1253130561Sobrien		      + strlen (".debug/")
1254218822Sdim		      + strlen (basename)
1255130561Sobrien		      + 1);
1256130561Sobrien  if (debugfile == NULL)
1257130561Sobrien    {
1258130561Sobrien      free (basename);
1259130561Sobrien      free (dir);
1260130561Sobrien      return NULL;
1261130561Sobrien    }
1262130561Sobrien
1263130561Sobrien  /* First try in the same directory as the original file:  */
1264130561Sobrien  strcpy (debugfile, dir);
1265130561Sobrien  strcat (debugfile, basename);
1266130561Sobrien
1267130561Sobrien  if (separate_debug_file_exists (debugfile, crc32))
1268130561Sobrien    {
1269130561Sobrien      free (basename);
1270130561Sobrien      free (dir);
1271130561Sobrien      return debugfile;
1272130561Sobrien    }
1273130561Sobrien
1274130561Sobrien  /* Then try in a subdirectory called .debug.  */
1275130561Sobrien  strcpy (debugfile, dir);
1276130561Sobrien  strcat (debugfile, ".debug/");
1277130561Sobrien  strcat (debugfile, basename);
1278130561Sobrien
1279130561Sobrien  if (separate_debug_file_exists (debugfile, crc32))
1280130561Sobrien    {
1281130561Sobrien      free (basename);
1282130561Sobrien      free (dir);
1283130561Sobrien      return debugfile;
1284130561Sobrien    }
1285130561Sobrien
1286130561Sobrien  /* Then try in the global debugfile directory.  */
1287130561Sobrien  strcpy (debugfile, debug_file_directory);
1288130561Sobrien  i = strlen (debug_file_directory) - 1;
1289130561Sobrien  if (i > 0
1290130561Sobrien      && debug_file_directory[i] != '/'
1291130561Sobrien      && dir[0] != '/')
1292130561Sobrien    strcat (debugfile, "/");
1293130561Sobrien  strcat (debugfile, dir);
1294130561Sobrien  strcat (debugfile, basename);
1295130561Sobrien
1296130561Sobrien  if (separate_debug_file_exists (debugfile, crc32))
1297130561Sobrien    {
1298130561Sobrien      free (basename);
1299130561Sobrien      free (dir);
1300130561Sobrien      return debugfile;
1301130561Sobrien    }
1302130561Sobrien
1303130561Sobrien  free (debugfile);
1304130561Sobrien  free (basename);
1305130561Sobrien  free (dir);
1306130561Sobrien  return NULL;
1307130561Sobrien}
1308130561Sobrien
1309130561Sobrien
1310130561Sobrien/*
1311130561SobrienFUNCTION
1312130561Sobrien	bfd_follow_gnu_debuglink
1313130561Sobrien
1314130561SobrienSYNOPSIS
1315130561Sobrien	char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir);
1316130561Sobrien
1317130561SobrienDESCRIPTION
1318130561Sobrien
1319130561Sobrien	Takes a BFD and searches it for a .gnu_debuglink section.  If this
1320130561Sobrien	section is found, it examines the section for the name and checksum
1321130561Sobrien	of a '.debug' file containing auxiliary debugging information.  It
1322130561Sobrien	then searches the filesystem for this .debug file in some standard
1323130561Sobrien	locations, including the directory tree rooted at @var{dir}, and if
1324130561Sobrien	found returns the full filename.
1325130561Sobrien
1326130561Sobrien	If @var{dir} is NULL, it will search a default path configured into
1327130561Sobrien	libbfd at build time.  [XXX this feature is not currently
1328130561Sobrien	implemented].
1329130561Sobrien
1330130561SobrienRETURNS
1331130561Sobrien	<<NULL>> on any errors or failure to locate the .debug file,
1332130561Sobrien	otherwise a pointer to a heap-allocated string containing the
1333130561Sobrien	filename.  The caller is responsible for freeing this string.
1334130561Sobrien*/
1335130561Sobrien
1336130561Sobrienchar *
1337130561Sobrienbfd_follow_gnu_debuglink (bfd *abfd, const char *dir)
1338130561Sobrien{
1339130561Sobrien  return find_separate_debug_file (abfd, dir);
1340130561Sobrien}
1341130561Sobrien
1342130561Sobrien/*
1343130561SobrienFUNCTION
1344130561Sobrien	bfd_create_gnu_debuglink_section
1345130561Sobrien
1346130561SobrienSYNOPSIS
1347130561Sobrien	struct bfd_section *bfd_create_gnu_debuglink_section
1348130561Sobrien	  (bfd *abfd, const char *filename);
1349130561Sobrien
1350130561SobrienDESCRIPTION
1351130561Sobrien
1352130561Sobrien	Takes a @var{BFD} and adds a .gnu_debuglink section to it.  The section is sized
1353130561Sobrien	to be big enough to contain a link to the specified @var{filename}.
1354130561Sobrien
1355130561SobrienRETURNS
1356130561Sobrien	A pointer to the new section is returned if all is ok.  Otherwise <<NULL>> is
1357218822Sdim	returned and bfd_error is set.
1358130561Sobrien*/
1359130561Sobrien
1360130561Sobrienasection *
1361130561Sobrienbfd_create_gnu_debuglink_section (bfd *abfd, const char *filename)
1362130561Sobrien{
1363130561Sobrien  asection *sect;
1364130561Sobrien  bfd_size_type debuglink_size;
1365218822Sdim  flagword flags;
1366130561Sobrien
1367130561Sobrien  if (abfd == NULL || filename == NULL)
1368130561Sobrien    {
1369130561Sobrien      bfd_set_error (bfd_error_invalid_operation);
1370130561Sobrien      return NULL;
1371130561Sobrien    }
1372130561Sobrien
1373130561Sobrien  /* Strip off any path components in filename.  */
1374130561Sobrien  filename = lbasename (filename);
1375218822Sdim
1376130561Sobrien  sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK);
1377130561Sobrien  if (sect)
1378130561Sobrien    {
1379130561Sobrien      /* Section already exists.  */
1380130561Sobrien      bfd_set_error (bfd_error_invalid_operation);
1381130561Sobrien      return NULL;
1382130561Sobrien    }
1383130561Sobrien
1384218822Sdim  flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING;
1385218822Sdim  sect = bfd_make_section_with_flags (abfd, GNU_DEBUGLINK, flags);
1386130561Sobrien  if (sect == NULL)
1387130561Sobrien    return NULL;
1388130561Sobrien
1389130561Sobrien  debuglink_size = strlen (filename) + 1;
1390130561Sobrien  debuglink_size += 3;
1391130561Sobrien  debuglink_size &= ~3;
1392130561Sobrien  debuglink_size += 4;
1393130561Sobrien
1394130561Sobrien  if (! bfd_set_section_size (abfd, sect, debuglink_size))
1395130561Sobrien    /* XXX Should we delete the section from the bfd ?  */
1396130561Sobrien    return NULL;
1397218822Sdim
1398130561Sobrien  return sect;
1399130561Sobrien}
1400130561Sobrien
1401130561Sobrien
1402130561Sobrien/*
1403130561SobrienFUNCTION
1404130561Sobrien	bfd_fill_in_gnu_debuglink_section
1405130561Sobrien
1406130561SobrienSYNOPSIS
1407130561Sobrien	bfd_boolean bfd_fill_in_gnu_debuglink_section
1408130561Sobrien	  (bfd *abfd, struct bfd_section *sect, const char *filename);
1409130561Sobrien
1410130561SobrienDESCRIPTION
1411130561Sobrien
1412130561Sobrien	Takes a @var{BFD} and containing a .gnu_debuglink section @var{SECT}
1413130561Sobrien	and fills in the contents of the section to contain a link to the
1414130561Sobrien	specified @var{filename}.  The filename should be relative to the
1415130561Sobrien	current directory.
1416130561Sobrien
1417130561SobrienRETURNS
1418130561Sobrien	<<TRUE>> is returned if all is ok.  Otherwise <<FALSE>> is returned
1419218822Sdim	and bfd_error is set.
1420130561Sobrien*/
1421130561Sobrien
1422130561Sobrienbfd_boolean
1423130561Sobrienbfd_fill_in_gnu_debuglink_section (bfd *abfd,
1424130561Sobrien				   struct bfd_section *sect,
1425130561Sobrien				   const char *filename)
1426130561Sobrien{
1427130561Sobrien  bfd_size_type debuglink_size;
1428130561Sobrien  unsigned long crc32;
1429130561Sobrien  char * contents;
1430130561Sobrien  bfd_size_type crc_offset;
1431130561Sobrien  FILE * handle;
1432218822Sdim  static unsigned char buffer[8 * 1024];
1433130561Sobrien  size_t count;
1434130561Sobrien
1435130561Sobrien  if (abfd == NULL || sect == NULL || filename == NULL)
1436130561Sobrien    {
1437130561Sobrien      bfd_set_error (bfd_error_invalid_operation);
1438130561Sobrien      return FALSE;
1439130561Sobrien    }
1440130561Sobrien
1441130561Sobrien  /* Make sure that we can read the file.
1442130561Sobrien     XXX - Should we attempt to locate the debug info file using the same
1443130561Sobrien     algorithm as gdb ?  At the moment, since we are creating the
1444130561Sobrien     .gnu_debuglink section, we insist upon the user providing us with a
1445130561Sobrien     correct-for-section-creation-time path, but this need not conform to
1446130561Sobrien     the gdb location algorithm.  */
1447218822Sdim  handle = real_fopen (filename, FOPEN_RB);
1448130561Sobrien  if (handle == NULL)
1449130561Sobrien    {
1450130561Sobrien      bfd_set_error (bfd_error_system_call);
1451130561Sobrien      return FALSE;
1452130561Sobrien    }
1453130561Sobrien
1454130561Sobrien  crc32 = 0;
1455130561Sobrien  while ((count = fread (buffer, 1, sizeof buffer, handle)) > 0)
1456130561Sobrien    crc32 = bfd_calc_gnu_debuglink_crc32 (crc32, buffer, count);
1457130561Sobrien  fclose (handle);
1458130561Sobrien
1459130561Sobrien  /* Strip off any path components in filename,
1460130561Sobrien     now that we no longer need them.  */
1461130561Sobrien  filename = lbasename (filename);
1462218822Sdim
1463130561Sobrien  debuglink_size = strlen (filename) + 1;
1464130561Sobrien  debuglink_size += 3;
1465130561Sobrien  debuglink_size &= ~3;
1466130561Sobrien  debuglink_size += 4;
1467130561Sobrien
1468215105Scperciva  contents = bfd_zmalloc (debuglink_size);
1469130561Sobrien  if (contents == NULL)
1470130561Sobrien    {
1471130561Sobrien      /* XXX Should we delete the section from the bfd ?  */
1472130561Sobrien      bfd_set_error (bfd_error_no_memory);
1473130561Sobrien      return FALSE;
1474130561Sobrien    }
1475130561Sobrien
1476130561Sobrien  strcpy (contents, filename);
1477130561Sobrien  crc_offset = debuglink_size - 4;
1478130561Sobrien
1479130561Sobrien  bfd_put_32 (abfd, crc32, contents + crc_offset);
1480130561Sobrien
1481130561Sobrien  if (! bfd_set_section_contents (abfd, sect, contents, 0, debuglink_size))
1482130561Sobrien    {
1483130561Sobrien      /* XXX Should we delete the section from the bfd ?  */
1484130561Sobrien      free (contents);
1485130561Sobrien      return FALSE;
1486130561Sobrien    }
1487130561Sobrien
1488130561Sobrien  return TRUE;
1489130561Sobrien}
1490