MSVC: there's no mmap() on Windows
There's a compatibility library, the mman-win32, which implement a
mmap-like semantics. However, on Windows one cannot map a read-only file
into memory for a length that is larger than the size of that file,
and you also cannot overwrite an existing mapping.
The easiest course of action is to just read the file into memory and be
done with it.
See-also: https://stackoverflow.com/a/46014637/2245623
diff --git a/CMakeModules/UseCompat.cmake b/CMakeModules/UseCompat.cmake
index ac330e5..753b10d 100644
--- a/CMakeModules/UseCompat.cmake
+++ b/CMakeModules/UseCompat.cmake
@@ -54,6 +54,7 @@
check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH)
check_symbol_exists(localtime_r "time.h" HAVE_LOCALTIME_R)
check_symbol_exists(strptime "time.h" HAVE_STRPTIME)
+ check_symbol_exists(mmap "sys/mman.h" HAVE_MMAP)
unset(CMAKE_REQUIRED_DEFINITIONS)
unset(CMAKE_REQUIRED_LIBRARIES)
diff --git a/compat/compat.h.in b/compat/compat.h.in
index f8be220..6672fcf 100644
--- a/compat/compat.h.in
+++ b/compat/compat.h.in
@@ -64,6 +64,7 @@
#cmakedefine HAVE_REALPATH
#cmakedefine HAVE_LOCALTIME_R
#cmakedefine HAVE_STRPTIME
+#cmakedefine HAVE_MMAP
#ifndef bswap64
#define bswap64(val) \
diff --git a/src/common.c b/src/common.c
index fa27588..41e5270 100644
--- a/src/common.c
+++ b/src/common.c
@@ -24,7 +24,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifndef _WIN32
#include <sys/mman.h>
+#endif
#include <sys/stat.h>
#include <unistd.h>
@@ -346,6 +348,7 @@
return len;
}
+#ifdef HAVE_MMAP
LY_ERR
ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
{
@@ -404,6 +407,71 @@
return LY_SUCCESS;
}
+#else
+
+LY_ERR
+ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
+{
+ struct stat sb;
+ size_t m;
+
+ assert(length);
+ assert(addr);
+ assert(fd >= 0);
+
+ if (fstat(fd, &sb) == -1) {
+ LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
+ return LY_ESYS;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
+ return LY_ESYS;
+ }
+ if (!sb.st_size) {
+ *addr = NULL;
+ return LY_SUCCESS;
+ }
+ /* On Windows, the mman-win32 mmap() emulation uses CreateFileMapping and MapViewOfFile, and these functions
+ * do not allow mapping more than "length of file" bytes for PROT_READ. Remapping existing mappings is not allowed, either.
+ * At that point the path of least resistance is just reading the file in as-is. */
+ m = sb.st_size + 1;
+ char *buf = calloc(m, 1);
+
+ if (!buf) {
+ LOGERR(ctx, LY_ESYS, "ly_mmap: malloc() failed (%s).", strerror(errno));
+ }
+ *addr = buf;
+ *length = m;
+
+ lseek(fd, 0, SEEK_SET);
+ ssize_t to_read = m - 1;
+
+ while (to_read > 0) {
+ ssize_t n = read(fd, buf, to_read);
+ if (n == 0) {
+ return LY_SUCCESS;
+ } else if (n < 0) {
+ if (errno == EINTR) {
+ continue; // can I get this on Windows?
+ }
+ LOGERR(ctx, LY_ESYS, "ly_mmap: read() failed (%s).", strerror(errno));
+ }
+ to_read -= n;
+ buf += n;
+ }
+ return LY_SUCCESS;
+}
+
+LY_ERR
+ly_munmap(void *addr, size_t length)
+{
+ (void)length;
+ free(addr);
+ return LY_SUCCESS;
+}
+
+#endif
+
LY_ERR
ly_strcat(char **dest, const char *format, ...)
{