Home | History | Annotate | Line # | Download | only in bfd
compress.c revision 1.3
      1  1.1  christos /* Compressed section support (intended for debug sections).
      2  1.3  christos    Copyright (C) 2008-2015 Free Software Foundation, Inc.
      3  1.1  christos 
      4  1.1  christos    This file is part of BFD, the Binary File Descriptor library.
      5  1.1  christos 
      6  1.1  christos    This program is free software; you can redistribute it and/or modify
      7  1.1  christos    it under the terms of the GNU General Public License as published by
      8  1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9  1.1  christos    (at your option) any later version.
     10  1.1  christos 
     11  1.1  christos    This program is distributed in the hope that it will be useful,
     12  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  1.1  christos    GNU General Public License for more details.
     15  1.1  christos 
     16  1.1  christos    You should have received a copy of the GNU General Public License
     17  1.1  christos    along with this program; if not, write to the Free Software
     18  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19  1.1  christos    MA 02110-1301, USA.  */
     20  1.1  christos 
     21  1.1  christos #include "sysdep.h"
     22  1.1  christos #include "bfd.h"
     23  1.1  christos #include "libbfd.h"
     24  1.1  christos #ifdef HAVE_ZLIB_H
     25  1.1  christos #include <zlib.h>
     26  1.1  christos #endif
     27  1.3  christos #include "safe-ctype.h"
     28  1.1  christos 
     29  1.1  christos #ifdef HAVE_ZLIB_H
     30  1.1  christos static bfd_boolean
     31  1.1  christos decompress_contents (bfd_byte *compressed_buffer,
     32  1.1  christos 		     bfd_size_type compressed_size,
     33  1.1  christos 		     bfd_byte *uncompressed_buffer,
     34  1.1  christos 		     bfd_size_type uncompressed_size)
     35  1.1  christos {
     36  1.1  christos   z_stream strm;
     37  1.1  christos   int rc;
     38  1.1  christos 
     39  1.1  christos   /* It is possible the section consists of several compressed
     40  1.1  christos      buffers concatenated together, so we uncompress in a loop.  */
     41  1.1  christos   strm.zalloc = NULL;
     42  1.1  christos   strm.zfree = NULL;
     43  1.1  christos   strm.opaque = NULL;
     44  1.1  christos   strm.avail_in = compressed_size - 12;
     45  1.1  christos   strm.next_in = (Bytef*) compressed_buffer + 12;
     46  1.1  christos   strm.avail_out = uncompressed_size;
     47  1.1  christos 
     48  1.1  christos   BFD_ASSERT (Z_OK == 0);
     49  1.1  christos   rc = inflateInit (&strm);
     50  1.1  christos   while (strm.avail_in > 0 && strm.avail_out > 0)
     51  1.1  christos     {
     52  1.1  christos       if (rc != Z_OK)
     53  1.1  christos 	break;
     54  1.1  christos       strm.next_out = ((Bytef*) uncompressed_buffer
     55  1.1  christos                        + (uncompressed_size - strm.avail_out));
     56  1.1  christos       rc = inflate (&strm, Z_FINISH);
     57  1.1  christos       if (rc != Z_STREAM_END)
     58  1.1  christos 	break;
     59  1.1  christos       rc = inflateReset (&strm);
     60  1.1  christos     }
     61  1.1  christos   rc |= inflateEnd (&strm);
     62  1.1  christos   return rc == Z_OK && strm.avail_out == 0;
     63  1.1  christos }
     64  1.1  christos #endif
     65  1.1  christos 
     66  1.1  christos /*
     67  1.1  christos FUNCTION
     68  1.1  christos 	bfd_compress_section_contents
     69  1.1  christos 
     70  1.1  christos SYNOPSIS
     71  1.1  christos 	bfd_boolean bfd_compress_section_contents
     72  1.1  christos 	  (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer,
     73  1.1  christos 	   bfd_size_type uncompressed_size);
     74  1.1  christos 
     75  1.1  christos DESCRIPTION
     76  1.1  christos 
     77  1.1  christos 	Compress data of the size specified in @var{uncompressed_size}
     78  1.1  christos 	and pointed to by @var{uncompressed_buffer} using zlib and store
     79  1.1  christos 	as the contents field.  This function assumes the contents
     80  1.1  christos 	field was allocated using bfd_malloc() or equivalent.  If zlib
     81  1.1  christos 	is not installed on this machine, the input is unmodified.
     82  1.1  christos 
     83  1.1  christos 	Return @code{TRUE} if the full section contents is compressed
     84  1.1  christos 	successfully.
     85  1.1  christos */
     86  1.1  christos 
     87  1.1  christos bfd_boolean
     88  1.1  christos bfd_compress_section_contents (bfd *abfd ATTRIBUTE_UNUSED,
     89  1.1  christos 			       sec_ptr sec ATTRIBUTE_UNUSED,
     90  1.1  christos 			       bfd_byte *uncompressed_buffer ATTRIBUTE_UNUSED,
     91  1.1  christos 			       bfd_size_type uncompressed_size ATTRIBUTE_UNUSED)
     92  1.1  christos {
     93  1.1  christos #ifndef HAVE_ZLIB_H
     94  1.1  christos   bfd_set_error (bfd_error_invalid_operation);
     95  1.1  christos   return FALSE;
     96  1.1  christos #else
     97  1.1  christos   uLong compressed_size;
     98  1.1  christos   bfd_byte *compressed_buffer;
     99  1.1  christos 
    100  1.1  christos   compressed_size = compressBound (uncompressed_size) + 12;
    101  1.1  christos   compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size);
    102  1.1  christos 
    103  1.1  christos   if (compressed_buffer == NULL)
    104  1.1  christos     return FALSE;
    105  1.1  christos 
    106  1.1  christos   if (compress ((Bytef*) compressed_buffer + 12,
    107  1.1  christos 		&compressed_size,
    108  1.1  christos 		(const Bytef*) uncompressed_buffer,
    109  1.1  christos 		uncompressed_size) != Z_OK)
    110  1.1  christos     {
    111  1.1  christos       free (compressed_buffer);
    112  1.1  christos       bfd_set_error (bfd_error_bad_value);
    113  1.1  christos       return FALSE;
    114  1.1  christos     }
    115  1.1  christos 
    116  1.1  christos   /* Write the zlib header.  In this case, it should be "ZLIB" followed
    117  1.1  christos      by the uncompressed section size, 8 bytes in big-endian order.  */
    118  1.1  christos   memcpy (compressed_buffer, "ZLIB", 4);
    119  1.1  christos   compressed_buffer[11] = uncompressed_size; uncompressed_size >>= 8;
    120  1.1  christos   compressed_buffer[10] = uncompressed_size; uncompressed_size >>= 8;
    121  1.1  christos   compressed_buffer[9] = uncompressed_size; uncompressed_size >>= 8;
    122  1.1  christos   compressed_buffer[8] = uncompressed_size; uncompressed_size >>= 8;
    123  1.1  christos   compressed_buffer[7] = uncompressed_size; uncompressed_size >>= 8;
    124  1.1  christos   compressed_buffer[6] = uncompressed_size; uncompressed_size >>= 8;
    125  1.1  christos   compressed_buffer[5] = uncompressed_size; uncompressed_size >>= 8;
    126  1.1  christos   compressed_buffer[4] = uncompressed_size;
    127  1.1  christos   compressed_size += 12;
    128  1.1  christos 
    129  1.1  christos   /* Free the uncompressed contents if we compress in place.  */
    130  1.1  christos   if (uncompressed_buffer == sec->contents)
    131  1.1  christos     free (uncompressed_buffer);
    132  1.1  christos 
    133  1.1  christos   sec->contents = compressed_buffer;
    134  1.1  christos   sec->size = compressed_size;
    135  1.1  christos   sec->compress_status = COMPRESS_SECTION_DONE;
    136  1.1  christos 
    137  1.1  christos   return TRUE;
    138  1.1  christos #endif  /* HAVE_ZLIB_H */
    139  1.1  christos }
    140  1.1  christos 
    141  1.1  christos /*
    142  1.1  christos FUNCTION
    143  1.1  christos 	bfd_get_full_section_contents
    144  1.1  christos 
    145  1.1  christos SYNOPSIS
    146  1.1  christos 	bfd_boolean bfd_get_full_section_contents
    147  1.1  christos 	  (bfd *abfd, asection *section, bfd_byte **ptr);
    148  1.1  christos 
    149  1.1  christos DESCRIPTION
    150  1.1  christos 	Read all data from @var{section} in BFD @var{abfd}, decompress
    151  1.1  christos 	if needed, and store in @var{*ptr}.  If @var{*ptr} is NULL,
    152  1.1  christos 	return @var{*ptr} with memory malloc'd by this function.
    153  1.1  christos 
    154  1.1  christos 	Return @code{TRUE} if the full section contents is retrieved
    155  1.3  christos 	successfully.  If the section has no contents then this function
    156  1.3  christos 	returns @code{TRUE} but @var{*ptr} is set to NULL.
    157  1.1  christos */
    158  1.1  christos 
    159  1.1  christos bfd_boolean
    160  1.1  christos bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
    161  1.1  christos {
    162  1.1  christos   bfd_size_type sz;
    163  1.1  christos   bfd_byte *p = *ptr;
    164  1.1  christos #ifdef HAVE_ZLIB_H
    165  1.1  christos   bfd_boolean ret;
    166  1.1  christos   bfd_size_type save_size;
    167  1.1  christos   bfd_size_type save_rawsize;
    168  1.1  christos   bfd_byte *compressed_buffer;
    169  1.1  christos #endif
    170  1.1  christos 
    171  1.1  christos   if (abfd->direction != write_direction && sec->rawsize != 0)
    172  1.1  christos     sz = sec->rawsize;
    173  1.1  christos   else
    174  1.1  christos     sz = sec->size;
    175  1.1  christos   if (sz == 0)
    176  1.3  christos     {
    177  1.3  christos       *ptr = NULL;
    178  1.3  christos       return TRUE;
    179  1.3  christos     }
    180  1.1  christos 
    181  1.1  christos   switch (sec->compress_status)
    182  1.1  christos     {
    183  1.1  christos     case COMPRESS_SECTION_NONE:
    184  1.1  christos       if (p == NULL)
    185  1.1  christos 	{
    186  1.1  christos 	  p = (bfd_byte *) bfd_malloc (sz);
    187  1.1  christos 	  if (p == NULL)
    188  1.1  christos 	    return FALSE;
    189  1.1  christos 	}
    190  1.3  christos 
    191  1.1  christos       if (!bfd_get_section_contents (abfd, sec, p, 0, sz))
    192  1.1  christos 	{
    193  1.1  christos 	  if (*ptr != p)
    194  1.1  christos 	    free (p);
    195  1.1  christos 	  return FALSE;
    196  1.1  christos 	}
    197  1.1  christos       *ptr = p;
    198  1.1  christos       return TRUE;
    199  1.1  christos 
    200  1.1  christos     case DECOMPRESS_SECTION_SIZED:
    201  1.1  christos #ifndef HAVE_ZLIB_H
    202  1.1  christos       bfd_set_error (bfd_error_invalid_operation);
    203  1.1  christos       return FALSE;
    204  1.1  christos #else
    205  1.1  christos       /* Read in the full compressed section contents.  */
    206  1.1  christos       compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
    207  1.1  christos       if (compressed_buffer == NULL)
    208  1.1  christos 	return FALSE;
    209  1.1  christos       save_rawsize = sec->rawsize;
    210  1.1  christos       save_size = sec->size;
    211  1.1  christos       /* Clear rawsize, set size to compressed size and set compress_status
    212  1.1  christos 	 to COMPRESS_SECTION_NONE.  If the compressed size is bigger than
    213  1.1  christos 	 the uncompressed size, bfd_get_section_contents will fail.  */
    214  1.1  christos       sec->rawsize = 0;
    215  1.1  christos       sec->size = sec->compressed_size;
    216  1.1  christos       sec->compress_status = COMPRESS_SECTION_NONE;
    217  1.1  christos       ret = bfd_get_section_contents (abfd, sec, compressed_buffer,
    218  1.1  christos 				      0, sec->compressed_size);
    219  1.1  christos       /* Restore rawsize and size.  */
    220  1.1  christos       sec->rawsize = save_rawsize;
    221  1.1  christos       sec->size = save_size;
    222  1.1  christos       sec->compress_status = DECOMPRESS_SECTION_SIZED;
    223  1.1  christos       if (!ret)
    224  1.1  christos 	goto fail_compressed;
    225  1.1  christos 
    226  1.1  christos       if (p == NULL)
    227  1.1  christos 	p = (bfd_byte *) bfd_malloc (sz);
    228  1.1  christos       if (p == NULL)
    229  1.1  christos 	goto fail_compressed;
    230  1.1  christos 
    231  1.1  christos       if (!decompress_contents (compressed_buffer, sec->compressed_size, p, sz))
    232  1.1  christos 	{
    233  1.1  christos 	  bfd_set_error (bfd_error_bad_value);
    234  1.1  christos 	  if (p != *ptr)
    235  1.1  christos 	    free (p);
    236  1.1  christos 	fail_compressed:
    237  1.1  christos 	  free (compressed_buffer);
    238  1.1  christos 	  return FALSE;
    239  1.1  christos 	}
    240  1.1  christos 
    241  1.1  christos       free (compressed_buffer);
    242  1.1  christos       *ptr = p;
    243  1.1  christos       return TRUE;
    244  1.1  christos #endif
    245  1.1  christos 
    246  1.1  christos     case COMPRESS_SECTION_DONE:
    247  1.3  christos       if (sec->contents == NULL)
    248  1.3  christos 	return FALSE;
    249  1.1  christos       if (p == NULL)
    250  1.1  christos 	{
    251  1.1  christos 	  p = (bfd_byte *) bfd_malloc (sz);
    252  1.1  christos 	  if (p == NULL)
    253  1.1  christos 	    return FALSE;
    254  1.1  christos 	  *ptr = p;
    255  1.1  christos 	}
    256  1.3  christos       /* PR 17512; file: 5bc29788.  */
    257  1.3  christos       if (p != sec->contents)
    258  1.3  christos 	memcpy (p, sec->contents, sz);
    259  1.1  christos       return TRUE;
    260  1.1  christos 
    261  1.1  christos     default:
    262  1.1  christos       abort ();
    263  1.1  christos     }
    264  1.1  christos }
    265  1.1  christos 
    266  1.1  christos /*
    267  1.1  christos FUNCTION
    268  1.1  christos 	bfd_cache_section_contents
    269  1.1  christos 
    270  1.1  christos SYNOPSIS
    271  1.1  christos 	void bfd_cache_section_contents
    272  1.1  christos 	  (asection *sec, void *contents);
    273  1.1  christos 
    274  1.1  christos DESCRIPTION
    275  1.1  christos 	Stash @var(contents) so any following reads of @var(sec) do
    276  1.1  christos 	not need to decompress again.
    277  1.1  christos */
    278  1.1  christos 
    279  1.1  christos void
    280  1.1  christos bfd_cache_section_contents (asection *sec, void *contents)
    281  1.1  christos {
    282  1.1  christos   if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
    283  1.1  christos     sec->compress_status = COMPRESS_SECTION_DONE;
    284  1.1  christos   sec->contents = contents;
    285  1.1  christos   sec->flags |= SEC_IN_MEMORY;
    286  1.1  christos }
    287  1.1  christos 
    288  1.1  christos 
    289  1.1  christos /*
    290  1.1  christos FUNCTION
    291  1.1  christos 	bfd_is_section_compressed
    292  1.1  christos 
    293  1.1  christos SYNOPSIS
    294  1.1  christos 	bfd_boolean bfd_is_section_compressed
    295  1.1  christos 	  (bfd *abfd, asection *section);
    296  1.1  christos 
    297  1.1  christos DESCRIPTION
    298  1.1  christos 	Return @code{TRUE} if @var{section} is compressed.
    299  1.1  christos */
    300  1.1  christos 
    301  1.1  christos bfd_boolean
    302  1.1  christos bfd_is_section_compressed (bfd *abfd, sec_ptr sec)
    303  1.1  christos {
    304  1.1  christos   bfd_byte compressed_buffer [12];
    305  1.1  christos   unsigned int saved = sec->compress_status;
    306  1.1  christos   bfd_boolean compressed;
    307  1.1  christos 
    308  1.1  christos   /* Don't decompress the section.  */
    309  1.1  christos   sec->compress_status = COMPRESS_SECTION_NONE;
    310  1.1  christos 
    311  1.1  christos   /* Read the zlib header.  In this case, it should be "ZLIB" followed
    312  1.1  christos      by the uncompressed section size, 8 bytes in big-endian order.  */
    313  1.1  christos   compressed = (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12)
    314  1.1  christos 		&& CONST_STRNEQ ((char*) compressed_buffer, "ZLIB"));
    315  1.1  christos 
    316  1.3  christos   /* Check for the pathalogical case of a debug string section that
    317  1.3  christos      contains the string ZLIB.... as the first entry.  We assume that
    318  1.3  christos      no uncompressed .debug_str section would ever be big enough to
    319  1.3  christos      have the first byte of its (big-endian) size be non-zero.  */
    320  1.3  christos   if (compressed
    321  1.3  christos       && strcmp (sec->name, ".debug_str") == 0
    322  1.3  christos       && ISPRINT (compressed_buffer[4]))
    323  1.3  christos     compressed = FALSE;
    324  1.3  christos 
    325  1.1  christos   /* Restore compress_status.  */
    326  1.1  christos   sec->compress_status = saved;
    327  1.1  christos   return compressed;
    328  1.1  christos }
    329  1.1  christos 
    330  1.1  christos /*
    331  1.1  christos FUNCTION
    332  1.1  christos 	bfd_init_section_decompress_status
    333  1.1  christos 
    334  1.1  christos SYNOPSIS
    335  1.1  christos 	bfd_boolean bfd_init_section_decompress_status
    336  1.1  christos 	  (bfd *abfd, asection *section);
    337  1.1  christos 
    338  1.1  christos DESCRIPTION
    339  1.1  christos 	Record compressed section size, update section size with
    340  1.1  christos 	decompressed size and set compress_status to
    341  1.1  christos 	DECOMPRESS_SECTION_SIZED.
    342  1.1  christos 
    343  1.1  christos 	Return @code{FALSE} if the section is not a valid compressed
    344  1.1  christos 	section or zlib is not installed on this machine.  Otherwise,
    345  1.1  christos 	return @code{TRUE}.
    346  1.1  christos */
    347  1.1  christos 
    348  1.1  christos bfd_boolean
    349  1.1  christos bfd_init_section_decompress_status (bfd *abfd ATTRIBUTE_UNUSED,
    350  1.1  christos 				    sec_ptr sec ATTRIBUTE_UNUSED)
    351  1.1  christos {
    352  1.1  christos #ifndef HAVE_ZLIB_H
    353  1.1  christos   bfd_set_error (bfd_error_invalid_operation);
    354  1.1  christos   return FALSE;
    355  1.1  christos #else
    356  1.1  christos   bfd_byte compressed_buffer [12];
    357  1.1  christos   bfd_size_type uncompressed_size;
    358  1.1  christos 
    359  1.1  christos   if (sec->rawsize != 0
    360  1.1  christos       || sec->contents != NULL
    361  1.1  christos       || sec->compress_status != COMPRESS_SECTION_NONE
    362  1.1  christos       || !bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12))
    363  1.1  christos     {
    364  1.1  christos       bfd_set_error (bfd_error_invalid_operation);
    365  1.1  christos       return FALSE;
    366  1.1  christos     }
    367  1.1  christos 
    368  1.1  christos   /* Read the zlib header.  In this case, it should be "ZLIB" followed
    369  1.1  christos      by the uncompressed section size, 8 bytes in big-endian order.  */
    370  1.1  christos   if (! CONST_STRNEQ ((char*) compressed_buffer, "ZLIB"))
    371  1.1  christos     {
    372  1.1  christos       bfd_set_error (bfd_error_wrong_format);
    373  1.1  christos       return FALSE;
    374  1.1  christos     }
    375  1.1  christos 
    376  1.1  christos   uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8;
    377  1.1  christos   uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8;
    378  1.1  christos   uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8;
    379  1.1  christos   uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8;
    380  1.1  christos   uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8;
    381  1.1  christos   uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8;
    382  1.1  christos   uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8;
    383  1.1  christos   uncompressed_size += compressed_buffer[11];
    384  1.1  christos 
    385  1.1  christos   sec->compressed_size = sec->size;
    386  1.1  christos   sec->size = uncompressed_size;
    387  1.1  christos   sec->compress_status = DECOMPRESS_SECTION_SIZED;
    388  1.1  christos 
    389  1.1  christos   return TRUE;
    390  1.1  christos #endif
    391  1.1  christos }
    392  1.1  christos 
    393  1.1  christos /*
    394  1.1  christos FUNCTION
    395  1.1  christos 	bfd_init_section_compress_status
    396  1.1  christos 
    397  1.1  christos SYNOPSIS
    398  1.1  christos 	bfd_boolean bfd_init_section_compress_status
    399  1.1  christos 	  (bfd *abfd, asection *section);
    400  1.1  christos 
    401  1.1  christos DESCRIPTION
    402  1.1  christos 	If open for read, compress section, update section size with
    403  1.1  christos 	compressed size and set compress_status to COMPRESS_SECTION_DONE.
    404  1.1  christos 
    405  1.1  christos 	Return @code{FALSE} if the section is not a valid compressed
    406  1.1  christos 	section or zlib is not installed on this machine.  Otherwise,
    407  1.1  christos 	return @code{TRUE}.
    408  1.1  christos */
    409  1.1  christos 
    410  1.1  christos bfd_boolean
    411  1.1  christos bfd_init_section_compress_status (bfd *abfd ATTRIBUTE_UNUSED,
    412  1.1  christos 				  sec_ptr sec ATTRIBUTE_UNUSED)
    413  1.1  christos {
    414  1.1  christos #ifndef HAVE_ZLIB_H
    415  1.1  christos   bfd_set_error (bfd_error_invalid_operation);
    416  1.1  christos   return FALSE;
    417  1.1  christos #else
    418  1.1  christos   bfd_size_type uncompressed_size;
    419  1.1  christos   bfd_byte *uncompressed_buffer;
    420  1.1  christos   bfd_boolean ret;
    421  1.1  christos 
    422  1.1  christos   /* Error if not opened for read.  */
    423  1.1  christos   if (abfd->direction != read_direction
    424  1.1  christos       || sec->size == 0
    425  1.1  christos       || sec->rawsize != 0
    426  1.1  christos       || sec->contents != NULL
    427  1.1  christos       || sec->compress_status != COMPRESS_SECTION_NONE)
    428  1.1  christos     {
    429  1.1  christos       bfd_set_error (bfd_error_invalid_operation);
    430  1.1  christos       return FALSE;
    431  1.1  christos     }
    432  1.1  christos 
    433  1.1  christos   /* Read in the full section contents and compress it.  */
    434  1.1  christos   uncompressed_size = sec->size;
    435  1.1  christos   uncompressed_buffer = (bfd_byte *) bfd_malloc (uncompressed_size);
    436  1.1  christos   if (!bfd_get_section_contents (abfd, sec, uncompressed_buffer,
    437  1.1  christos 				 0, uncompressed_size))
    438  1.1  christos     ret = FALSE;
    439  1.1  christos   else
    440  1.1  christos     ret = bfd_compress_section_contents (abfd, sec,
    441  1.1  christos 					 uncompressed_buffer,
    442  1.1  christos 					 uncompressed_size);
    443  1.1  christos 
    444  1.1  christos   free (uncompressed_buffer);
    445  1.1  christos   return ret;
    446  1.1  christos #endif
    447  1.1  christos }
    448