mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-08 04:29:46 +00:00
242 lines
5.6 KiB
C++
242 lines
5.6 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h> // for close();
|
|
|
|
#include "util.h"
|
|
#include "Data_window.h"
|
|
#include "debug.h"
|
|
|
|
enum
|
|
{
|
|
MINBUFSIZE = 1 << 16,
|
|
WIN_ALIGN = 8
|
|
};
|
|
|
|
Data_window::Data_window (char *file_name)
|
|
{
|
|
Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:%d %s\n"), (int) __LINE__, STR (file_name));
|
|
page_size = sysconf (_SC_PAGESIZE);
|
|
need_swap_endian = false;
|
|
opened = false;
|
|
fsize = 0;
|
|
base = NULL;
|
|
woffset = 0;
|
|
wsize = 0;
|
|
basesize = 0;
|
|
fname = dbe_strdup (file_name);
|
|
mmap_on_file = false;
|
|
use_mmap = false;
|
|
#if DEBUG
|
|
if (DBE_USE_MMAP)
|
|
use_mmap = true;
|
|
#endif /* DEBUG */
|
|
fd = open64 (fname, O_RDONLY);
|
|
if (fd == -1)
|
|
return;
|
|
fsize = lseek (fd, 0, SEEK_END);
|
|
if (fsize == 0)
|
|
{
|
|
close (fd);
|
|
fd = -1;
|
|
return;
|
|
}
|
|
opened = true;
|
|
if (use_mmap)
|
|
{
|
|
if (fsize != -1)
|
|
{
|
|
base = (void*) mmap (NULL, (size_t) fsize, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
close (fd);
|
|
fd = -1;
|
|
if (base == MAP_FAILED)
|
|
{
|
|
base = NULL;
|
|
use_mmap = false;
|
|
return;
|
|
}
|
|
mmap_on_file = true;
|
|
wsize = fsize;
|
|
}
|
|
}
|
|
}
|
|
|
|
void *
|
|
Data_window::bind (int64_t file_offset, int64_t minSize)
|
|
{
|
|
Span span;
|
|
span.length = fsize - file_offset;
|
|
span.offset = file_offset;
|
|
return bind (&span, minSize);
|
|
}
|
|
|
|
void *
|
|
Data_window::bind (Span *span, int64_t minSize)
|
|
{
|
|
// Do any necessary mapping to access the desired span of data
|
|
// and return a pointer to the first byte.
|
|
Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:bind:%d offset=%llx:%lld minSize=%lld \n"),
|
|
(int) __LINE__, (long long) span->offset, (long long) span->length, (long long) minSize);
|
|
if (minSize == 0 || span->length < minSize)
|
|
return NULL;
|
|
|
|
if (span->offset < woffset || span->offset + minSize > woffset + wsize)
|
|
{
|
|
// Remap the window
|
|
if (span->offset + minSize > fsize)
|
|
return NULL;
|
|
int myfd = fd;
|
|
if (myfd == -1)
|
|
{
|
|
if (fname)
|
|
myfd = open64 (fname, O_RDONLY, 0);
|
|
if (myfd == -1)
|
|
return NULL;
|
|
}
|
|
bool remap_failed = true;
|
|
if (use_mmap)
|
|
{
|
|
if (base)
|
|
{
|
|
munmap ((caddr_t) base, (size_t) wsize);
|
|
base = NULL;
|
|
}
|
|
woffset = span->offset & ~(page_size - 1);
|
|
wsize = page_size * ((MINBUFSIZE + page_size - 1) / page_size);
|
|
if (span->offset + minSize > woffset + wsize)
|
|
// Extend a window
|
|
wsize += page_size * ((span->offset + minSize -
|
|
woffset - wsize + page_size - 1) / page_size);
|
|
base = (void *) mmap (0, (size_t) wsize, PROT_READ, MAP_SHARED, fd, woffset);
|
|
if (base == MAP_FAILED)
|
|
{
|
|
base = NULL;
|
|
use_mmap = false;
|
|
}
|
|
remap_failed = (base == NULL);
|
|
}
|
|
if (remap_failed)
|
|
{
|
|
remap_failed = false;
|
|
woffset = span->offset & ~(WIN_ALIGN - 1);
|
|
wsize = minSize + (span->offset % WIN_ALIGN);
|
|
if (wsize < MINBUFSIZE)
|
|
wsize = MINBUFSIZE;
|
|
if (wsize > fsize)
|
|
wsize = fsize;
|
|
if (basesize < wsize)
|
|
{ // Need to realloc 'base'
|
|
free (base);
|
|
basesize = wsize;
|
|
base = (void *) malloc (basesize);
|
|
Dprintf (DEBUG_DATA_WINDOW,
|
|
NTXT ("Data_window:bind:%d realloc basesize=%llx woffset=%lld \n"),
|
|
(int) __LINE__, (long long) basesize, (long long) woffset);
|
|
if (base == NULL)
|
|
{
|
|
basesize = 0;
|
|
remap_failed = true;
|
|
}
|
|
}
|
|
if (wsize > fsize - woffset)
|
|
wsize = fsize - woffset;
|
|
off_t woff = (off_t) woffset;
|
|
if (base == NULL || woff != lseek (myfd, woff, SEEK_SET)
|
|
|| wsize != read_from_file (myfd, base, wsize))
|
|
remap_failed = true;
|
|
}
|
|
if (fd == -1)
|
|
close (myfd);
|
|
if (remap_failed)
|
|
{
|
|
woffset = 0;
|
|
wsize = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
return (void *) ((char*) base + span->offset - woffset);
|
|
}
|
|
|
|
void *
|
|
Data_window::get_data (int64_t offset, int64_t size, void *datap)
|
|
{
|
|
if (size <= 0)
|
|
return NULL;
|
|
void *buf = bind (offset, size);
|
|
if (buf == NULL)
|
|
return NULL;
|
|
if (datap == NULL && !mmap_on_file)
|
|
// Can be remmaped or reallocated. Need to make a copy
|
|
datap = (void *) malloc (size);
|
|
if (datap)
|
|
{
|
|
memcpy (datap, buf, (size_t) size);
|
|
return datap;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
Data_window::~Data_window ()
|
|
{
|
|
free (fname);
|
|
if (fd != -1)
|
|
close (fd);
|
|
if (base)
|
|
{
|
|
if (use_mmap)
|
|
munmap ((caddr_t) base, (size_t) wsize);
|
|
else
|
|
free (base);
|
|
}
|
|
}
|
|
|
|
int64_t
|
|
Data_window::get_buf_size ()
|
|
{
|
|
int64_t sz = MINBUFSIZE;
|
|
if (sz < basesize)
|
|
sz = basesize;
|
|
if (sz > fsize)
|
|
sz = fsize;
|
|
return sz;
|
|
}
|
|
|
|
int64_t
|
|
Data_window::copy_to_file (int f, int64_t offset, int64_t size)
|
|
{
|
|
long long bsz = get_buf_size ();
|
|
for (long long n = 0; n < size;)
|
|
{
|
|
long long sz = (bsz <= (size - n)) ? bsz : (size - n);
|
|
void *b = bind (offset + n, sz);
|
|
if (b == NULL)
|
|
return n;
|
|
long long len = write (f, b, sz);
|
|
if (len <= 0)
|
|
return n;
|
|
n += len;
|
|
}
|
|
return size;
|
|
}
|