Bring back MMAP support

Will be used where available for files up to 256MB
This commit is contained in:
Bernhard Schelling 2020-07-14 03:04:01 +09:00
parent c05f1e91fc
commit 32dcff3880
3 changed files with 110 additions and 37 deletions

View File

@ -32,6 +32,14 @@
#include <lists/string_list.h>
#include <string/stdstring.h>
#ifdef HAVE_MMAP
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#endif
static int file_archive_get_file_list_cb(
const char *path,
const char *valid_exts,
@ -159,6 +167,25 @@ static int file_archive_parse_file_init(file_archive_transfer_t *state,
state->archive_size = filestream_get_size(state->archive_file);
#ifdef HAVE_MMAP
if (state->archive_size <= (256*1024*1024))
{
state->archive_mmap_fd = open(path, O_RDONLY);
if (state->archive_mmap_fd)
{
state->archive_mmap_data = (uint8_t*)mmap(NULL, (size_t)state->archive_size,
PROT_READ, MAP_SHARED, state->archive_mmap_fd, 0);
if (state->archive_mmap_data == (uint8_t*)MAP_FAILED)
{
close(state->archive_mmap_fd);
state->archive_mmap_fd = 0;
state->archive_mmap_data = NULL;
}
}
}
#endif
state->step_current = 0;
state->step_total = 0;
@ -273,6 +300,16 @@ int file_archive_parse_file_iterate(
state->archive_file = NULL;
}
#ifdef HAVE_MMAP
if (state->archive_mmap_data)
{
munmap(state->archive_mmap_data, (size_t)state->archive_size);
close(state->archive_mmap_fd);
state->archive_mmap_fd = 0;
state->archive_mmap_data = NULL;
}
#endif
if (userdata)
userdata->transfer = NULL;
break;
@ -302,15 +339,19 @@ static bool file_archive_walk(const char *file, const char *valid_exts,
file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
{
file_archive_transfer_t state;
bool returnerr = true;
bool returnerr = true;
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_file = NULL;
state.archive_size = 0;
state.context = NULL;
state.step_total = 0;
state.step_current = 0;
state.backend = NULL;
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_file = NULL;
#ifdef HAVE_MMAP
state.archive_mmap_fd = 0;
state.archive_mmap_data = NULL;
#endif
state.archive_size = 0;
state.context = NULL;
state.step_total = 0;
state.step_current = 0;
state.backend = NULL;
for (;;)
{
@ -640,13 +681,17 @@ uint32_t file_archive_get_file_crc32(const char *path)
archive_path += 1;
}
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_file = NULL;
state.archive_size = 0;
state.context = NULL;
state.step_total = 0;
state.step_current = 0;
state.backend = NULL;
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_file = NULL;
#ifdef HAVE_MMAP
state.archive_mmap_fd = 0;
state.archive_mmap_data = NULL;
#endif
state.archive_size = 0;
state.context = NULL;
state.step_total = 0;
state.step_current = 0;
state.backend = NULL;
/* Initialize and open archive first.
Sets next state type to ITERATE. */

View File

@ -49,7 +49,7 @@ enum file_archive_compression_mode
typedef struct
{
RFILE *file;
struct file_archive_transfer *state;
uint8_t *directory;
uint8_t *directory_entry;
uint8_t *directory_end;
@ -80,8 +80,13 @@ static void zip_context_free_stream(
}
if (zip_context->compressed_data)
{
free(zip_context->compressed_data);
zip_context->compressed_data = NULL;
#ifdef HAVE_MMAP
if (!zip_context->state->archive_mmap_data)
#endif
{
free(zip_context->compressed_data);
zip_context->compressed_data = NULL;
}
}
if (zip_context->decompressed_data && !keep_decompressed)
{
@ -95,38 +100,57 @@ static bool zlib_stream_decompress_data_to_file_init(
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
zip_context_t *zip_context = (zip_context_t *)context;
struct file_archive_transfer *state = zip_context->state;
uint8_t local_header_buf[4];
uint8_t *local_header;
uint32_t offsetNL, offsetEL;
int64_t offsetData;
/* free previous stream if left unfinished */
/* free previous data and stream if left unfinished */
zip_context_free_stream(zip_context, false);
/* allocate memory for the compressed data */
zip_context->compressed_data = (uint8_t*)malloc(csize);
if (!zip_context->compressed_data)
goto error;
/* seek past most of the local directory header */
filestream_seek(zip_context->file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(zip_context->file, local_header_buf, 4) != 4)
goto error;
#ifdef HAVE_MMAP
if (state->archive_mmap_data)
{
local_header = state->archive_mmap_data + (size_t)cdata + 26;
}
else
#endif
{
filestream_seek(state->archive_file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, local_header_buf, 4) != 4)
goto error;
local_header = local_header_buf;
}
offsetNL = read_le(local_header_buf, 2); /* file name length */
offsetEL = read_le(local_header_buf + 2, 2); /* extra field length */
offsetNL = read_le(local_header, 2); /* file name length */
offsetEL = read_le(local_header + 2, 2); /* extra field length */
offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;
/* skip over name and extra data */
filestream_seek(zip_context->file, offsetData, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(zip_context->file, zip_context->compressed_data, csize) != csize)
goto error;
#ifdef HAVE_MMAP
if (state->archive_mmap_data)
{
zip_context->compressed_data = state->archive_mmap_data + (size_t)offsetData;
}
else
#endif
{
/* allocate memory for the compressed data */
zip_context->compressed_data = (uint8_t*)malloc(csize);
if (!zip_context->compressed_data)
goto error;
/* skip over name and extra data */
filestream_seek(state->archive_file, offsetData, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, zip_context->compressed_data, csize) != csize)
goto error;
}
switch (cmode)
{
case ZIP_MODE_STORED:
zip_context->decompressed_data = zip_context->compressed_data;
zip_context->compressed_data = NULL;
handle->data = zip_context->decompressed_data;
handle->data = zip_context->compressed_data;
return true;
case ZIP_MODE_DEFLATED:
@ -397,7 +421,7 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
* context and the entire directory, then read the directory.
*/
zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
zip_context->file = state->archive_file;
zip_context->state = state;
zip_context->directory = (uint8_t*)(zip_context + 1);
zip_context->directory_entry = zip_context->directory;
zip_context->directory_end = zip_context->directory + (size_t)directory_size;

View File

@ -58,6 +58,10 @@ typedef struct file_archive_transfer
{
enum file_archive_transfer_type type;
struct RFILE *archive_file;
#ifdef HAVE_MMAP
int archive_mmap_fd;
uint8_t *archive_mmap_data;
#endif
int64_t archive_size;
void *context;
unsigned step_total, step_current;