]> git.proxmox.com Git - wasi-libc.git/blame - libc-bottom-half/mman/mman.c
bump version to 0.0~git20240411.9e8c542-3~bpo12+pve1
[wasi-libc.git] / libc-bottom-half / mman / mman.c
CommitLineData
ca9046d8
DG
1// Userspace emulation of mmap and munmap. Restrictions apply.
2//
3// This is meant to be complete enough to be compatible with code that uses
4// mmap for simple file I/O. It just allocates memory with malloc and reads
5// and writes data with pread and pwrite.
320054e8
DG
6
7#define _WASI_EMULATED_MMAN
8#include <stdlib.h>
9#include <errno.h>
10#include <unistd.h>
11#include <string.h>
12#include <sys/mman.h>
13#include <sys/types.h>
14
15struct map {
16 int prot;
17 int flags;
18 off_t offset;
19 size_t length;
320054e8
DG
20};
21
22void *mmap(void *addr, size_t length, int prot, int flags,
23 int fd, off_t offset) {
24 // Check for unsupported flags.
3e9892fc 25 if ((flags & (MAP_PRIVATE | MAP_SHARED)) == 0 ||
26 (flags & MAP_FIXED) != 0 ||
320054e8 27#ifdef MAP_SHARED_VALIDATE
3e9892fc 28 (flags & MAP_SHARED_VALIDATE) == MAP_SHARED_VALIDATE ||
320054e8
DG
29#endif
30#ifdef MAP_NORESERVE
31 (flags & MAP_NORESERVE) != 0 ||
32#endif
33#ifdef MAP_GROWSDOWN
34 (flags & MAP_GROWSDOWN) != 0 ||
35#endif
36#ifdef MAP_HUGETLB
37 (flags & MAP_HUGETLB) != 0 ||
38#endif
39#ifdef MAP_FIXED_NOREPLACE
40 (flags & MAP_FIXED_NOREPLACE) != 0 ||
41#endif
42 0)
43 {
44 errno = EINVAL;
45 return MAP_FAILED;
46 }
47
48 // Check for unsupported protection requests.
49 if (prot == PROT_NONE ||
50#ifdef PROT_EXEC
51 (prot & PROT_EXEC) != 0 ||
52#endif
53 0)
54 {
55 errno = EINVAL;
56 return MAP_FAILED;
57 }
58
d987aad4 59 // To be consistent with POSIX.
60 if (length == 0) {
61 errno = EINVAL;
62 return MAP_FAILED;
63 }
64
4a8d1c7c 65 // Check for integer overflow.
30e5a1fd 66 size_t buf_len = 0;
d987aad4 67 if (__builtin_add_overflow(length, sizeof(struct map), &buf_len)) {
68 errno = ENOMEM;
20c48b57 69 return MAP_FAILED;
70 }
71
320054e8 72 // Allocate the memory.
ccfe4bda 73 struct map *map = malloc(buf_len);
320054e8
DG
74 if (!map) {
75 errno = ENOMEM;
76 return MAP_FAILED;
77 }
78
79 // Initialize the header.
80 map->prot = prot;
81 map->flags = flags;
82 map->offset = offset;
83 map->length = length;
84
85 // Initialize the main memory buffer, either with the contents of a file,
86 // or with zeros.
9b9d243b 87 addr = map + 1;
320054e8 88 if ((flags & MAP_ANON) == 0) {
9b9d243b 89 char *body = (char *)addr;
320054e8 90 while (length > 0) {
20c48b57 91 const ssize_t nread = pread(fd, body, length, offset);
320054e8
DG
92 if (nread < 0) {
93 if (errno == EINTR)
94 continue;
95 return MAP_FAILED;
96 }
97 if (nread == 0)
98 break;
99 length -= (size_t)nread;
100 offset += (size_t)nread;
101 body += (size_t)nread;
102 }
103 } else {
9b9d243b 104 memset(addr, 0, length);
320054e8
DG
105 }
106
9b9d243b 107 return addr;
320054e8
DG
108}
109
110int munmap(void *addr, size_t length) {
111 struct map *map = (struct map *)addr - 1;
ca9046d8 112
320054e8
DG
113 // We don't support partial munmapping.
114 if (map->length != length) {
115 errno = EINVAL;
116 return -1;
117 }
118
119 // Release the memory.
120 free(map);
121
122 // Success!
123 return 0;
124}