Skip to content

Commit f1960dc

Browse files
jktjktmichalvasko
authored andcommitted
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
1 parent ec54cb7 commit f1960dc

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

CMakeModules/UseCompat.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ macro(USE_COMPAT)
5454
check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH)
5555
check_symbol_exists(localtime_r "time.h" HAVE_LOCALTIME_R)
5656
check_symbol_exists(strptime "time.h" HAVE_STRPTIME)
57+
check_symbol_exists(mmap "sys/mman.h" HAVE_MMAP)
5758

5859
unset(CMAKE_REQUIRED_DEFINITIONS)
5960
unset(CMAKE_REQUIRED_LIBRARIES)

compat/compat.h.in

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#cmakedefine HAVE_REALPATH
6565
#cmakedefine HAVE_LOCALTIME_R
6666
#cmakedefine HAVE_STRPTIME
67+
#cmakedefine HAVE_MMAP
6768

6869
#ifndef bswap64
6970
#define bswap64(val) \

src/common.c

+68
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#include <stdio.h>
2525
#include <stdlib.h>
2626
#include <string.h>
27+
#ifndef _WIN32
2728
#include <sys/mman.h>
29+
#endif
2830
#include <sys/stat.h>
2931
#include <unistd.h>
3032

@@ -346,6 +348,7 @@ LY_VCODE_INSTREXP_len(const char *str)
346348
return len;
347349
}
348350

351+
#ifdef HAVE_MMAP
349352
LY_ERR
350353
ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
351354
{
@@ -404,6 +407,71 @@ ly_munmap(void *addr, size_t length)
404407
return LY_SUCCESS;
405408
}
406409

410+
#else
411+
412+
LY_ERR
413+
ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
414+
{
415+
struct stat sb;
416+
size_t m;
417+
418+
assert(length);
419+
assert(addr);
420+
assert(fd >= 0);
421+
422+
if (fstat(fd, &sb) == -1) {
423+
LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
424+
return LY_ESYS;
425+
}
426+
if (!S_ISREG(sb.st_mode)) {
427+
LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
428+
return LY_ESYS;
429+
}
430+
if (!sb.st_size) {
431+
*addr = NULL;
432+
return LY_SUCCESS;
433+
}
434+
/* On Windows, the mman-win32 mmap() emulation uses CreateFileMapping and MapViewOfFile, and these functions
435+
* do not allow mapping more than "length of file" bytes for PROT_READ. Remapping existing mappings is not allowed, either.
436+
* At that point the path of least resistance is just reading the file in as-is. */
437+
m = sb.st_size + 1;
438+
char *buf = calloc(m, 1);
439+
440+
if (!buf) {
441+
LOGERR(ctx, LY_ESYS, "ly_mmap: malloc() failed (%s).", strerror(errno));
442+
}
443+
*addr = buf;
444+
*length = m;
445+
446+
lseek(fd, 0, SEEK_SET);
447+
ssize_t to_read = m - 1;
448+
449+
while (to_read > 0) {
450+
ssize_t n = read(fd, buf, to_read);
451+
if (n == 0) {
452+
return LY_SUCCESS;
453+
} else if (n < 0) {
454+
if (errno == EINTR) {
455+
continue; // can I get this on Windows?
456+
}
457+
LOGERR(ctx, LY_ESYS, "ly_mmap: read() failed (%s).", strerror(errno));
458+
}
459+
to_read -= n;
460+
buf += n;
461+
}
462+
return LY_SUCCESS;
463+
}
464+
465+
LY_ERR
466+
ly_munmap(void *addr, size_t length)
467+
{
468+
(void)length;
469+
free(addr);
470+
return LY_SUCCESS;
471+
}
472+
473+
#endif
474+
407475
LY_ERR
408476
ly_strcat(char **dest, const char *format, ...)
409477
{

0 commit comments

Comments
 (0)