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