]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/mman/mman.c
575a49578ce830358e7b9f9efc5491ae7ca61907
[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 // Check for integer overflow.
62 size_t buf_len = 0;
63 if(__builtin_add_overflow(length, sizeof(struct map), &buf_len)) {
64 errno = EINVAL;
65 return MAP_FAILED;
66 }
67
68 // Allocate the memory.
69 struct map *map = malloc(buf_len);
70 if (!map) {
71 errno = ENOMEM;
72 return MAP_FAILED;
73 }
74
75 // Initialize the header.
76 map->prot = prot;
77 map->flags = flags;
78 map->offset = offset;
79 map->length = length;
80
81 // Initialize the main memory buffer, either with the contents of a file,
82 // or with zeros.
83 if ((flags & MAP_ANON) == 0) {
84 char *body = map->body;
85 while (length > 0) {
86 const ssize_t nread = pread(fd, body, length, offset);
87 if (nread < 0) {
88 if (errno == EINTR)
89 continue;
90 return MAP_FAILED;
91 }
92 if (nread == 0)
93 break;
94 length -= (size_t)nread;
95 offset += (size_t)nread;
96 body += (size_t)nread;
97 }
98 } else {
99 memset(map->body, 0, length);
100 }
101
102 return map->body;
103 }
104
105 int munmap(void *addr, size_t length) {
106 struct map *map = (struct map *)addr - 1;
107
108 // We don't support partial munmapping.
109 if (map->length != length) {
110 errno = EINVAL;
111 return -1;
112 }
113
114 // Release the memory.
115 free(map);
116
117 // Success!
118 return 0;
119 }