xref: /PHP-7.2/win32/ioutil.h (revision 902d39a3)
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 #define PHP_WIN32_IOUTIL_IS_UNC(pathw, path_lenw) (path_lenw >= 2 && PHP_WIN32_IOUTIL_IS_SLASHW(pathw[0]) && PHP_WIN32_IOUTIL_IS_SLASHW(pathw[1]) \
122 	|| path_lenw >= PHP_WIN32_IOUTIL_UNC_PATH_PREFIX_LENW && 0 == wcsncmp((pathw), PHP_WIN32_IOUTIL_UNC_PATH_PREFIXW, PHP_WIN32_IOUTIL_UNC_PATH_PREFIX_LENW))
123 
124 #define PHP_WIN32_IOUTIL_INIT_W(path) \
125 	wchar_t *pathw = php_win32_ioutil_any_to_w(path); \
126 
127 #define PHP_WIN32_IOUTIL_CLEANUP_W() do { \
128 		free(pathw); \
129 		pathw = NULL; \
130 } while (0);
131 
132 #define PHP_WIN32_IOUTIL_REINIT_W(path) do { \
133 	PHP_WIN32_IOUTIL_CLEANUP_W() \
134 	pathw = php_win32_ioutil_any_to_w(path); \
135 } while (0);
136 
137 #define PHP_WIN32_IOUTIL_PATH_IS_OK_W(pathw, len) \
138 	(!((len) >= 1 && L' ' == pathw[(len)-1] || \
139 	(len) > 1 && !PHP_WIN32_IOUTIL_IS_SLASHW(pathw[(len)-2]) && L'.' != pathw[(len)-2] && L'.' == pathw[(len)-1]))
140 
141 #define PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, ret, dealloc) do { \
142 		if (!PHP_WIN32_IOUTIL_PATH_IS_OK_W(pathw, wcslen(pathw))) { \
143 			if (dealloc) { \
144 				free((void *)pathw); \
145 			} \
146 			SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED); \
147 			return ret; \
148 		} \
149 } while (0);
150 
151 PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len);
152 #ifdef PHP_EXPORTS
153 /* This symbols are needed only for the DllMain, but should not be exported
154 	or be available when used with PHP binaries. */
155 BOOL php_win32_ioutil_init(void);
156 #endif
157 
158 /* Keep these functions aliased for case some additional handling
159    is needed later. */
php_win32_ioutil_conv_any_to_w(const char * in,size_t in_len,size_t * out_len)160 __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, size_t in_len, size_t *out_len)
161 {/*{{{*/
162 	wchar_t *mb, *ret;
163 	size_t mb_len;
164 
165 	mb = php_win32_cp_conv_any_to_w(in, in_len, &mb_len);
166 	if (!mb) {
167 		return NULL;
168 	}
169 
170 	/* Only prefix with long if it's needed. */
171 	if (mb_len >= _MAX_PATH) {
172 		size_t new_mb_len;
173 
174 		ret = (wchar_t *) malloc((mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
175 		if (!ret) {
176 			free(mb);
177 			return NULL;
178 		}
179 
180 		if (PHP_WIN32_IOUTIL_NORM_FAIL == php_win32_ioutil_normalize_path_w(&mb, mb_len, &new_mb_len)) {
181 				free(ret);
182 				free(mb);
183 				return NULL;
184 		}
185 
186 		if (new_mb_len > mb_len) {
187 			wchar_t *tmp = (wchar_t *) realloc(ret, (new_mb_len + 1) * sizeof(wchar_t));
188 			if (!tmp) {
189 				free(ret);
190 				free(mb);
191 				return NULL;
192 			}
193 			ret = tmp;
194 			mb_len = new_mb_len;
195 		}
196 
197 		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)) {
198 			memmove(ret, mb, mb_len * sizeof(wchar_t));
199 			ret[mb_len] = L'\0';
200 		} else {
201 			memmove(ret, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
202 			memmove(ret+PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, mb, mb_len * sizeof(wchar_t));
203 			ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW] = L'\0';
204 
205 			mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
206 		}
207 
208 		free(mb);
209 	} else {
210 		ret = mb;
211 	}
212 
213 	if (PHP_WIN32_CP_IGNORE_LEN_P != out_len) {
214 		*out_len = mb_len;
215 	}
216 
217 	return ret;
218 }/*}}}*/
219 #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)
220 
221 #define php_win32_ioutil_ascii_to_w php_win32_cp_ascii_to_w
222 #define php_win32_ioutil_utf8_to_w php_win32_cp_utf8_to_w
223 #define php_win32_ioutil_cur_to_w php_win32_cp_cur_to_w
224 #define php_win32_ioutil_w_to_any php_win32_cp_w_to_any
225 #define php_win32_ioutil_conv_w_to_any php_win32_cp_conv_w_to_any
226 /*__forceinline static char *php_win32_ioutil_w_to_any(wchar_t* w_source_ptr)
227 {
228 	return php_win32_cp_w_to_any(w_source_ptr);
229 }*/
230 #define php_win32_ioutil_w_to_utf8 php_win32_cp_w_to_utf8
231 #define php_win32_ioutil_w_to_thread php_win32_cp_w_to_thread
232 
233 PW32IO int php_win32_ioutil_close(int fd);
234 PW32IO BOOL php_win32_ioutil_posix_to_open_opts(int flags, mode_t mode, php_ioutil_open_opts *opts);
235 PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode);
236 PW32IO size_t php_win32_ioutil_dirname(char *buf, size_t len);
237 
238 PW32IO int php_win32_ioutil_open_w(const wchar_t *path, int flags, ...);
239 PW32IO int php_win32_ioutil_chdir_w(const wchar_t *path);
240 PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newname);
241 PW32IO wchar_t *php_win32_ioutil_getcwd_w(wchar_t *buf, size_t len);
242 
243 #if 0
244 PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode);
245 PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode);
246 #endif
247 
248 #define php_win32_ioutil_access_cond(path, mode) _waccess(pathw, mode)
249 #define php_win32_ioutil_unlink_cond(path) php_win32_ioutil_unlink_w(pathw)
250 #define php_win32_ioutil_rmdir_cond(path) php_win32_ioutil_rmdir_w(pathw)
251 
php_win32_ioutil_access(const char * path,mode_t mode)252 __forceinline static int php_win32_ioutil_access(const char *path, mode_t mode)
253 {/*{{{*/
254 	PHP_WIN32_IOUTIL_INIT_W(path)
255 	int ret, err;
256 
257 	if (!pathw) {
258 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
259 		return -1;
260 	}
261 
262 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
263 
264 	ret = _waccess(pathw, mode);
265 	if (0 > ret) {
266 		_get_errno(&err);
267 	}
268 	PHP_WIN32_IOUTIL_CLEANUP_W()
269 
270 	if (0 > ret) {
271 		_set_errno(err);
272 	}
273 
274 	return ret;
275 }/*}}}*/
276 
php_win32_ioutil_open(const char * path,int flags,...)277 __forceinline static int php_win32_ioutil_open(const char *path, int flags, ...)
278 {/*{{{*/
279 	mode_t mode = 0;
280 	PHP_WIN32_IOUTIL_INIT_W(path)
281 	int ret = -1;
282 	DWORD err;
283 
284 	if (!pathw) {
285 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
286 		return -1;
287 	}
288 
289 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
290 
291 	if (flags & O_CREAT) {
292 		va_list arg;
293 
294 		va_start(arg, flags);
295 		mode = (mode_t) va_arg(arg, int);
296 		va_end(arg);
297 	}
298 
299 	ret = php_win32_ioutil_open_w(pathw, flags, mode);
300 	if (0 > ret) {
301 		err = GetLastError();
302 	}
303 	PHP_WIN32_IOUTIL_CLEANUP_W()
304 
305 	if (0 > ret) {
306 		SET_ERRNO_FROM_WIN32_CODE(err);
307 	}
308 
309 	return ret;
310 }/*}}}*/
311 
php_win32_ioutil_unlink(const char * path)312 __forceinline static int php_win32_ioutil_unlink(const char *path)
313 {/*{{{*/
314 	PHP_WIN32_IOUTIL_INIT_W(path)
315 	int ret = 0;
316 	DWORD err = 0;
317 
318 	if (!pathw) {
319 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
320 		return -1;
321 	}
322 
323 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
324 
325 	if (!DeleteFileW(pathw)) {
326 		err = GetLastError();
327 		ret = -1;
328 	}
329 	PHP_WIN32_IOUTIL_CLEANUP_W()
330 
331 	if (0 > ret) {
332 		SET_ERRNO_FROM_WIN32_CODE(err);
333 	}
334 
335 	return ret;
336 }/*}}}*/
337 
php_win32_ioutil_rmdir(const char * path)338 __forceinline static int php_win32_ioutil_rmdir(const char *path)
339 {/*{{{*/
340 	PHP_WIN32_IOUTIL_INIT_W(path)
341 	int ret = 0;
342 	DWORD err = 0;
343 
344 	if (!pathw) {
345 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
346 		return -1;
347 	}
348 
349 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
350 
351 	if (!RemoveDirectoryW(pathw)) {
352 		err = GetLastError();
353 		ret = -1;
354 	}
355 
356 	PHP_WIN32_IOUTIL_CLEANUP_W()
357 
358 	if (0 > ret) {
359 		SET_ERRNO_FROM_WIN32_CODE(err);
360 	}
361 
362 	return ret;
363 }/*}}}*/
364 
365 /* This needs to be improved once long path support is implemented. Use ioutil_open() and then
366 fdopen() might be the way, if we learn how to convert the mode options (maybe grab the routine
367  from the streams). That will allow to split for _a and _w. */
php_win32_ioutil_fopen(const char * patha,const char * modea)368 __forceinline static FILE *php_win32_ioutil_fopen(const char *patha, const char *modea)
369 {/*{{{*/
370 	FILE *ret;
371 	wchar_t *pathw;
372 	wchar_t *modew;
373 	int err = 0;
374 
375 	pathw = php_win32_ioutil_any_to_w(patha);
376 	if (!pathw) {
377 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
378 		return NULL;
379 	}
380 
381 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, NULL, 1)
382 
383 	modew = php_win32_ioutil_ascii_to_w(modea);
384 	if (!modew) {
385 		free(pathw);
386 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
387 		return NULL;
388 	}
389 
390 	ret = _wfopen(pathw, modew);
391 	if (!ret) {
392 		_get_errno(&err);
393 	}
394 	free(pathw);
395 	free(modew);
396 
397 	if (!ret) {
398 		_set_errno(err);
399 	}
400 	return ret;
401 }/*}}}*/
402 
php_win32_ioutil_rename(const char * oldnamea,const char * newnamea)403 __forceinline static int php_win32_ioutil_rename(const char *oldnamea, const char *newnamea)
404 {/*{{{*/
405 	wchar_t *oldnamew;
406 	wchar_t *newnamew;
407 	int ret;
408 	DWORD err = 0;
409 
410 	oldnamew = php_win32_ioutil_any_to_w(oldnamea);
411 	if (!oldnamew) {
412 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
413 		return -1;
414 	}
415 	PHP_WIN32_IOUTIL_CHECK_PATH_W(oldnamew, -1, 1)
416 
417 	newnamew = php_win32_ioutil_any_to_w(newnamea);
418 	if (!newnamew) {
419 		free(oldnamew);
420 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
421 		return -1;
422 	} else if (!PHP_WIN32_IOUTIL_PATH_IS_OK_W(newnamew, wcslen(newnamew))) {
423 		free(oldnamew);
424 		free(newnamew);
425 		SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED);
426 		return -1;
427 	}
428 
429 	ret = php_win32_ioutil_rename_w(oldnamew, newnamew);
430 	if (0 > ret) {
431 		err = GetLastError();
432 	}
433 
434 	free(oldnamew);
435 	free(newnamew);
436 
437 	if (0 > ret) {
438 		SET_ERRNO_FROM_WIN32_CODE(err);
439 	}
440 
441 	return ret;
442 }/*}}}*/
443 
php_win32_ioutil_chdir(const char * patha)444 __forceinline static int php_win32_ioutil_chdir(const char *patha)
445 {/*{{{*/
446 	int ret;
447 	wchar_t *pathw = php_win32_ioutil_any_to_w(patha);
448 	DWORD err = 0;
449 
450 	if (!pathw) {
451 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
452 		return -1;
453 	}
454 
455 	ret = php_win32_ioutil_chdir_w(pathw);
456 	if (0 > ret) {
457 		err = GetLastError();
458 	}
459 
460 	free(pathw);
461 
462 	if (0 > ret) {
463 		SET_ERRNO_FROM_WIN32_CODE(err);
464 	}
465 
466 	return ret;
467 }/*}}}*/
468 
php_win32_ioutil_getcwd(char * buf,int len)469 __forceinline static char *php_win32_ioutil_getcwd(char *buf, int len)
470 {/*{{{*/
471 	wchar_t tmp_bufw[PHP_WIN32_IOUTIL_MAXPATHLEN];
472 	char *tmp_bufa = NULL;
473 	size_t tmp_bufa_len;
474 	DWORD err = 0;
475 
476 	if (php_win32_ioutil_getcwd_w(tmp_bufw, PHP_WIN32_IOUTIL_MAXPATHLEN) == NULL) {
477 		err = GetLastError();
478 		SET_ERRNO_FROM_WIN32_CODE(err);
479 		return NULL;
480 	}
481 
482 	tmp_bufa = php_win32_cp_conv_w_to_any(tmp_bufw, wcslen(tmp_bufw), &tmp_bufa_len);
483 	if (!tmp_bufa) {
484 		err = GetLastError();
485 		SET_ERRNO_FROM_WIN32_CODE(err);
486 		return NULL;
487 	} else if (tmp_bufa_len + 1 > PHP_WIN32_IOUTIL_MAXPATHLEN) {
488 		free(tmp_bufa);
489 		SET_ERRNO_FROM_WIN32_CODE(ERROR_BAD_LENGTH);
490 		return NULL;
491 	}
492 
493 	if (!buf) {
494 		/* If buf was NULL, the result has to be freed outside here. */
495 		buf = tmp_bufa;
496 	} else {
497 		if (tmp_bufa_len + 1 > (size_t)len) {
498 			free(tmp_bufa);
499 			SET_ERRNO_FROM_WIN32_CODE(ERROR_INSUFFICIENT_BUFFER);
500 			return NULL;
501 		}
502 		memmove(buf, tmp_bufa, tmp_bufa_len + 1);
503 		free(tmp_bufa);
504 	}
505 
506 	return buf;
507 }/*}}}*/
508 
509 /* TODO improve with usage of native APIs, split for _a and _w. */
php_win32_ioutil_chmod(const char * patha,int mode)510 __forceinline static int php_win32_ioutil_chmod(const char *patha, int mode)
511 {/*{{{*/
512 	wchar_t *pathw = php_win32_ioutil_any_to_w(patha);
513 	int err = 0;
514 	int ret;
515 
516 	if (!pathw) {
517 		SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
518 		return -1;
519 	}
520 
521 	PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
522 
523 	ret = _wchmod(pathw, mode);
524 	if (0 > ret) {
525 		_get_errno(&err);
526 	}
527 
528 	free(pathw);
529 
530 	if (0 > ret) {
531 		_set_errno(err);
532 	}
533 
534 	return ret;
535 }/*}}}*/
536 
537 #ifdef __cplusplus
538 }
539 #endif
540 
541 #endif /* PHP_WIN32_IOUTIL_H */
542 
543 /*
544  * Local variables:
545  * tab-width: 4
546  * c-basic-offset: 4
547  * End:
548  * vim600: sw=4 ts=4 fdm=marker
549  * vim<600: sw=4 ts=4
550  */
551