1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <sys/mman.h> 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <string.h> 12 13 #include <OS.h> 14 15 #include <syscall_utils.h> 16 #include <syscalls.h> 17 #include <vm_defs.h> 18 19 20 static const char* kSharedMemoryDir = "/var/shared_memory/"; 21 22 23 static bool 24 append_string(char*& path, size_t& bytesLeft, const char* toAppend, size_t size) 25 { 26 if (bytesLeft <= size) 27 return false; 28 29 memcpy(path, toAppend, size); 30 path += size; 31 path[0] = '\0'; 32 bytesLeft -= size; 33 34 return true; 35 } 36 37 38 static bool 39 append_string(char*& path, size_t& bytesLeft, const char* toAppend) 40 { 41 return append_string(path, bytesLeft, toAppend, strlen(toAppend)); 42 } 43 44 45 static status_t 46 shm_name_to_path(const char* name, char* path, size_t pathSize) 47 { 48 if (name == NULL) 49 return B_BAD_VALUE; 50 51 // skip leading slashes 52 while (*name == '/') 53 name++; 54 55 if (*name == '\0') 56 return B_BAD_VALUE; 57 58 // create the path; replace occurrences of '/' by "%s" and '%' by "%%" 59 if (!append_string(path, pathSize, kSharedMemoryDir)) 60 return ENAMETOOLONG; 61 62 while (const char* found = strpbrk(name, "%/")) { 63 // append section that doesn't need escaping 64 if (found != name) { 65 if (!append_string(path, pathSize, name, found - name)) 66 return ENAMETOOLONG; 67 } 68 69 // append escaped char 70 const char* append = (*found == '%' ? "%%" : "%s"); 71 if (!append_string(path, pathSize, append, 2)) 72 return ENAMETOOLONG; 73 name = found + 1; 74 } 75 76 // append remaining string 77 if (!append_string(path, pathSize, name)) 78 return ENAMETOOLONG; 79 80 return B_OK; 81 } 82 83 84 // #pragma mark - 85 86 87 void* 88 mmap(void* address, size_t length, int protection, int flags, int fd, 89 off_t offset) 90 { 91 // offset and length must be page-aligned 92 if (length == 0 || offset % B_PAGE_SIZE != 0) { 93 errno = B_BAD_VALUE; 94 return MAP_FAILED; 95 } 96 97 // check anonymous mapping 98 if ((flags & MAP_ANONYMOUS) != 0) { 99 fd = -1; 100 } else if (fd < 0) { 101 errno = EBADF; 102 return MAP_FAILED; 103 } 104 105 // either MAP_SHARED or MAP_PRIVATE must be specified 106 if (((flags & MAP_SHARED) != 0) == ((flags & MAP_PRIVATE) != 0)) { 107 errno = B_BAD_VALUE; 108 return MAP_FAILED; 109 } 110 111 // translate mapping, address specification, and protection 112 int mapping = (flags & MAP_SHARED) != 0 113 ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP; 114 115 uint32 addressSpec = B_ANY_ADDRESS; 116 if ((flags & MAP_FIXED) != 0) 117 addressSpec = B_EXACT_ADDRESS; 118 119 uint32 areaProtection = 0; 120 if ((protection & PROT_READ) != 0) 121 areaProtection |= B_READ_AREA; 122 if ((protection & PROT_WRITE) != 0) 123 areaProtection |= B_WRITE_AREA; 124 if ((protection & PROT_EXEC) != 0) 125 areaProtection |= B_EXECUTE_AREA; 126 127 // ask the kernel to map 128 area_id area = _kern_map_file("mmap area", &address, addressSpec, 129 length, areaProtection, mapping, true, fd, offset); 130 if (area < 0) { 131 errno = area; 132 return MAP_FAILED; 133 } 134 135 return address; 136 } 137 138 139 int 140 munmap(void* address, size_t length) 141 { 142 RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length)); 143 } 144 145 146 int 147 mprotect(void* address, size_t length, int protection) 148 { 149 RETURN_AND_SET_ERRNO(_kern_set_memory_protection(address, length, 150 protection)); 151 } 152 153 154 int 155 msync(void* address, size_t length, int flags) 156 { 157 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sync_memory(address, length, flags)); 158 } 159 160 161 int 162 posix_madvise(void* address, size_t length, int advice) 163 { 164 RETURN_AND_SET_ERRNO(_kern_memory_advice(address, length, advice)); 165 } 166 167 168 int 169 shm_open(const char* name, int openMode, mode_t permissions) 170 { 171 char path[PATH_MAX]; 172 status_t error = shm_name_to_path(name, path, sizeof(path)); 173 if (error != B_OK) 174 RETURN_AND_SET_ERRNO(error); 175 176 return open(path, openMode, permissions); 177 } 178 179 180 int 181 shm_unlink(const char* name) 182 { 183 char path[PATH_MAX]; 184 status_t error = shm_name_to_path(name, path, sizeof(path)); 185 if (error != B_OK) 186 RETURN_AND_SET_ERRNO(error); 187 188 return unlink(path); 189 } 190