From 95cfa2f6fad18fc14fadd3d03c26dbe42c5d47ad Mon Sep 17 00:00:00 2001 From: Baudouin Raoult Date: Mon, 2 Nov 2020 11:42:00 +0000 Subject: [PATCH] Support for MEMFS on older Linux --- src/memfs.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 src/memfs.c diff --git a/src/memfs.c b/src/memfs.c new file mode 100644 index 000000000..21ea1ad49 --- /dev/null +++ b/src/memfs.c @@ -0,0 +1,201 @@ +/* + * (C) Copyright 2005- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * + * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by + * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. + */ + + +#include "eccodes_config.h" +#ifdef ECCODES_HAVE_FMEMOPEN +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include "eccodes_windef.h" + +struct entry { + const char* path; + const unsigned char* content; + size_t length; +}; + +/* The code will be added below: */ +/* Start generated code */ +/* */ +/* End generated code */ + +#if !defined(ECCODES_HAVE_FMEMOPEN) + +#if defined(ECCODES_HAVE_FUNOPEN) +typedef struct mem_file { + const char* buffer; + size_t size; + size_t pos; +} mem_file; + +static int read_mem(void *data, char * buf, int len) { + mem_file* f = (mem_file*)data; + int n = len; + + if(f->pos + n > f->size) { + n = f->size - f->pos; + } + + memcpy(buf, f->buffer + f->pos, n); + + f->pos += n; + return n; +} + +static int write_mem(void* data, const char* buf, int len) { + mem_file* f = (mem_file*)data; + return -1; +} + +static fpos_t seek_mem(void *data, fpos_t pos, int whence) { + mem_file* f = (mem_file*)data; + long newpos = 0; + + switch (whence) { + case SEEK_SET: + newpos = (long)pos; + break; + + case SEEK_CUR: + newpos = (long)f->pos + (long)pos; + break; + + case SEEK_END: + newpos = (long)f->size - (long)pos; + break; + + default: + return -1; + break; + } + + if(newpos < 0) { newpos = 0; } + if(newpos > f->size) { newpos = f->size; } + + f->pos = newpos; + return newpos; +} + +static int close_mem(void *data) { + mem_file* f = (mem_file*)data; + free(f); + return 0; +} + +static FILE* fmemopen(const char* buffer, size_t size, const char* mode){ + mem_file* f = (mem_file*)calloc(sizeof(mem_file), 1); + if(!f) return NULL; + + f->buffer = buffer; + f->size = size; + + return funopen(f, &read_mem, &write_mem, &seek_mem, &close_mem); +} + +#else /* defined(ECCODES_HAVE_FUNOPEN) */ + +#if defined(ECCODES_ON_WINDOWS) + +#include +#include +#include + +static FILE *fmemopen(void* buffer, size_t size, const char* mode) { + char path[MAX_PATH - 13]; + if (!GetTempPath(sizeof(path), path)) + return NULL; + + char filename[MAX_PATH + 1]; + if (!GetTempFileName(path, "eccodes", 0, filename)) + return NULL; + + HANDLE h = CreateFile(filename, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if (h == INVALID_HANDLE_VALUE) + return NULL; + + int fd = _open_osfhandle((intptr_t)h, _O_RDWR); + if (fd < 0) { + CloseHandle(h); + return NULL; + } + + FILE* f = _fdopen(fd, "w+"); + if (!f) { + _close(fd); + return NULL; + } + + fwrite(buffer, size, 1, f); + rewind(f); + return f; +} + +#else /* defined(ECCODES_ON_WINDOWS) */ +#include +/* On old unix systems */ + +static FILE *fmemopen(void* buffer, size_t size, const char* mode) { + + FILE* f = tmpfile(); + if (!f) { + return NULL; + } + + fwrite(buffer, size, 1, f); + rewind(f); + return f; +} + +#endif /* defined(ECCODES_ON_WINDOWS) */ + +#endif /* defined(ECCODES_HAVE_FUNOPEN) */ +#endif /* !defined(ECCODES_HAVE_FMEMOPEN) */ + +static size_t entries_count = sizeof(entries)/sizeof(entries[0]); + +static const unsigned char* find(const char* path, size_t* length) { + size_t i; + + for(i = 0; i < entries_count; i++) { + if(strcmp(path, entries[i].path) == 0) { + /*printf("Found in MEMFS %s\\n", path);*/ + *length = entries[i].length; + return entries[i].content; + } + } + + return NULL; +} + +int codes_memfs_exists(const char* path) { + size_t dummy; + return find(path, &dummy) != NULL; +} + +FILE* codes_memfs_open(const char* path) { + size_t size; + const unsigned char* mem = find(path, &size); + if(!mem) { + return NULL; + } + return fmemopen((void*)mem, size, "r"); +}