1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*++ |
6 | |
7 | |
8 | |
9 | Module Name: |
10 | |
11 | misc/utils.c |
12 | |
13 | Abstract: |
14 | |
15 | Miscellaneous helper functions for the PAL, which don't fit anywhere else |
16 | |
17 | |
18 | |
19 | --*/ |
20 | |
21 | #include "pal/dbgmsg.h" |
22 | SET_DEFAULT_DEBUG_CHANNEL(MISC); // some headers have code with asserts, so do this first |
23 | |
24 | #include "pal/palinternal.h" |
25 | #if HAVE_VM_ALLOCATE |
26 | #include <mach/message.h> |
27 | #endif //HAVE_VM_ALLOCATE |
28 | |
29 | #include "pal/utils.h" |
30 | #include "pal/file.h" |
31 | |
32 | #include <errno.h> |
33 | #include <string.h> |
34 | |
35 | |
36 | // In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable |
37 | // defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement |
38 | // should be placed after the SET_DEFAULT_DEBUG_CHANNEL(MISC) |
39 | #include <safemath.h> |
40 | |
41 | /*++ |
42 | Function: |
43 | UTIL_inverse_wcspbrk |
44 | |
45 | Opposite of wcspbrk : searches a string for the first character NOT in the |
46 | given set |
47 | |
48 | Parameters : |
49 | LPWSTR lpwstr : string to search |
50 | LPCWSTR charset : list of characters to search for |
51 | |
52 | Return value : |
53 | pointer to first character of lpwstr that isn't in the set |
54 | NULL if all characters are in the set |
55 | --*/ |
56 | LPWSTR UTIL_inverse_wcspbrk(LPWSTR lpwstr, LPCWSTR charset) |
57 | { |
58 | while(*lpwstr) |
59 | { |
60 | if(NULL == PAL_wcschr(charset,*lpwstr)) |
61 | { |
62 | return lpwstr; |
63 | } |
64 | lpwstr++; |
65 | } |
66 | return NULL; |
67 | } |
68 | |
69 | |
70 | /*++ |
71 | Function : |
72 | UTIL_IsReadOnlyBitsSet |
73 | |
74 | Takes a struct stat * |
75 | Returns true if the file is read only, |
76 | --*/ |
77 | BOOL UTIL_IsReadOnlyBitsSet( struct stat * stat_data ) |
78 | { |
79 | BOOL bRetVal = FALSE; |
80 | |
81 | /* Check for read permissions. */ |
82 | if ( stat_data->st_uid == geteuid() ) |
83 | { |
84 | /* The process owner is the file owner as well. */ |
85 | if ( ( stat_data->st_mode & S_IRUSR ) && !( stat_data->st_mode & S_IWUSR ) ) |
86 | { |
87 | bRetVal = TRUE; |
88 | } |
89 | } |
90 | else if ( stat_data->st_gid == getegid() ) |
91 | { |
92 | /* The process's owner is in the same group as the file's owner. */ |
93 | if ( ( stat_data->st_mode & S_IRGRP ) && !( stat_data->st_mode & S_IWGRP ) ) |
94 | { |
95 | bRetVal = TRUE; |
96 | } |
97 | } |
98 | else |
99 | { |
100 | /* Check the other bits to see who can access the file. */ |
101 | if ( ( stat_data->st_mode & S_IROTH ) && !( stat_data->st_mode & S_IWOTH ) ) |
102 | { |
103 | bRetVal = TRUE; |
104 | } |
105 | } |
106 | |
107 | return bRetVal; |
108 | } |
109 | |
110 | /*++ |
111 | Function : |
112 | UTIL_IsExecuteBitsSet |
113 | |
114 | Takes a struct stat * |
115 | Returns true if the file is executable, |
116 | --*/ |
117 | BOOL UTIL_IsExecuteBitsSet( struct stat * stat_data ) |
118 | { |
119 | BOOL bRetVal = FALSE; |
120 | |
121 | if ( (stat_data->st_mode & S_IFMT) == S_IFDIR ) |
122 | { |
123 | return FALSE; |
124 | } |
125 | |
126 | /* Check for read permissions. */ |
127 | if ( 0 == geteuid() ) |
128 | { |
129 | /* The process owner is root */ |
130 | bRetVal = TRUE; |
131 | } |
132 | else if ( stat_data->st_uid == geteuid() ) |
133 | { |
134 | /* The process owner is the file owner as well. */ |
135 | if ( ( stat_data->st_mode & S_IXUSR ) ) |
136 | { |
137 | bRetVal = TRUE; |
138 | } |
139 | } |
140 | else if ( stat_data->st_gid == getegid() ) |
141 | { |
142 | /* The process's owner is in the same group as the file's owner. */ |
143 | if ( ( stat_data->st_mode & S_IXGRP ) ) |
144 | { |
145 | bRetVal = TRUE; |
146 | } |
147 | } |
148 | else |
149 | { |
150 | /* Check the other bits to see who can access the file. */ |
151 | if ( ( stat_data->st_mode & S_IXOTH ) ) |
152 | { |
153 | bRetVal = TRUE; |
154 | } |
155 | } |
156 | |
157 | return bRetVal; |
158 | } |
159 | |
160 | /*++ |
161 | Function : |
162 | UTIL_WCToMB_Alloc |
163 | |
164 | Converts a wide string to a multibyte string, allocating the required buffer |
165 | |
166 | Parameters : |
167 | LPCWSTR lpWideCharStr : string to convert |
168 | int cchWideChar : number of wide characters to convert |
169 | (-1 to convert a complete null-termnated string) |
170 | |
171 | Return Value : |
172 | newly allocated buffer containing the converted string. Conversion is |
173 | performed using CP_ACP. Buffer is allocated with malloc(), release it |
174 | with free(). |
175 | In case if failure, LastError will be set. |
176 | --*/ |
177 | LPSTR UTIL_WCToMB_Alloc(LPCWSTR lpWideCharStr, int cchWideChar) |
178 | { |
179 | int length; |
180 | LPSTR lpMultiByteStr; |
181 | |
182 | /* get required buffer length */ |
183 | length = WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, cchWideChar, |
184 | NULL, 0, NULL, NULL); |
185 | if(0 == length) |
186 | { |
187 | ERROR("WCToMB error; GetLastError returns %#x" , GetLastError()); |
188 | return NULL; |
189 | } |
190 | |
191 | /* allocate required buffer */ |
192 | lpMultiByteStr = (LPSTR)PAL_malloc(length); |
193 | if(NULL == lpMultiByteStr) |
194 | { |
195 | ERROR("malloc() failed! errno is %d (%s)\n" , errno,strerror(errno)); |
196 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
197 | return NULL; |
198 | } |
199 | |
200 | /* convert into allocated buffer */ |
201 | length = WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, cchWideChar, |
202 | lpMultiByteStr, length, NULL, NULL); |
203 | if(0 == length) |
204 | { |
205 | ASSERT("WCToMB error; GetLastError returns %#x\n" , GetLastError()); |
206 | PAL_free(lpMultiByteStr); |
207 | return NULL; |
208 | } |
209 | return lpMultiByteStr; |
210 | } |
211 | |
212 | /*++ |
213 | Function : |
214 | UTIL_MBToWC_Alloc |
215 | |
216 | Converts a multibyte string to a wide string, allocating the required buffer |
217 | |
218 | Parameters : |
219 | LPCSTR lpMultiByteStr : string to convert |
220 | int cbMultiByte : number of bytes to convert |
221 | (-1 to convert a complete null-termnated string) |
222 | |
223 | Return Value : |
224 | newly allocated buffer containing the converted string. Conversion is |
225 | performed using CP_ACP. Buffer is allocated with malloc(), release it |
226 | with free(). |
227 | In case if failure, LastError will be set. |
228 | --*/ |
229 | LPWSTR UTIL_MBToWC_Alloc(LPCSTR lpMultiByteStr, int cbMultiByte) |
230 | { |
231 | int length; |
232 | LPWSTR lpWideCharStr; |
233 | |
234 | /* get required buffer length */ |
235 | length = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, cbMultiByte, |
236 | NULL, 0); |
237 | if(0 == length) |
238 | { |
239 | ERROR("MBToWC error; GetLastError returns %#x" , GetLastError()); |
240 | return NULL; |
241 | } |
242 | |
243 | /* allocate required buffer */ |
244 | size_t fullsize; |
245 | if (!ClrSafeInt<size_t>::multiply(length,sizeof(WCHAR),fullsize)) |
246 | { |
247 | ERROR("integer overflow! length = %d , sizeof(WCHAR) = (%d)\n" , length,sizeof(WCHAR) ); |
248 | SetLastError(ERROR_ARITHMETIC_OVERFLOW); |
249 | return NULL; |
250 | } |
251 | |
252 | lpWideCharStr = (LPWSTR)PAL_malloc(fullsize); |
253 | if(NULL == lpWideCharStr) |
254 | { |
255 | ERROR("malloc() failed! errno is %d (%s)\n" , errno,strerror(errno)); |
256 | SetLastError(FILEGetLastErrorFromErrno()); |
257 | return NULL; |
258 | } |
259 | |
260 | /* convert into allocated buffer */ |
261 | length = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, cbMultiByte, |
262 | lpWideCharStr, length); |
263 | if(0 >= length) |
264 | { |
265 | ASSERT("MCToMB error; GetLastError returns %#x\n" , GetLastError()); |
266 | PAL_free(lpWideCharStr); |
267 | return NULL; |
268 | } |
269 | return lpWideCharStr; |
270 | } |
271 | |
272 | #if HAVE_VM_ALLOCATE |
273 | /*++ |
274 | Function: |
275 | UTIL_MachErrorToPalError |
276 | |
277 | Maps a Mach kern_return_t to a Win32 error code. |
278 | --*/ |
279 | DWORD UTIL_MachErrorToPalError(kern_return_t MachReturn) |
280 | { |
281 | switch (MachReturn) |
282 | { |
283 | case KERN_SUCCESS: |
284 | return ERROR_SUCCESS; |
285 | |
286 | case KERN_NO_ACCESS: |
287 | case KERN_INVALID_CAPABILITY: |
288 | return ERROR_ACCESS_DENIED; |
289 | |
290 | case KERN_TERMINATED: |
291 | return ERROR_INVALID_HANDLE; |
292 | |
293 | case KERN_INVALID_ADDRESS: |
294 | return ERROR_INVALID_ADDRESS; |
295 | |
296 | case KERN_NO_SPACE: |
297 | return ERROR_NOT_ENOUGH_MEMORY; |
298 | |
299 | case KERN_INVALID_ARGUMENT: |
300 | return ERROR_INVALID_PARAMETER; |
301 | |
302 | default: |
303 | ASSERT("Unknown kern_return_t value %d - reporting ERROR_INTERNAL_ERROR\n" , MachReturn); |
304 | return ERROR_INTERNAL_ERROR; |
305 | } |
306 | } |
307 | |
308 | /*++ |
309 | Function: |
310 | UTIL_SetLastErrorFromMach |
311 | |
312 | Sets Win32 LastError according to the argument Mach kern_return_t value, |
313 | provided it indicates an error. If the argument indicates success, does |
314 | not modify LastError. |
315 | --*/ |
316 | void UTIL_SetLastErrorFromMach(kern_return_t MachReturn) |
317 | { |
318 | DWORD palError = UTIL_MachErrorToPalError(MachReturn); |
319 | if (palError != ERROR_SUCCESS) |
320 | { |
321 | SetLastError(palError); |
322 | } |
323 | } |
324 | #endif //HAVE_VM_ALLOCATE |
325 | |
326 | |