#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
bfd_size_type
bfd_bread (ptr, size, abfd)
PTR ptr;
bfd_size_type size;
bfd *abfd;
{
while (abfd->my_archive != NULL)
abfd = abfd->my_archive;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
{
struct bfd_in_memory *bim;
bim = (struct bfd_in_memory *) abfd->iostream;
if (abfd->where + size > bim->size)
{
if (abfd->where > bim->size) {
size = 0;
} else {
size = bim->size - abfd->where;
}
bfd_set_error (bfd_error_file_truncated);
}
memcpy (ptr, bim->buffer + abfd->where, size);
abfd->where += size;
return size;
}
else if ((abfd->flags & BFD_IO_FUNCS) != 0)
{
struct bfd_io_functions *bif;
bif = (struct bfd_io_functions *) abfd->iostream;
return (*bif->read_func) (bif->iodata, ptr, 1, size, abfd, abfd->where);
}
else
{
int nread;
nread = fread (ptr, 1, (size_t) (size), bfd_cache_lookup(abfd));
if (nread > 0)
abfd->where += nread;
if (nread < (int) (size))
{
if (ferror (bfd_cache_lookup (abfd)))
bfd_set_error (bfd_error_system_call);
else
bfd_set_error (bfd_error_file_truncated);
}
return nread;
}
}
bfd_size_type
bfd_bwrite (ptr, size, abfd)
CONST PTR ptr;
bfd_size_type size;
bfd *abfd;
{
while (abfd->my_archive != NULL)
abfd = abfd->my_archive;
if (abfd->flags & BFD_IN_MEMORY)
{
struct bfd_in_memory *bim = (struct bfd_in_memory *) (abfd->iostream);
if (abfd->where + size > bim->size)
{
long newsize, oldsize = (bim->size + 127) & ~127;
bim->size = abfd->where + size;
newsize = (bim->size + 127) & ~127;
if (newsize > oldsize)
{
bim->buffer = bfd_realloc (bim->buffer, newsize);
if (bim->buffer == 0)
{
bim->size = 0;
return 0;
}
}
}
}
else if ((abfd->flags & BFD_IO_FUNCS) != 0)
{
struct bfd_io_functions *bif;
bif = (struct bfd_io_functions *) abfd->iostream;
return (*bif->write_func) (bif->iodata, ptr, 1, size, abfd, abfd->where);
}
else
{
long nwrote;
nwrote = fwrite (ptr, 1, (size_t) (size),
bfd_cache_lookup (abfd));
if (nwrote > 0)
abfd->where += nwrote;
if ((bfd_size_type) nwrote != size)
{
#ifdef ENOSPC
if (nwrote >= 0)
errno = ENOSPC;
#endif
bfd_set_error (bfd_error_system_call);
}
return nwrote;
}
}
bfd_size_type
bfd_tell (abfd)
bfd *abfd;
{
file_ptr ptr = 0;
bfd *cur = abfd;
while (cur->my_archive) {
ptr -= cur->origin;
cur = cur->my_archive;
}
if ((cur->flags & BFD_IN_MEMORY) != 0)
{
ptr += cur->where;
}
else if ((abfd->flags & BFD_IO_FUNCS) != 0)
{
ptr += cur->where;
}
else
{
cur->where = ftell (bfd_cache_lookup (cur));
ptr += cur->where;
}
return ptr;
}
int
bfd_flush (abfd)
bfd *abfd;
{
while (abfd->my_archive)
abfd = abfd->my_archive;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
{
return 0;
}
else if ((abfd->flags & BFD_IO_FUNCS) != 0)
{
struct bfd_io_functions *bif;
bif = (struct bfd_io_functions *) abfd->iostream;
return (*bif->flush_func) (bif->iodata, abfd);
}
else
{
return fflush (bfd_cache_lookup (abfd));
}
}
int
bfd_stat (abfd, statbuf)
bfd *abfd;
struct stat *statbuf;
{
FILE *f;
int result;
while (abfd->my_archive)
abfd = abfd->my_archive;
if ((abfd->flags & BFD_IN_MEMORY) != 0)
{
BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) == 0);
return -1;
}
else if ((abfd->flags & BFD_IO_FUNCS) != 0)
{
BFD_ASSERT ((abfd->flags & BFD_IO_FUNCS) == 0);
return -1;
}
else
{
f = bfd_cache_lookup (abfd);
if (f == NULL)
{
bfd_set_error (bfd_error_system_call);
return -1;
}
result = fstat (fileno (f), statbuf);
if (result < 0)
bfd_set_error (bfd_error_system_call);
return result;
}
}
int
bfd_seek (abfd, position, direction)
bfd *abfd;
file_ptr position;
int direction;
{
BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
if (direction == SEEK_CUR && position == 0)
return 0;
while (abfd->my_archive != NULL)
{
if (direction == SEEK_SET)
position += abfd->origin;
abfd = abfd->my_archive;
}
if (direction == SEEK_SET && position == abfd->where)
return 0;
if ((position < 0) && (direction != SEEK_CUR)) {
bfd_set_error (bfd_error_system_call);
return -1;
}
if (((abfd->flags & BFD_IN_MEMORY) != 0)
|| (abfd->flags & BFD_IO_FUNCS) != 0)
{
if (direction == SEEK_SET) {
abfd->where = position;
} else {
abfd->where += position;
}
return 0;
}
else
{
int result;
BFD_ASSERT (ftell (bfd_cache_lookup (abfd)) == abfd->where);
result = fseek (bfd_cache_lookup (abfd), position, direction);
if (result != 0)
{
bfd_tell (abfd);
bfd_set_error (bfd_error_system_call);
}
else
{
if (direction == SEEK_SET)
abfd->where = position;
else
abfd->where += position;
}
return result;
}
}
boolean
bfd_io_close (abfd)
bfd *abfd;
{
if (abfd->flags & BFD_IN_MEMORY)
{
int ret = 0;
struct bfd_in_memory *b = (struct bfd_in_memory *) abfd->iostream;
BFD_ASSERT (b != NULL);
#if 0
ret = munmap (b->buffer, b->size);
#endif
abfd->iostream = NULL;
BFD_ASSERT (ret == 0);
return true;
}
else if (abfd->flags & BFD_IO_FUNCS)
{
struct bfd_io_functions *bif;
bif = (struct bfd_io_functions *) abfd->iostream;
return (*bif->close_func) (bif->iodata, abfd);
}
else
{
boolean ret = true;
ret = bfd_cache_close (abfd);
if (ret
&& abfd->direction == write_direction
&& abfd->flags & EXEC_P)
{
struct stat buf;
if (stat (abfd->filename, &buf) == 0)
{
int mask = umask (0);
umask (mask);
chmod (abfd->filename,
(0x777
& (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask))));
}
}
}
}
long
bfd_get_mtime (abfd)
bfd *abfd;
{
while (abfd->my_archive)
abfd = abfd->my_archive;
if (abfd->flags & BFD_IO_FUNCS)
{
return 0;
}
else
{
FILE *fp;
struct stat buf;
fp = bfd_cache_lookup_null (abfd);
if (fp == NULL)
return 0;
if (0 != fstat (fileno (fp), &buf))
return 0;
abfd->mtime = buf.st_mtime;
return abfd->mtime;
}
}
long
bfd_get_size (abfd)
bfd *abfd;
{
while (abfd->my_archive)
abfd = abfd->my_archive;
if (abfd->flags & BFD_IN_MEMORY)
{
return ((struct bfd_in_memory *) abfd->iostream)->size;
}
else if (abfd->flags & BFD_IO_FUNCS)
{
return LONG_MAX;
}
else
{
FILE *fp;
struct stat buf;
fp = bfd_cache_lookup (abfd);
if (0 != fstat (fileno (fp), &buf))
return 0;
return buf.st_size;
}
}