xref: /PHP-7.1/win32/ioutil.h (revision 7f6387b5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Anatol Belski <ab@php.net>                                   |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* This file integrates several modified parts from the libuv project, which
20  * is copyrighted to
21  *
22  * Copyright Joyent, Inc. and other Node contributors. All rights reserved.
23  *
24  * Permission is hereby granted, free of charge, to any person obtaining a copy
25  * of this software and associated documentation files (the "Software"), to
26  * deal in the Software without restriction, including without limitation the
27  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
28  * sell copies of the Software, and to permit persons to whom the Software is
29  * furnished to do so, subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be included in
32  * all copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
39  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
40  * IN THE SOFTWARE.
41  */
42 
43 #ifndef PHP_WIN32_IOUTIL_H
44 #define PHP_WIN32_IOUTIL_H
45 
46 #include <fcntl.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <io.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 
53 #include "win32/winutil.h"
54 #include "win32/codepage.h"
55 
56 #ifdef __cplusplus
57 extern "C" {
58 #endif
59 
60 #ifdef PHP_EXPORTS
61 # define PW32IO __declspec(dllexport)
62 #else
63 # define PW32IO __declspec(dllimport)
64 #endif
65 
66 #define PHP_WIN32_IOUTIL_MAXPATHLEN 2048
67 
68 #if !defined(MAXPATHLEN) || MAXPATHLEN < PHP_WIN32_IOUTIL_MAXPATHLEN
69 # undef MAXPATHLEN
70 # define MAXPATHLEN PHP_WIN32_IOUTIL_MAXPATHLEN
71 #endif
72 
73 #ifndef mode_t
74 typedef unsigned short mode_t;
75 #endif
76 
77 typedef struct {
78 	DWORD access;
79 	DWORD share;
80 	DWORD disposition;
81 	DWORD attributes;
82 } php_ioutil_open_opts;
83 
84 typedef enum {
85 	PHP_WIN32_IOUTIL_IS_ASCII,
86 	PHP_WIN32_IOUTIL_IS_ANSI,
87 	PHP_WIN32_IOUTIL_IS_UTF8
88 } php_win32_ioutil_encoding;
89 
90 typedef enum {
91 	PHP_WIN32_IOUTIL_NORM_OK,
92 	PHP_WIN32_IOUTIL_NORM_PARTIAL,
93 	PHP_WIN32_IOUTIL_NORM_FAIL,
94 } php_win32_ioutil_normalization_result;
95 
96 #define PHP_WIN32_IOUTIL_FW_SLASHW L'/'
97 #define PHP_WIN32_IOUTIL_FW_SLASH '/'
98 #define PHP_WIN32_IOUTIL_BW_SLASHW L'\\'
99 #define PHP_WIN32_IOUTIL_BW_SLASH '\\'
100 #define PHP_WIN32_IOUTIL_DEFAULT_SLASHW PHP_WIN32_IOUTIL_BW_SLASHW
101 #define PHP_WIN32_IOUTIL_DEFAULT_SLASH PHP_WIN32_IOUTIL_BW_SLASH
102 
103 #define PHP_WIN32_IOUTIL_DEFAULT_DIR_SEPARATORW	L';'
104 #define PHP_WIN32_IOUTIL_IS_SLASHW(c) ((c) == PHP_WIN32_IOUTIL_BW_SLASHW || (c) == PHP_WIN32_IOUTIL_FW_SLASHW)
105 #define PHP_WIN32_IOUTIL_IS_LETTERW(c) (((c) >= L'a' && (c) <= L'z') || ((c) >= L'A' && (c) <= L'Z'))
106 #define PHP_WIN32_IOUTIL_JUNCTION_PREFIXW L"\\??\\"
107 #define PHP_WIN32_IOUTIL_JUNCTION_PREFIX_LENW 4
108 #define PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW L"\\\\?\\"
109 #define PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW 4
110 #define PHP_WIN32_IOUTIL_UNC_PATH_PREFIXW L"\\\\?\\UNC\\"
111 #define PHP_WIN32_IOUTIL_UNC_PATH_PREFIX_LENW 8
112 
113 #define PHP_WIN32_IOUTIL_IS_LONG_PATHW(pathw, path_lenw) (path_lenw >= PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW \
114 	&& 0 == wcsncmp((pathw), PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW))
115 #define PHP_WIN32_IOUTIL_IS_UNC_PATHW(pathw, path_lenw) (path_lenw >= PHP_WIN32_IOUTIL_UNC_PATH_PREFIX_LENW \
116 	&& 0 == wcsncmp((pathw), PHP_WIN32_IOUTIL_UNC_PATH_PREFIXW, PHP_WIN32_IOUTIL_UNC_PATH_PREFIX_LENW))
117 #define PHP_WIN32_IOUTIL_IS_JUNCTION_PATHW(pathw, path_lenw) (path_lenw >= PHP_WIN32_IOUTIL_JUNCTION_PREFIX_LENW \
118 	&& 0 == wcsncmp((pathw), PHP_WIN32_IOUTIL_JUNCTION_PREFIXW, PHP_WIN32_IOUTIL_JUNCTION_PREFIX_LENW))
119 #define PHP_WIN32_IOUTIL_IS_ABSOLUTEW(pathw, path_lenw) (PHP_WIN32_IOUTIL_IS_LONG_PATHW(pathw, path_lenw) \
120 	|| path_lenw >= 3 && PHP_WIN32_IOUTIL_IS_LETTERW(pathw[0]) && L':' == pathw[1] && PHP_WIN32_IOUTIL_IS_SLASHW(pathw[2]))
121 
122 #define PHP_WIN32_IOUTIL_INIT_W(path) \
123 	wchar_t *pathw = php_win32_ioutil_any_to_w(path); \
124 
125 #define PHP_WIN32_IOUTIL_CLEANUP_W() do { \
126 		free(pathw); \
127 		pathw = NULL; \
128 } while (0);
129 
130 #define PHP_WIN32_IOUTIL_REINIT_W(path) do { \
131 	PHP_WIN32_IOUTIL_CLEANUP_W() \
132 	pathw = php_win32_ioutil_any_to_w(path); \
133 } while (0);
134 
135 #define PHP_WIN32_IOUTIL_PATH_IS_OK_W(pathw, len) \
136 	(!((len) >= 1 && L' ' == pathw[(len)-1] || \
137 	(len) > 1 && !PHP_WIN32_IOUTIL_IS_SLASHW(pathw[(len)-2]) && L'.' != pathw[(len)-2] && L'.' == pathw[(len)-1]))
138 
139 #define PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, ret, dealloc) do { \
140 		if (!PHP_WIN32_IOUTIL_PATH_IS_OK_W(pathw, wcslen(pathw))) { \
141 			if (dealloc) { \
142 				free(pathw); \
143 			} \
144 			SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED); \
145 			return ret; \
146 		} \
147 } while (0);
148 
149 PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len);
150 #ifdef PHP_EXPORTS
151 /* This symbols are needed only for the DllMain, but should not be exported
152 	or be available when used with PHP binaries. */
153 BOOL php_win32_ioutil_init(void);
154 #endif
155 
156 /* Keep these functions aliased for case some additional handling
157    is needed later. */
php_win32_ioutil_conv_any_to_w(const char * in,size_t in_len,size_t * out_len)158 __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, size_t in_len, size_t *out_len)
159 {/*{{{*/
160 	wchar_t *mb, *ret;
161 	size_t mb_len;
162 
163 	mb = php_win32_cp_conv_any_to_w(in, in_len, &mb_len);
164 	if (!mb) {
165 		return NULL;
166 	}
167 
168 	/* Only prefix with long if it's needed. */
169 	if (mb_len >= _MAX_PATH) {
170 		size_t new_mb_len;
171 
172 		ret = (wchar_t *) malloc((mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
173 		if (!ret) {
174 			free(mb);
175 			return NULL;
176 		}
177 
178 		if (PHP_WIN32_IOUTIL_NORM_FAIL == php_win32_ioutil_normalize_path_w(&mb, mb_len, &new_mb_len)) {
179 				free(ret);
180 				free(mb);
181 				return NULL;
182 		}
183 
184 		if (new_mb_len > mb_len) {
185 			wchar_t *tmp = (wchar_t *) realloc(ret, (new_mb_len + 1) * sizeof(wchar_t));
186 			if (!tmp) {
187 				free(ret);
188 				free(mb);
189 				return NULL;
190 			}
191 			ret = tmp;
192 			mb_len = new_mb_len;
193 		}
194 
195 		if (PHP_WIN32_IOUTIL_IS_LONG_PATHW(mb, mb_len) || PHP_WIN32_IOUTIL_IS_JUNCTION_PATHW(mb, mb_len) || PHP_WIN32_IOUTIL_IS_UNC_PATHW(mb, mb_len)) {
196 			memmove(ret, mb, mb_len * sizeof(wchar_t));
197 			ret[mb_len] = L'\0';
198 		} else {
199 			memmove(ret, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
200 			memmove(ret+PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, mb, mb_len * sizeof(wchar_t));
201 			ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW] = L'\0';
202 
203 			mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
204 		}
205 
206 		free(mb);
207 	} else {
208 		ret = mb;
209 	}
210 
211 	if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
212 		*out_len = mb_len;
213 	}
214 
215 	return ret;
216 }/*}}}*/
217 #define php_win32_ioutil_any_to_w(in) php_win32_ioutil_conv_any_to_w(in, PHP_WIN32_CP_IGNORE_LEN, PHP_WIN32_CP_IGNORE_LEN_P)
218 
219 #define php_win32_ioutil_ascii_to_w php_win32_cp_ascii_to_w
220 #define php_win32_ioutil_utf8_to_w php_win32_cp_utf8_to_w
221 #define php_win32_ioutil_cur_to_w php_win32_cp_cur_to_w
222 #define php_win32_ioutil_w_to_any php_win32_cp_w_to_any
223 #define php_win32_ioutil_conv_w_to_any php_win32_cp_conv_w_to_any
224 /*__forceinline static char *php_win32_ioutil_w_to_any(wchar_t* w_source_ptr)
225 {
226 	return php_win32_cp_w_to_any(w_source_ptr);
227 }*/
228 #define php_win32_ioutil_w_to_utf8 php_win32_cp_w_to_utf8
229 #define php_win32_ioutil_w_to_thread php_win32_cp_w_to_thread
230 
231 PW32IO int php_win32_ioutil_close(int fd);
232 PW32IO BOOL php_win32_ioutil_posix_to_open_opts(int flags, mode_t mode, php_ioutil_open_opts *opts);
233 PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode);
234 PW32IO size_t php_win32_ioutil_dirname(char *buf, size_t len);
235 
236 PW32IO int php_win32_ioutil_open_w(const wchar_t *path, int flags, ...);
237 PW32IO int php_win32_ioutil_chdir_w(const wchar_t *path);
238 PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newname);
239 PW32IO wchar_t *php_win32_ioutil_getcwd_w(const wchar_t *buf, int len);
240 
241 #if 0
242 PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode);
243 PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode);
244 #endif
245 
246 #define php_win32_ioutil_access_cond(path, mode) _waccess(pathw, mode)
247 #define php_win32_ioutil_unlink_cond(path) php_win32_ioutil_unlink_w(pathw)
248 #define php_win32_ioutil_rmdir_cond(path) php_win32_ioutil_rmdir_w(pathw)
249 
php_win32_ioutil_access(const char * path,mode_t mode)250 __forceinline static int php_win32_ioutil_access(const char *path, mode_t mode)
251 {/*{{{*/
252 	PHP_WIN32_IOUTIL_INIT_W(path)
253 	int ret, err;
254 
255 	if (!pathw) {
256 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
257 		return -1;
258 	}
259 
260 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
261 
262 	ret = _waccess(pathw, mode);
263 	if (0 > ret) {
264 		_get_errno(&err);
265 	}
266 	PHP_WIN32_IOUTIL_CLEANUP_W()
267 
268 	if (0 > ret) {
269 		_set_errno(err);
270 	}
271 
272 	return ret;
273 }/*}}}*/
274 
php_win32_ioutil_open(const char * path,int flags,...)275 __forceinline static int php_win32_ioutil_open(const char *path, int flags, ...)
276 {/*{{{*/
277 	mode_t mode = 0;
278 	PHP_WIN32_IOUTIL_INIT_W(path)
279 	int ret = -1;
280 	DWORD err;
281 
282 	if (!pathw) {
283 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
284 		return -1;
285 	}
286 
287 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
288 
289 	if (flags & O_CREAT) {
290 		va_list arg;
291 
292 		va_start(arg, flags);
293 		mode = (mode_t) va_arg(arg, int);
294 		va_end(arg);
295 	}
296 
297 	ret = php_win32_ioutil_open_w(pathw, flags, mode);
298 	if (0 > ret) {
299 		err = GetLastError();
300 	}
301 	PHP_WIN32_IOUTIL_CLEANUP_W()
302 
303 	if (0 > ret) {
304 		SET_ERRNO_FROM_WIN32_CODE(err);
305 	}
306 
307 	return ret;
308 }/*}}}*/
309 
php_win32_ioutil_unlink(const char * path)310 __forceinline static int php_win32_ioutil_unlink(const char *path)
311 {/*{{{*/
312 	PHP_WIN32_IOUTIL_INIT_W(path)
313 	int ret = 0;
314 	DWORD err = 0;
315 
316 	if (!pathw) {
317 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
318 		return -1;
319 	}
320 
321 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
322 
323 	if (!DeleteFileW(pathw)) {
324 		err = GetLastError();
325 		ret = -1;
326 	}
327 	PHP_WIN32_IOUTIL_CLEANUP_W()
328 
329 	if (0 > ret) {
330 		SET_ERRNO_FROM_WIN32_CODE(err);
331 	}
332 
333 	return ret;
334 }/*}}}*/
335 
php_win32_ioutil_rmdir(const char * path)336 __forceinline static int php_win32_ioutil_rmdir(const char *path)
337 {/*{{{*/
338 	PHP_WIN32_IOUTIL_INIT_W(path)
339 	int ret = 0;
340 	DWORD err = 0;
341 
342 	if (!pathw) {
343 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
344 		return -1;
345 	}
346 
347 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
348 
349 	if (!RemoveDirectoryW(pathw)) {
350 		err = GetLastError();
351 		ret = -1;
352 	}
353 
354 	PHP_WIN32_IOUTIL_CLEANUP_W()
355 
356 	if (0 > ret) {
357 		SET_ERRNO_FROM_WIN32_CODE(err);
358 	}
359 
360 	return ret;
361 }/*}}}*/
362 
363 /* This needs to be improved once long path support is implemented. Use ioutil_open() and then
364 fdopen() might be the way, if we learn how to convert the mode options (maybe grab the routine
365  from the streams). That will allow to split for _a and _w. */
php_win32_ioutil_fopen(const char * patha,const char * modea)366 __forceinline static FILE *php_win32_ioutil_fopen(const char *patha, const char *modea)
367 {/*{{{*/
368 	FILE *ret;
369 	wchar_t *pathw;
370 	wchar_t *modew;
371 	int err = 0;
372 
373 	pathw = php_win32_ioutil_any_to_w(patha);
374 	if (!pathw) {
375 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
376 		return NULL;
377 	}
378 
379 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, NULL, 1)
380 
381 	modew = php_win32_ioutil_ascii_to_w(modea);
382 	if (!modew) {
383 		free(pathw);
384 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
385 		return NULL;
386 	}
387 
388 	ret = _wfopen(pathw, modew);
389 	if (!ret) {
390 		_get_errno(&err);
391 	}
392 	free(pathw);
393 	free(modew);
394 
395 	if (!ret) {
396 		_set_errno(err);
397 	}
398 	return ret;
399 }/*}}}*/
400 
php_win32_ioutil_rename(const char * oldnamea,const char * newnamea)401 __forceinline static int php_win32_ioutil_rename(const char *oldnamea, const char *newnamea)
402 {/*{{{*/
403 	wchar_t *oldnamew;
404 	wchar_t *newnamew;
405 	int ret;
406 	DWORD err = 0;
407 
408 	oldnamew = php_win32_ioutil_any_to_w(oldnamea);
409 	if (!oldnamew) {
410 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
411 		return -1;
412 	}
413 	PHP_WIN32_IOUTIL_CHECK_PATH_W(oldnamew, -1, 1)
414 
415 	newnamew = php_win32_ioutil_any_to_w(newnamea);
416 	if (!newnamew) {
417 		free(oldnamew);
418 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
419 		return -1;
420 	} else if (!PHP_WIN32_IOUTIL_PATH_IS_OK_W(newnamew, wcslen(newnamew))) {
421 		free(oldnamew);
422 		free(newnamew);
423 		SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED);
424 		return -1;
425 	}
426 
427 	ret = php_win32_ioutil_rename_w(oldnamew, newnamew);
428 	if (0 > ret) {
429 		err = GetLastError();
430 	}
431 
432 	free(oldnamew);
433 	free(newnamew);
434 
435 	if (0 > ret) {
436 		SET_ERRNO_FROM_WIN32_CODE(err);
437 	}
438 
439 	return ret;
440 }/*}}}*/
441 
php_win32_ioutil_chdir(const char * patha)442 __forceinline static int php_win32_ioutil_chdir(const char *patha)
443 {/*{{{*/
444 	int ret;
445 	wchar_t *pathw = php_win32_ioutil_any_to_w(patha);
446 	DWORD err = 0;
447 
448 	if (!pathw) {
449 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
450 		return -1;
451 	}
452 
453 	ret = php_win32_ioutil_chdir_w(pathw);
454 	if (0 > ret) {
455 		err = GetLastError();
456 	}
457 
458 	free(pathw);
459 
460 	if (0 > ret) {
461 		SET_ERRNO_FROM_WIN32_CODE(err);
462 	}
463 
464 	return ret;
465 }/*}}}*/
466 
php_win32_ioutil_getcwd(char * buf,int len)467 __forceinline static char *php_win32_ioutil_getcwd(char *buf, int len)
468 {/*{{{*/
469 	wchar_t tmp_bufw[PHP_WIN32_IOUTIL_MAXPATHLEN];
470 	char *tmp_bufa = NULL;
471 	size_t tmp_bufa_len;
472 	DWORD err = 0;
473 
474 	if (php_win32_ioutil_getcwd_w(tmp_bufw, PHP_WIN32_IOUTIL_MAXPATHLEN) == NULL) {
475 		err = GetLastError();
476 		SET_ERRNO_FROM_WIN32_CODE(err);
477 		return NULL;
478 	}
479 
480 	tmp_bufa = php_win32_cp_conv_w_to_any(tmp_bufw, wcslen(tmp_bufw), &tmp_bufa_len);
481 	if (!tmp_bufa) {
482 		err = GetLastError();
483 		SET_ERRNO_FROM_WIN32_CODE(err);
484 		return NULL;
485 	} else if (tmp_bufa_len + 1 > PHP_WIN32_IOUTIL_MAXPATHLEN) {
486 		free(tmp_bufa);
487 		SET_ERRNO_FROM_WIN32_CODE(ERROR_BAD_LENGTH);
488 		return NULL;
489 	}
490 
491 	if (!buf) {
492 		/* If buf was NULL, the result has to be freed outside here. */
493 		buf = tmp_bufa;
494 	} else {
495 		if (tmp_bufa_len + 1 > len) {
496 			free(tmp_bufa);
497 			SET_ERRNO_FROM_WIN32_CODE(ERROR_INSUFFICIENT_BUFFER);
498 			return NULL;
499 		}
500 		memmove(buf, tmp_bufa, tmp_bufa_len + 1);
501 		free(tmp_bufa);
502 	}
503 
504 	return buf;
505 }/*}}}*/
506 
507 /* TODO improve with usage of native APIs, split for _a and _w. */
php_win32_ioutil_chmod(const char * patha,int mode)508 __forceinline static int php_win32_ioutil_chmod(const char *patha, int mode)
509 {/*{{{*/
510 	wchar_t *pathw = php_win32_ioutil_any_to_w(patha);
511 	int err = 0;
512 	int ret;
513 
514 	if (!pathw) {
515 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
516 		return -1;
517 	}
518 
519 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
520 
521 	ret = _wchmod(pathw, mode);
522 	if (0 > ret) {
523 		_get_errno(&err);
524 	}
525 
526 	free(pathw);
527 
528 	if (0 > ret) {
529 		_set_errno(err);
530 	}
531 
532 	return ret;
533 }/*}}}*/
534 
535 #ifdef __cplusplus
536 }
537 #endif
538 
539 #endif /* PHP_WIN32_IOUTIL_H */
540 
541 /*
542  * Local variables:
543  * tab-width: 4
544  * c-basic-offset: 4
545  * End:
546  * vim600: sw=4 ts=4 fdm=marker
547  * vim<600: sw=4 ts=4
548  */
549