#include "sysdep.h"
#include "bfd.h"
#include "libbfd.h"
#include <limits.h>
#ifndef S_IXUSR
#define S_IXUSR 0100
#endif
#ifndef S_IXGRP
#define S_IXGRP 0010
#endif
#ifndef S_IXOTH
#define S_IXOTH 0001
#endif
file_ptr
real_ftell (FILE *file)
{
#if defined (HAVE_FTELLO64)
return ftello64 (file);
#elif defined (HAVE_FTELLO)
return ftello (file);
#else
return ftell (file);
#endif
}
int
real_fseek (FILE *file, file_ptr offset, int whence)
{
#if defined (HAVE_FSEEKO64)
return fseeko64 (file, offset, whence);
#elif defined (HAVE_FSEEKO)
return fseeko (file, offset, whence);
#else
return fseek (file, offset, whence);
#endif
}
FILE *
real_fopen (const char *filename, const char *modes)
{
#if defined (HAVE_FOPEN64)
return fopen64 (filename, modes);
#else
return fopen (filename, modes);
#endif
}
bfd_size_type
bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
{
size_t nread;
if (abfd->arelt_data != NULL)
{
size_t maxbytes = ((struct areltdata *) abfd->arelt_data)->parsed_size;
if (size > maxbytes)
size = maxbytes;
}
if ((abfd->flags & BFD_IN_MEMORY) != 0)
{
struct bfd_in_memory *bim;
bfd_size_type get;
bim = abfd->iostream;
get = size;
if (abfd->where + get > bim->size)
{
if (bim->size < (bfd_size_type) abfd->where)
get = 0;
else
get = bim->size - abfd->where;
bfd_set_error (bfd_error_file_truncated);
}
memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
abfd->where += get;
return get;
}
if (abfd->iovec)
nread = abfd->iovec->bread (abfd, ptr, size);
else
nread = 0;
if (nread != (size_t) -1)
abfd->where += nread;
return nread;
}
bfd_size_type
bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
{
size_t nwrote;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
{
struct bfd_in_memory *bim = abfd->iostream;
size = (size_t) size;
if (abfd->where + size > bim->size)
{
bfd_size_type newsize, oldsize;
oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
bim->size = abfd->where + size;
newsize = (bim->size + 127) & ~(bfd_size_type) 127;
if (newsize > oldsize)
{
bim->buffer = bfd_realloc (bim->buffer, newsize);
if (bim->buffer == 0)
{
bim->size = 0;
return 0;
}
}
}
memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
abfd->where += size;
return size;
}
if (abfd->iovec)
nwrote = abfd->iovec->bwrite (abfd, ptr, size);
else
nwrote = 0;
if (nwrote != (size_t) -1)
abfd->where += nwrote;
if (nwrote != size)
{
#ifdef ENOSPC
errno = ENOSPC;
#endif
bfd_set_error (bfd_error_system_call);
}
return nwrote;
}
file_ptr
bfd_tell (bfd *abfd)
{
file_ptr ptr;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
return abfd->where;
if (abfd->iovec)
{
ptr = abfd->iovec->btell (abfd);
if (abfd->my_archive)
ptr -= abfd->origin;
}
else
ptr = 0;
abfd->where = ptr;
return ptr;
}
int
bfd_flush (bfd *abfd)
{
if ((abfd->flags & BFD_IN_MEMORY) != 0)
return 0;
if (abfd->iovec)
return abfd->iovec->bflush (abfd);
return 0;
}
int
bfd_stat (bfd *abfd, struct stat *statbuf)
{
int result;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
abort ();
if (abfd->iovec)
result = abfd->iovec->bstat (abfd, statbuf);
else
result = -1;
if (result < 0)
bfd_set_error (bfd_error_system_call);
return result;
}
int
bfd_seek (bfd *abfd, file_ptr position, int direction)
{
int result;
file_ptr file_position;
BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
if (direction == SEEK_CUR && position == 0)
return 0;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
{
struct bfd_in_memory *bim;
bim = abfd->iostream;
if (direction == SEEK_SET)
abfd->where = position;
else
abfd->where += position;
if (abfd->where > bim->size)
{
if ((abfd->direction == write_direction) ||
(abfd->direction == both_direction))
{
bfd_size_type newsize, oldsize;
oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
bim->size = abfd->where;
newsize = (bim->size + 127) & ~(bfd_size_type) 127;
if (newsize > oldsize)
{
bim->buffer = bfd_realloc (bim->buffer, newsize);
if (bim->buffer == 0)
{
bim->size = 0;
return -1;
}
}
}
else
{
abfd->where = bim->size;
bfd_set_error (bfd_error_file_truncated);
return -1;
}
}
return 0;
}
if (abfd->format != bfd_archive && abfd->my_archive == 0)
{
if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
return 0;
}
else
{
}
file_position = position;
if (direction == SEEK_SET && abfd->my_archive != NULL)
file_position += abfd->origin;
if (abfd->iovec)
result = abfd->iovec->bseek (abfd, file_position, direction);
else
result = -1;
if (result != 0)
{
int hold_errno = errno;
bfd_tell (abfd);
if (hold_errno == EINVAL)
bfd_set_error (bfd_error_file_truncated);
else
{
bfd_set_error (bfd_error_system_call);
errno = hold_errno;
}
}
else
{
if (direction == SEEK_SET)
abfd->where = position;
else
abfd->where += position;
}
return result;
}
long
bfd_get_mtime (bfd *abfd)
{
struct stat buf;
if (abfd->mtime_set)
return abfd->mtime;
if (abfd->iovec == NULL)
return 0;
if (abfd->iovec->bstat (abfd, &buf) != 0)
return 0;
abfd->mtime = buf.st_mtime;
return buf.st_mtime;
}
file_ptr
bfd_get_size (bfd *abfd)
{
struct stat buf;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
return ((struct bfd_in_memory *) abfd->iostream)->size;
if (abfd->iovec == NULL)
return 0;
if (abfd->iovec->bstat (abfd, &buf) != 0)
return 0;
return buf.st_size;
}